From 2bd657d0c19f192b40c210708ec5e9ed6c2e4b57 Mon Sep 17 00:00:00 2001 From: mrq Date: Mon, 7 Dec 2020 00:00:00 -0600 Subject: [PATCH] Commit for 2020.12.07.7z --- bin/data/shaders/gltf.frag.glsl | 4 +- .../shaders/gltf.stereo.instanced.vert.glsl | 65 +++ .../gltf.stereo.skinned.instanced.vert.glsl | 75 ++++ .../shaders/gltf.stereo.skinned.vert.glsl | 8 +- bin/data/shaders/gltf.stereo.vert.glsl | 6 +- engine/inc/uf/ext/gltf/graph.h | 42 +- engine/inc/uf/ext/gltf/mesh.h | 12 +- engine/src/engine/object/behaviors/gltf.cpp | 230 +++++----- engine/src/ext/gltf/gltf.cpp | 95 ++-- engine/src/ext/gltf/graph.cpp | 405 ++++++++---------- engine/src/ext/gltf/mesh.cpp | 4 +- engine/src/ext/lua/lua.cpp | 6 +- engine/src/ext/lua/usertypes/vector.cpp | 6 + ext/behaviors/soundemitter/behavior.cpp | 81 ++-- 14 files changed, 591 insertions(+), 448 deletions(-) create mode 100644 bin/data/shaders/gltf.stereo.instanced.vert.glsl create mode 100644 bin/data/shaders/gltf.stereo.skinned.instanced.vert.glsl diff --git a/bin/data/shaders/gltf.frag.glsl b/bin/data/shaders/gltf.frag.glsl index d76fdc85..a5adbde3 100644 --- a/bin/data/shaders/gltf.frag.glsl +++ b/bin/data/shaders/gltf.frag.glsl @@ -1,7 +1,7 @@ #version 450 layout (constant_id = 0) const uint TEXTURES = 1; -layout (binding = 2) uniform sampler2D samplerTextures[TEXTURES]; +layout (binding = 0) uniform sampler2D samplerTextures[TEXTURES]; struct Material { vec4 colorBase; @@ -17,7 +17,7 @@ struct Material { int indexMetallicRoughness; int indexMappedTarget; }; -layout (std140, binding = 3) buffer Materials { +layout (std140, binding = 1) buffer Materials { Material materials[]; }; diff --git a/bin/data/shaders/gltf.stereo.instanced.vert.glsl b/bin/data/shaders/gltf.stereo.instanced.vert.glsl new file mode 100644 index 00000000..fb09c460 --- /dev/null +++ b/bin/data/shaders/gltf.stereo.instanced.vert.glsl @@ -0,0 +1,65 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUv; +layout (location = 2) in vec3 inNormal; +layout (location = 3) in vec4 inTangent; +layout (location = 4) in ivec2 inId; + +layout( push_constant ) uniform PushBlock { + uint pass; +} PushConstant; + +layout (binding = 2) uniform UBO { + mat4 view[2]; + mat4 projection[2]; +} ubo; + +layout (std140, binding = 3) buffer Models { + mat4 models[]; +}; + +layout (location = 0) noperspective out vec2 outUv; +layout (location = 1) out vec4 outColor; +layout (location = 2) out vec3 outNormal; +layout (location = 3) out mat3 outTBN; +layout (location = 6) out vec3 outPosition; +layout (location = 7) flat out uint outId; +layout (location = 8) out float affine; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec4 snap(vec4 vertex, vec2 resolution) { + vec4 snappedPos = vertex; + snappedPos.xyz = vertex.xyz / vertex.w; + snappedPos.xy = floor(resolution * snappedPos.xy) / resolution; + snappedPos.xyz *= vertex.w; + return snappedPos; +} + +void main() { + outUv = inUv; + outColor = vec4(1.0); + + mat4 model = models.length() <= 0 ? mat4(1.0) : models[int(inId.x)]; + outPosition = vec3(ubo.view[PushConstant.pass] * model * vec4(inPos.xyz, 1.0)); + outNormal = vec3(ubo.view[PushConstant.pass] * model * vec4(inNormal.xyz, 0.0)); + outNormal = normalize(outNormal); + + outId = inId.y; + + { + vec3 T = vec3(ubo.view[PushConstant.pass] * model * vec4(inTangent.xyz, 0.0)); + vec3 N = outNormal; + vec3 B = cross(N, T) * inTangent.w; + outTBN = mat3( T, B, N ); + } + + gl_Position = ubo.projection[PushConstant.pass] * ubo.view[PushConstant.pass] * model * vec4(inPos.xyz, 1.0); + +// gl_Position = snap( gl_Position, vec2(320.0, 240.0) ); + + affine = 1; +} \ No newline at end of file diff --git a/bin/data/shaders/gltf.stereo.skinned.instanced.vert.glsl b/bin/data/shaders/gltf.stereo.skinned.instanced.vert.glsl new file mode 100644 index 00000000..8eeb95a5 --- /dev/null +++ b/bin/data/shaders/gltf.stereo.skinned.instanced.vert.glsl @@ -0,0 +1,75 @@ +#version 450 + +layout (location = 0) in vec3 inPos; +layout (location = 1) in vec2 inUv; +layout (location = 2) in vec3 inNormal; +layout (location = 3) in vec4 inTangent; +layout (location = 4) in ivec2 inId; +layout (location = 5) in vec4 inJoints; +layout (location = 6) in vec4 inWeights; + +layout( push_constant ) uniform PushBlock { + uint pass; +} PushConstant; + +layout (binding = 2) uniform UBO { + mat4 view[2]; + mat4 projection[2]; +} ubo; + +layout (std140, binding = 3) buffer Models { + mat4 models[]; +}; + +layout (std140, binding = 4) buffer Joints { + mat4 joints[]; +}; + +layout (location = 0) noperspective out vec2 outUv; +layout (location = 1) out vec4 outColor; +layout (location = 2) out vec3 outNormal; +layout (location = 3) out mat3 outTBN; +layout (location = 6) out vec3 outPosition; +layout (location = 7) flat out uint outId; +layout (location = 8) out float affine; + +out gl_PerVertex { + vec4 gl_Position; +}; + +vec4 snap(vec4 vertex, vec2 resolution) { + vec4 snappedPos = vertex; + snappedPos.xyz = vertex.xyz / vertex.w; + snappedPos.xy = floor(resolution * snappedPos.xy) / resolution; + snappedPos.xyz *= vertex.w; + return snappedPos; +} + +void main() { + outUv = inUv; + outColor = vec4(1.0); + + mat4 model = models.length() <= 0 ? mat4(1.0) : models[int(inId.x)]; + mat4 skinnedMatrix = joints.length() <= 0 ? mat4(1.0) : + inWeights.x * joints[int(inJoints.x)] + + inWeights.y * joints[int(inJoints.y)] + + inWeights.z * joints[int(inJoints.z)] + + inWeights.w * joints[int(inJoints.w)]; + + outPosition = vec3(ubo.view[PushConstant.pass] * model * skinnedMatrix * vec4(inPos.xyz, 1.0)); + outNormal = vec3(ubo.view[PushConstant.pass] * model * vec4(inNormal.xyz, 0.0)); + outNormal = normalize(outNormal); + + outId = inId.y; + + { + vec3 T = vec3(ubo.view[PushConstant.pass] * model * vec4(inTangent.xyz, 0.0)); + vec3 N = outNormal; + vec3 B = cross(N, T) * inTangent.w; + outTBN = mat3( T, B, N ); + } + + gl_Position = ubo.projection[PushConstant.pass] * ubo.view[PushConstant.pass] * model * skinnedMatrix * vec4(inPos.xyz, 1.0); + + affine = 1; +} \ No newline at end of file diff --git a/bin/data/shaders/gltf.stereo.skinned.vert.glsl b/bin/data/shaders/gltf.stereo.skinned.vert.glsl index 013d1afb..180e9924 100644 --- a/bin/data/shaders/gltf.stereo.skinned.vert.glsl +++ b/bin/data/shaders/gltf.stereo.skinned.vert.glsl @@ -4,7 +4,7 @@ layout (location = 0) in vec3 inPos; layout (location = 1) in vec2 inUv; layout (location = 2) in vec3 inNormal; layout (location = 3) in vec4 inTangent; -layout (location = 4) in uint inId; +layout (location = 4) in ivec2 inId; layout (location = 5) in vec4 inJoints; layout (location = 6) in vec4 inWeights; @@ -17,12 +17,12 @@ struct Matrices { mat4 view[2]; mat4 projection[2]; }; -layout (binding = 0) uniform UBO { +layout (binding = 2) uniform UBO { Matrices matrices; vec4 color; } ubo; -layout (std140, binding = 1) buffer Joints { +layout (std140, binding = 3) buffer Joints { mat4 joints[]; }; @@ -61,7 +61,7 @@ void main() { outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0)); outNormal = normalize(outNormal); - outId = inId; + outId = inId.y; { vec3 T = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inTangent.xyz, 0.0)); diff --git a/bin/data/shaders/gltf.stereo.vert.glsl b/bin/data/shaders/gltf.stereo.vert.glsl index 89a32f0d..0d0999a4 100644 --- a/bin/data/shaders/gltf.stereo.vert.glsl +++ b/bin/data/shaders/gltf.stereo.vert.glsl @@ -4,7 +4,7 @@ layout (location = 0) in vec3 inPos; layout (location = 1) in vec2 inUv; layout (location = 2) in vec3 inNormal; layout (location = 3) in vec4 inTangent; -layout (location = 4) in uint inId; +layout (location = 4) in ivec2 inId; layout( push_constant ) uniform PushBlock { uint pass; @@ -16,7 +16,7 @@ struct Matrices { mat4 projection[2]; }; -layout (binding = 0) uniform UBO { +layout (binding = 2) uniform UBO { Matrices matrices; vec4 color; } ubo; @@ -49,7 +49,7 @@ void main() { outNormal = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inNormal.xyz, 0.0)); outNormal = normalize(outNormal); - outId = inId; + outId = inId.y; { vec3 T = vec3(ubo.matrices.view[PushConstant.pass] * ubo.matrices.model * vec4(inTangent.xyz, 0.0)); diff --git a/engine/inc/uf/ext/gltf/graph.h b/engine/inc/uf/ext/gltf/graph.h index 2c25c28f..ce27d49a 100644 --- a/engine/inc/uf/ext/gltf/graph.h +++ b/engine/inc/uf/ext/gltf/graph.h @@ -25,6 +25,12 @@ namespace pod { float intensity = 1.0f; float range = 0.0f; }; +/* + struct UF_API Instance { + alignas(16) pod::Matrix4f model = uf::matrix::identity(); + alignas(4) int32_t materialId = -1; + }; +*/ struct UF_API Material { std::string name = ""; // @@ -53,10 +59,10 @@ namespace pod { std::string name = ""; int32_t index = -1; - Node* parent = NULL; - std::vector children; - // int32_t parent = -1; - // std::vector; + // Node* parent = NULL; + // std::vector children; + int32_t parent = -1; + std::vector children; uf::Object* entity = NULL; size_t jointBufferIndex = -1; @@ -71,8 +77,8 @@ namespace pod { struct UF_API Skin { std::string name = ""; - std::vector joints; - // std::vector joints; + // std::vector joints; + std::vector joints; std::vector inverseBindMatrices; }; struct UF_API Animation { @@ -83,7 +89,8 @@ namespace pod { }; struct Channel { std::string path; - Node* node; + // Node* node; + int32_t node; uint32_t sampler; }; @@ -95,11 +102,12 @@ namespace pod { float cur = 0; }; struct UF_API Graph { - Node* node = NULL; - // int32_t node = -1; - // std::vector nodes; + // Node* node = NULL; + pod::Node root; + std::vector nodes; uf::Object* entity = NULL; + size_t instanceBufferIndex = -1; std::string name = ""; ext::gltf::load_mode_t mode; @@ -122,7 +130,7 @@ namespace pod { struct { float a = -std::numeric_limits::max(); float speed = 1 / 0.125f; - std::unordered_map, pod::Transform<>>> map; + std::unordered_map, pod::Transform<>>> map; } override; } animations; } settings; @@ -131,6 +139,7 @@ namespace pod { namespace uf { namespace graph { + /* pod::Node& UF_API node(); pod::Node* UF_API find( const pod::Node& node, int32_t index ); pod::Node* UF_API find( pod::Node* node, int32_t index ); @@ -142,10 +151,19 @@ namespace uf { pod::Matrix4f UF_API local( const pod::Node& node ); pod::Matrix4f UF_API matrix( const pod::Node& node ); + */ + pod::Node* UF_API find( pod::Graph& graph, int32_t index ); + pod::Node* UF_API find( pod::Graph& graph, const std::string& name ); + + // pod::Matrix4f UF_API local( const pod::Node& node ); + // pod::Matrix4f UF_API matrix( pod::Graph&, const pod::Node& node ); + + pod::Matrix4f UF_API local( pod::Graph&, int32_t ); + pod::Matrix4f UF_API matrix( pod::Graph&, int32_t ); void UF_API process( uf::Object& entity ); void UF_API process( pod::Graph& graph ); - void UF_API process( pod::Graph& graph, pod::Node& node, uf::Object& parent ); + void UF_API process( pod::Graph& graph, int32_t, uf::Object& parent ); void UF_API override( pod::Graph& ); void UF_API animate( pod::Graph&, const std::string&, float = 1, bool = true ); diff --git a/engine/inc/uf/ext/gltf/mesh.h b/engine/inc/uf/ext/gltf/mesh.h index 5f4d1a2b..3209b9a1 100644 --- a/engine/inc/uf/ext/gltf/mesh.h +++ b/engine/inc/uf/ext/gltf/mesh.h @@ -36,7 +36,7 @@ namespace ext { alignas(8) pod::Vector2f uv; alignas(16) pod::Vector3f normal; alignas(16) pod::Vector4f tangent; - alignas(4) uint32_t id; + alignas(8) pod::Vector2ui id; static UF_API std::vector descriptor; @@ -54,7 +54,7 @@ namespace ext { alignas(8) pod::Vector2f uv; alignas(16) pod::Vector3f normal; alignas(16) pod::Vector4f tangent; - alignas(4) uint32_t id; + alignas(8) pod::Vector2ui id; alignas(16) pod::Vector4f joints; alignas(16) pod::Vector4f weights; @@ -80,27 +80,27 @@ namespace ext { namespace std { template<> struct hash { size_t operator()(ext::gltf::mesh::ID const& vertex) const { - std::size_t seed = 3 + 2 + 3 + 4 + 1; + std::size_t seed = 3 + 2 + 3 + 4 + 2; std::hash hasher; for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.position[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 2; ++i ) seed ^= hasher( vertex.uv[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.normal[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 4; ++i ) seed ^= hasher( vertex.tangent[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= hasher( (float) vertex.id ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + for ( size_t i = 0; i < 2; ++i ) seed ^= hasher( (float) vertex.id[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } }; template<> struct hash { size_t operator()(ext::gltf::mesh::Skinned const& vertex) const { - std::size_t seed = 3 + 2 + 3 + 4 + 4 + 4 + 1; + std::size_t seed = 3 + 2 + 3 + 4 + 4 + 4 + 2; std::hash hasher; for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.position[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 2; ++i ) seed ^= hasher( vertex.uv[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 3; ++i ) seed ^= hasher( vertex.normal[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 4; ++i ) seed ^= hasher( vertex.tangent[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + for ( size_t i = 0; i < 2; ++i ) seed ^= hasher( (float) vertex.id[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 4; ++i ) seed ^= hasher( (float) vertex.joints[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); for ( size_t i = 0; i < 4; ++i ) seed ^= hasher( vertex.weights[i] ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= hasher( (float) vertex.id ) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } }; diff --git a/engine/src/engine/object/behaviors/gltf.cpp b/engine/src/engine/object/behaviors/gltf.cpp index bd722411..183f5ae4 100644 --- a/engine/src/engine/object/behaviors/gltf.cpp +++ b/engine/src/engine/object/behaviors/gltf.cpp @@ -49,27 +49,47 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { graphPointer = &graph; } auto& graph = this->getComponent(); - uf::Object* objectPointer = graph.entity; + uf::Object* objectPointer = graph.root.entity; objectPointer->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& graphic = entity->getComponent(); if ( !(graph.mode & ext::gltf::LoadMode::LOAD) ) { - { - std::string filename = "/gltf.stereo.vert.spv"; - if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { - filename = "/gltf.stereo.skinned.vert.spv"; + if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { + { + std::string filename = "/gltf.stereo.vert.spv"; + if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { + filename = "/gltf.stereo.skinned.vert.spv"; + } + if ( metadata["system"]["renderer"]["shaders"]["vertex"].is() ) + filename = metadata["system"]["renderer"]["shaders"]["vertex"].as(); + filename = this->grabURI( filename, metadata["system"]["root"].as() ); + graphic.material.attachShader(filename, VK_SHADER_STAGE_VERTEX_BIT); + } + { + std::string filename = "/gltf.frag.spv"; + if ( metadata["system"]["renderer"]["shaders"]["fragment"].is() ) + filename = metadata["system"]["renderer"]["shaders"]["fragment"].as(); + filename = this->grabURI( filename, metadata["system"]["root"].as() ); + graphic.material.attachShader(filename, VK_SHADER_STAGE_FRAGMENT_BIT); + } + } else { + { + std::string filename = "/gltf.stereo.instanced.vert.spv"; + if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { + filename = "/gltf.stereo.skinned.instanced.vert.spv"; + } + if ( metadata["system"]["renderer"]["shaders"]["vertex"].is() ) + filename = metadata["system"]["renderer"]["shaders"]["vertex"].as(); + filename = this->grabURI( filename, metadata["system"]["root"].as() ); + graphic.material.attachShader(filename, VK_SHADER_STAGE_VERTEX_BIT); + } + { + std::string filename = "/gltf.frag.spv"; + if ( metadata["system"]["renderer"]["shaders"]["fragment"].is() ) + filename = metadata["system"]["renderer"]["shaders"]["fragment"].as(); + filename = this->grabURI( filename, metadata["system"]["root"].as() ); + graphic.material.attachShader(filename, VK_SHADER_STAGE_FRAGMENT_BIT); } - if ( metadata["system"]["renderer"]["shaders"]["vertex"].is() ) - filename = metadata["system"]["renderer"]["shaders"]["vertex"].as(); - filename = this->grabURI( filename, metadata["system"]["root"].as() ); - graphic.material.attachShader(filename, VK_SHADER_STAGE_VERTEX_BIT); - } - { - std::string filename = "/gltf.frag.spv"; - if ( metadata["system"]["renderer"]["shaders"]["fragment"].is() ) - filename = metadata["system"]["renderer"]["shaders"]["fragment"].as(); - filename = this->grabURI( filename, metadata["system"]["root"].as() ); - graphic.material.attachShader(filename, VK_SHADER_STAGE_FRAGMENT_BIT); } } @@ -123,7 +143,9 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { } auto& eMetadata = entity->getComponent(); eMetadata["textures"]["map"] = metadata["textures"]["map"]; - uf::instantiator::bind( "RenderBehavior", *entity ); + if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { + uf::instantiator::bind( "RenderBehavior", *entity ); + } uf::instantiator::bind( "GltfBehavior", *entity ); if ( entity->getUid() == 0 ) entity->initialize(); }); @@ -138,22 +160,6 @@ void uf::GltfBehavior::initialize( uf::Object& self ) { uf::iostream << "Animations found: " << json << "\n"; } } - /* - auto& controller = scene.getController(); - ext::json::forEach(metadata["model"]["tags"], [&]( const std::string& key, const ext::json::Value& v ){ - if ( !ext::json::isObject( v ) ) return; - if ( v["action"].as() != "spawn" ) return; - auto* node = uf::graph::find( graph, key ); - if ( !node ) return; - std::cout << "Found: " << key << "\t" << v << std::endl; - auto flatten = uf::transform::flatten( node->transform ); - auto& controllerTransform = controller.getComponent>(); - std::cout << "Set transform from: " << uf::string::toString( controllerTransform.position ) << std::endl; - controllerTransform.position = flatten.position; - controllerTransform.orientation = flatten.orientation; - std::cout << "Set transform to: " << uf::string::toString( controllerTransform.position ) << std::endl; - }); - */ }); } void uf::GltfBehavior::destroy( uf::Object& self ) { @@ -201,21 +207,86 @@ void uf::GltfBehavior::tick( uf::Object& self ) { if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { uf::graph::update( graph ); } - + /* auto& transform = this->getComponent>(); auto& node = graph.node->children.size() == 1 ? *graph.node->children[0] : *graph.node; pod::Matrix4f nodeMatrix = node.transform.model; - pod::Node*currentParent = node.parent; + pod::Node* currentParent = uf::graph::find(graph, node.parent); while ( currentParent ) { nodeMatrix = currentParent->transform.model * nodeMatrix; - currentParent = currentParent->parent; + currentParent = uf::graph::find(graph, currentParent->parent); } transform.model = nodeMatrix; + */ } /* Update uniforms */ if ( this->hasComponent() ) { auto& scene = uf::scene::getCurrentScene(); auto& metadata = this->getComponent(); auto& graphic = this->getComponent(); + auto& controller = scene.getController(); + auto& camera = controller.getComponent(); + + if ( !graphic.initialized ) return; + if ( !graphic.material.hasShader("fragment") ) return; + if ( !graphic.hasStorage("Materials") ) return; + if ( !ext::json::isObject(metadata["textures"]["map"]) ) return; + + auto* objectWithGraph = this; + while ( objectWithGraph != &scene ) { + if ( objectWithGraph->hasComponent() ) break; + objectWithGraph = &objectWithGraph->getParent().as(); + } + if ( !objectWithGraph->hasComponent() ) return; + auto& graph = objectWithGraph->getComponent(); + if ( graph.materials.empty() ) return; + + { + auto& shader = graphic.material.getShader("fragment"); + std::vector materials( graph.materials.size() ); + for ( size_t i = 0; i < graph.materials.size(); ++i ) { + materials[i] = graph.materials[i].storage; + materials[i].indexMappedTarget = graph.mode & ext::gltf::LoadMode::ATLAS ? 0 : i; + materials[i].factorMappedBlend = graph.mode & ext::gltf::LoadMode::ATLAS ? 1.0f : 0.0f; + } + size_t texturesLen = graphic.material.textures.size(); + ext::json::forEach(metadata["textures"]["map"], [&]( const std::string& key, const ext::json::Value& mapping ){ + uint32_t from = std::stoi(key); + uint32_t to = mapping[0].as(); + float blend = 1.0f; + if ( mapping[1].as() == "sin(time)" ) { + blend = sin(uf::physics::time::current)*0.5f+0.5f; + } else if ( mapping[1].as() == "cos(time)" ) { + blend = cos(uf::physics::time::current)*0.5f+0.5f; + } else if ( mapping[1].is() ) { + blend = mapping[1].as(); + } + if ( from >= texturesLen || to >= texturesLen ) return; + materials[from].indexMappedTarget = to; + materials[from].factorMappedBlend = blend; + }); + auto& storageBuffer = *graphic.getStorageBuffer("Materials"); + graphic.updateBuffer( (void*) materials.data(), materials.size() * sizeof(pod::Material::Storage), graph.root.materialBufferIndex /*storageBuffer*/, false ); + } + if ( !(graph.mode & ext::gltf::LoadMode::SEPARATE) ) { + auto& shader = graphic.material.getShader("vertex"); + std::vector instances( graph.nodes.size() ); + for ( size_t i = 0; i < graph.nodes.size(); ++i ) { + auto& node = graph.nodes[i]; + instances[i] = node.entity ? uf::transform::model( node.entity->getComponent>() ) : uf::transform::model( node.transform ); + } + auto& storageBuffer = *graphic.getStorageBuffer("Models"); + graphic.updateBuffer( (void*) instances.data(), instances.size() * sizeof(pod::Matrix4f), graph.instanceBufferIndex /*storageBuffer*/, false ); + + } + } +} +void uf::GltfBehavior::render( uf::Object& self ) { + /* Update uniforms */ if ( this->hasComponent() ) { + auto& scene = uf::scene::getCurrentScene(); + auto& metadata = this->getComponent(); + auto& graphic = this->getComponent(); + auto& controller = scene.getController(); + auto& camera = controller.getComponent(); if ( !graphic.initialized ) return; if ( !graphic.material.hasShader("fragment") ) return; @@ -231,72 +302,33 @@ void uf::GltfBehavior::tick( uf::Object& self ) { auto& graph = objectWithGraph->getComponent(); if ( graph.materials.empty() ) return; - - auto& shader = graphic.material.getShader("fragment"); - std::vector materials( graph.materials.size() ); - for ( size_t i = 0; i < graph.materials.size(); ++i ) { - materials[i] = graph.materials[i].storage; - materials[i].indexMappedTarget = graph.mode & ext::gltf::LoadMode::ATLAS ? 0 : i; - materials[i].factorMappedBlend = graph.mode & ext::gltf::LoadMode::ATLAS ? 1.0f : 0.0f; - } - size_t texturesLen = graphic.material.textures.size(); - ext::json::forEach(metadata["textures"]["map"], [&]( const std::string& key, const ext::json::Value& mapping ){ - uint32_t from = std::stoi(key); - uint32_t to = mapping[0].as(); - float blend = 1.0f; - if ( mapping[1].as() == "sin(time)" ) { - blend = sin(uf::physics::time::current)*0.5f+0.5f; - } else if ( mapping[1].as() == "cos(time)" ) { - blend = cos(uf::physics::time::current)*0.5f+0.5f; - } else if ( mapping[1].is() ) { - blend = mapping[1].as(); + // std::cout << "START" << std::endl; + if ( !(graph.mode & ext::gltf::LoadMode::SEPARATE) ) { + auto& shader = graphic.material.getShader("vertex"); + auto& uniform = shader.getUniform("UBO"); + #if UF_UNIFORMS_UPDATE_WITH_JSON + // auto uniforms = shader.getUniformJson("UBO"); + ext::json::Value uniforms; + for ( std::size_t i = 0; i < 2; ++i ) { + uniforms["view"][i] = uf::matrix::encode( camera.getView( i ) ); + uniforms["projection"][i] = uf::matrix::encode( camera.getProjection( i ) ); } - if ( from >= texturesLen || to >= texturesLen ) return; - materials[from].indexMappedTarget = to; - materials[from].factorMappedBlend = blend; - }); - auto& storageBuffer = *graphic.getStorageBuffer("Materials"); - graphic.updateBuffer( (void*) materials.data(), materials.size() * sizeof(pod::Material::Storage), storageBuffer, false ); - /* - struct UniformDescriptor { - struct Mapping { - alignas(4) uint32_t target; - alignas(4) float blend; - uint32_t padding[2]; - } map; - }; - auto& uniform = shader.getUniform("UBO"); - - uint8_t* uniformBuffer = (uint8_t*) (void*) uniform; - UniformDescriptor* uniforms = (UniformDescriptor*) uniformBuffer; - UniformDescriptor::Mapping* mappings = (UniformDescriptor::Mapping*) &(uniformBuffer)[sizeof(UniformDescriptor) - sizeof(UniformDescriptor::Mapping)]; - - size_t textures = graphic.material.textures.size(); - for ( size_t i = 0; i < textures; ++i ) { - mappings[i].target = i; - mappings[i].blend = 0.0f; - } - for ( auto it = metadata["textures"]["map"].begin(); it != metadata["textures"]["map"].end(); ++it ) { - std::string key = it.key(); - uint32_t from = std::stoi(key); - uint32_t to = metadata["textures"]["map"][key][0].as(); - float blend = 1.0f; - if ( metadata["textures"]["map"][key][1].as() == "sin(time)" ) { - blend = sin(uf::physics::time::current)*0.5f+0.5f; - } else if ( metadata["textures"]["map"][key][1].as() == "cos(time)" ) { - blend = cos(uf::physics::time::current)*0.5f+0.5f; - } else if ( metadata["textures"]["map"][key][1].is() ) { - blend = metadata["textures"]["map"][key][1].as(); + // std::cout << "UNIFORM BUFFER UBO: " << &uniforms << std::endl; + shader.updateUniform("UBO", uniforms ); + #else + struct UniformDescriptor { + alignas(16) pod::Matrix4f view[2]; + alignas(16) pod::Matrix4f projection[2]; + }; + auto& uniforms = uniform.get(); + for ( std::size_t i = 0; i < 2; ++i ) { + uniforms.view[i] = camera.getView( i ); + uniforms.projection[i] = camera.getProjection( i ); } - if ( from >= textures || to >= textures ) continue; - mappings[from].target = to; - mappings[from].blend = blend; + // std::cout << "UNIFORM BUFFER UBO: " << &uniforms << std::endl; + shader.updateUniform( "UBO", uniform ); + #endif } - shader.updateUniform( "UBO" ); - */ } -} -void uf::GltfBehavior::render( uf::Object& self ) { - } #undef this \ No newline at end of file diff --git a/engine/src/ext/gltf/gltf.cpp b/engine/src/ext/gltf/gltf.cpp index dd14921f..ab097b01 100644 --- a/engine/src/ext/gltf/gltf.cpp +++ b/engine/src/ext/gltf/gltf.cpp @@ -40,25 +40,31 @@ namespace { } namespace { - pod::Node& loadNode( const tinygltf::Model& model, pod::Graph& graph, int32_t nodeIndex, pod::Node& parentNode ); + int32_t loadNode( const tinygltf::Model& model, pod::Graph& graph, int32_t nodeIndex, int32_t parentIndex ); - pod::Node& loadNodes( const tinygltf::Model& model, pod::Graph& graph, const std::vector& nodes, pod::Node& node ) { + int32_t loadNodes( const tinygltf::Model& model, pod::Graph& graph, const std::vector& nodes, int32_t nodeIndex ) { + graph.nodes[nodeIndex].children.reserve( nodes.size() ); for ( auto i : nodes ) { - node.children.emplace_back(&loadNode( model, graph, i, node )); + int32_t childIndex = loadNode( model, graph, i, nodeIndex ); + if ( 0 <= childIndex && childIndex < graph.nodes.size() && childIndex != nodeIndex && + std::find( graph.nodes[nodeIndex].children.begin(), graph.nodes[nodeIndex].children.end(), childIndex ) == graph.nodes[nodeIndex].children.end() + ) { + graph.nodes[nodeIndex].children.emplace_back(childIndex); + } } - return node; + return nodeIndex; } - pod::Node& loadNode( const tinygltf::Model& model, pod::Graph& graph, int32_t nodeIndex, pod::Node& parentNode ) { - auto& newNode = uf::graph::node(); - if ( nodeIndex < 0 ) return newNode; + int32_t loadNode( const tinygltf::Model& model, pod::Graph& graph, int32_t nodeIndex, int32_t parentIndex ) { + if ( nodeIndex < 0 ) return nodeIndex; auto& node = model.nodes[nodeIndex]; - newNode.parent = &parentNode; - newNode.index = nodeIndex; - newNode.skin = node.skin; - newNode.name = node.name; + graph.nodes[nodeIndex].parent = parentIndex; + graph.nodes[nodeIndex].index = nodeIndex; + graph.nodes[nodeIndex].skin = node.skin; - auto& transform = newNode.transform; + graph.nodes[nodeIndex].name = node.name; + + auto& transform = graph.nodes[nodeIndex].transform; if ( node.translation.size() == 3 ) { transform.position.x = node.translation[0]; transform.position.y = node.translation[1]; @@ -89,18 +95,16 @@ namespace { } else { transform.model = uf::matrix::identity(); } - if ( newNode.parent != &newNode ) { - transform.reference = &newNode.parent->transform; + if ( 0 <= parentIndex && parentIndex < graph.nodes.size() && nodeIndex != parentIndex ) { + transform.reference = &graph.nodes[parentIndex].transform; } - if ( node.children.size() > 0 ) { - loadNodes( model, graph, node.children, newNode ); + loadNodes( model, graph, node.children, nodeIndex ); } - auto& mesh = newNode.mesh; - auto& collider = newNode.collider; + auto& mesh = graph.nodes[nodeIndex].mesh; + auto& collider = graph.nodes[nodeIndex].collider; if ( node.mesh > -1 ) { - // size_t id = 0; for ( auto& primitive : model.meshes[node.mesh].primitives ) { size_t verticesStart = mesh.vertices.size(); size_t indicesStart = mesh.indices.size(); @@ -137,12 +141,6 @@ namespace { pod::Vector3f origin = (maxCorner + minCorner) * 0.5f; pod::Vector3f size = (maxCorner - minCorner) * 0.5f; - /* - if ( (graph.mode & ext::gltf::LoadMode::COLLISION) && (graph.mode & ext::gltf::LoadMode::AABB) ) { - auto* box = new uf::BoundingBox( origin, size ); - collider.add(box); - } - */ } if ( attribute.name == "JOINTS_0" ) { auto* buffer = reinterpret_cast(&(model.buffers[view.buffer].data[accessor.byteOffset + view.byteOffset])); @@ -195,7 +193,8 @@ namespace { if ( graph.mode & ext::gltf::LoadMode::TRANSFORM ) { vertex.position = uf::matrix::multiply( modelMatrix, vertex.position ); } - vertex.id = primitive.material; + vertex.id.x = nodeIndex; + vertex.id.y = primitive.material; } if ( primitive.indices > -1 ) { @@ -238,19 +237,9 @@ namespace { } } */ - // ++id; } - // setup collision - /* - if ( (graph.mode & ext::gltf::LoadMode::COLLISION) && !(graph.mode & ext::gltf::LoadMode::AABB) ) { - // auto* c = new uf::MeshCollider( transform ); - auto* c = new uf::MeshCollider(); - c->setPositions( mesh ); - collider.add(c); - } - */ } - return newNode; + return nodeIndex; } } @@ -348,18 +337,21 @@ pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t } // load node information/meshes { - const auto& scene = model.scenes[model.defaultScene > -1 ? model.defaultScene : 0]; - auto& node = uf::graph::node(); - graph.node = &loadNodes( model, graph, scene.nodes, node ); + size_t rootIndex = model.defaultScene > -1 ? model.defaultScene : 0; + const auto& scene = model.scenes[rootIndex]; + graph.nodes.resize( model.nodes.size() ); + graph.root.index = -1; + graph.root.children.reserve( scene.nodes.size() ); + for ( auto i : scene.nodes ) { + size_t childIndex = loadNode( model, graph, i, -1 ); + graph.root.children.emplace_back(childIndex); + } } // load lights { for ( auto& l : model.lights ) { - auto* node = uf::graph::find( graph, l.name ); - if ( !node ) continue; auto& light = graph.lights.emplace_back(); light.name = l.name; - light.transform = node->transform; light.color = { l.color[0], l.color[1], @@ -388,8 +380,7 @@ pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t } for ( auto& joint : s.joints ) { - auto* node = uf::graph::find( graph, joint ); - if ( node ) skin.joints.emplace_back( node ); + skin.joints.emplace_back( joint ); } } } @@ -449,7 +440,7 @@ pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t auto& channel = animation.channels.emplace_back(); channel.path = c.target_path; channel.sampler = c.sampler; - channel.node = uf::graph::find(graph, c.target_node); + channel.node = c.target_node; } } } @@ -459,14 +450,16 @@ pod::Graph ext::gltf::load( const std::string& filename, ext::gltf::load_mode_t // print node /* std::cout << "Tree for " << filename << " (Mode: " << std::bitset<16>( graph.mode ) << "): " << std::endl; - std::function print = [&]( pod::Node& node, size_t indent ) { + std::function print = [&]( pod::Node& node, size_t indent ) { for ( size_t i = 0; i < indent; ++i ) std::cout << "\t"; - std::cout << "Node " << &node << " (" << node.index << "):" << std::endl; - for ( auto* child : node.children ) print( *child, indent + 1 ); + std::cout << "Node " << node.name << " (" << node.index << ": " << &node << "):" << std::endl; + for ( auto index : node.children ) { + print( graph.nodes[index], indent + 1 ); + } }; - print( *graph.node, 1 ); + print( graph.root, 1 ); std::cout << std::endl; */ - return graph; + return graph; } \ No newline at end of file diff --git a/engine/src/ext/gltf/graph.cpp b/engine/src/ext/gltf/graph.cpp index 34f3956b..eb56c6e1 100644 --- a/engine/src/ext/gltf/graph.cpp +++ b/engine/src/ext/gltf/graph.cpp @@ -2,75 +2,146 @@ #include #include -pod::Node& uf::graph::node() { - pod::Node* pointer = uf::MemoryPool::global.size() > 0 ? &uf::MemoryPool::global.alloc() : new pod::Node; - return *pointer; +namespace { + void initializeGraphics( pod::Graph& graph, uf::Object& entity ) { + auto& graphic = entity.getComponent(); + graphic.device = &uf::renderer::device; + graphic.material.device = &uf::renderer::device; + graphic.descriptor.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + graphic.descriptor.cullMode = !(graph.mode & ext::gltf::LoadMode::INVERT) ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_FRONT_BIT; // VK_CULL_MODE_NONE + if ( graph.mode & ext::gltf::LoadMode::ATLAS ) { + auto& atlas = *graph.atlas; + auto& texture = graphic.material.textures.emplace_back(); + texture.loadFromImage( atlas.getAtlas() ); + } else { + for ( auto& image : graph.images ) { + auto& texture = graphic.material.textures.emplace_back(); + texture.loadFromImage( image ); + } + for ( auto& sampler : graph.samplers ) { + graphic.material.samplers.emplace_back( sampler ); + } + } + if ( graph.mode & ext::gltf::LoadMode::LOAD ) { + if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { + if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { + graphic.material.attachShader("./data/shaders/gltf.stereo.skinned.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + } else { + graphic.material.attachShader("./data/shaders/gltf.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + } + } else { + if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { + graphic.material.attachShader("./data/shaders/gltf.stereo.skinned.instanced.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + } else { + graphic.material.attachShader("./data/shaders/gltf.stereo.instanced.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); + } + } + graphic.material.attachShader("./data/shaders/gltf.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); + + auto& shader = graphic.material.shaders.back(); + struct SpecializationConstant { + uint32_t textures = 1; + }; + auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0]; + specializationConstants->textures = graphic.material.textures.size(); + for ( auto& binding : shader.descriptorSetLayoutBindings ) { + if ( binding.descriptorCount > 1 ) + binding.descriptorCount = specializationConstants->textures; + } + } else { + graphic.process = false; + } + } } -pod::Matrix4f uf::graph::local( const pod::Node& node ) { + +pod::Matrix4f uf::graph::local( pod::Graph& graph, int32_t index ) { + auto& node = 0 < index && index <= graph.nodes.size() ? graph.nodes[index] : graph.root; return uf::matrix::translate( uf::matrix::identity(), node.transform.position ) * uf::quaternion::matrix(node.transform.orientation) * uf::matrix::scale( uf::matrix::identity(), node.transform.scale ) * node.transform.model; } -pod::Matrix4f uf::graph::matrix( const pod::Node& node ) { -/* - if ( !node.parent ) return local(node); - return matrix( *node.parent ) * local(node); -*/ - pod::Matrix4f matrix = local( node ); - pod::Node* parent = node.parent; - while ( parent ) { - matrix = local( *parent ) * matrix; - parent = parent->parent; +pod::Matrix4f uf::graph::matrix( pod::Graph& graph, int32_t index ) { + pod::Matrix4f matrix = local( graph, index ); + auto& node = *uf::graph::find( graph, index ); + int32_t parent = node.parent; + while ( 0 < parent && parent <= graph.nodes.size() ) { + matrix = local( graph, parent ) * matrix; + parent = graph.nodes[parent].parent; } return matrix; } - -pod::Node* uf::graph::find( pod::Node* node, int32_t index ) { - return node ? find( *node, index ) : NULL; +pod::Node* uf::graph::find( pod::Graph& graph, int32_t index ) { + return 0 <= index && index < graph.nodes.size() ? &graph.nodes[index] : NULL; } -pod::Node* uf::graph::find( const pod::Graph& graph, int32_t index ) { - return find( graph.node, index ); -} -pod::Node* uf::graph::find( const pod::Node& node, int32_t index ) { - if ( node.parent && node.parent->index == index ) return node.parent; - if ( node.index == index ) return const_cast(&node); - - pod::Node* target = NULL; - for ( auto& child : node.children ) - if ( (target = uf::graph::find(*child, index)) ) break; - return target; -} - -pod::Node* uf::graph::find( pod::Node* node, const std::string& name ) { - return node ? find( *node, name ) : NULL; -} -pod::Node* uf::graph::find( const pod::Graph& graph, const std::string& name ) { - return find( graph.node, name ); -} -pod::Node* uf::graph::find( const pod::Node& node, const std::string& name ) { - if ( node.parent && node.parent->name == name ) return node.parent; - if ( node.name == name ) return const_cast(&node); - - pod::Node* target = NULL; - for ( auto& child : node.children ) - if ( (target = uf::graph::find(*child, name)) ) break; - return target; +pod::Node* uf::graph::find( pod::Graph& graph, const std::string& name ) { + for ( auto& node : graph.nodes ) if ( node.name == name ) return &node; + return NULL; } void uf::graph::process( uf::Object& entity ) { auto& graph = entity.getComponent(); - return process( graph, *graph.node, entity ); + for ( auto index : graph.root.children ) process( graph, index, entity ); } void uf::graph::process( pod::Graph& graph ) { - if ( !graph.entity ) graph.entity = new uf::Object; - process( graph, *graph.node, *graph.entity ); + if ( !graph.root.entity ) graph.root.entity = new uf::Object; + for ( auto index : graph.root.children ) process( graph, index, *graph.root.entity ); - graph.entity->process([&]( uf::Entity* entity ) { + if ( !(graph.mode & ext::gltf::LoadMode::SEPARATE) ) { + initializeGraphics( graph, *graph.root.entity ); + + auto& graphic = graph.root.entity->getComponent(); + + std::vector instances; + instances.reserve( graph.nodes.size() ); + for ( auto& node : graph.nodes ) { + instances.emplace_back( uf::transform::model( node.transform ) ); + } + // Models storage buffer + graph.instanceBufferIndex = graphic.initializeBuffer( + (void*) instances.data(), + instances.size() * sizeof(pod::Matrix4f), + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + true + ); + // Joints storage buffer + if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { + for ( auto& node : graph.nodes ) { + if ( node.skin < 0 ) continue; + auto& skin = graph.skins[node.skin]; + node.jointBufferIndex = graphic.initializeBuffer( + (void*) skin.inverseBindMatrices.data(), + skin.inverseBindMatrices.size() * sizeof(pod::Matrix4f), + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + true + ); + break; + } + } + // Materials storage buffer + std::vector materials( graph.materials.size() ); + for ( size_t i = 0; i < graph.materials.size(); ++i ) { + materials[i] = graph.materials[i].storage; + materials[i].indexMappedTarget = i; + } + graph.root.materialBufferIndex = graphic.initializeBuffer( + (void*) materials.data(), + materials.size() * sizeof(pod::Material::Storage), + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + true + ); + } + + graph.root.entity->process([&]( uf::Entity* entity ) { if ( !entity->hasComponent() ) return; auto& mesh = entity->getComponent(); + auto& metadata = entity->getComponent(); + std::string nodeName = metadata["system"]["graph"]["name"].as(); if ( graph.mode & ext::gltf::LoadMode::NORMALS ) { // bool invert = false; bool INVERTED = graph.mode & ext::gltf::LoadMode::INVERT; @@ -108,8 +179,7 @@ void uf::graph::process( pod::Graph& graph ) { graphic.initialize(); graphic.initializeGeometry( mesh ); } - auto& metadata = entity->getComponent(); - std::string nodeName = metadata["system"]["graph"]["name"].as(); + if ( !ext::json::isNull( graph.metadata["tags"][nodeName] ) ) { auto& info = graph.metadata["tags"][nodeName]; if ( info["collision"].is() ) { @@ -132,33 +202,15 @@ void uf::graph::process( pod::Graph& graph ) { } } } - /* - if ( graph.mode & ext::gltf::LoadMode::COLLISION ) { - bool applyTransform = false; //!(graph.mode & ext::gltf::LoadMode::TRANSFORM); - auto& collider = ext::bullet::create( entity->as(), mesh, applyTransform, 1 ); - if ( !applyTransform ) { - btBvhTriangleMeshShape* triangleMeshShape = (btBvhTriangleMeshShape*) collider.shape; - btTriangleInfoMap* triangleInfoMap = new btTriangleInfoMap(); - triangleInfoMap->m_edgeDistanceThreshold = 0.01f; - triangleInfoMap->m_maxEdgeAngleThreshold = SIMD_HALF_PI*0.25; - if ( applyTransform ) { - btGenerateInternalEdgeInfo(triangleMeshShape, triangleInfoMap); - } - collider.body->setCollisionFlags(collider.body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK); - } - } - */ }); } -void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent ) { +void uf::graph::process( pod::Graph& graph, int32_t index, uf::Object& parent ) { // create child if requested + uf::Object* pointer = new uf::Object; + parent.addChild(*pointer); - uf::Object* pointer = &parent; - if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { - pointer = new uf::Object; - parent.addChild(*pointer); - } uf::Object& entity = *pointer; + auto& node = graph.nodes[index]; node.entity = &entity; bool setName = entity.getName() == "Entity"; @@ -181,8 +233,8 @@ void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent auto& child = entity.loadChild( filename, false ); auto& childTransform = child.getComponent>(); auto flatten = uf::transform::flatten( node.transform ); - childTransform.position = flatten.position; - childTransform.orientation = flatten.orientation; + if ( !info["preserve position"].as() ) childTransform.position = flatten.position; + if ( !info["preserve orientation"].as() ) childTransform.orientation = flatten.orientation; } } // create as light @@ -201,28 +253,16 @@ void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent } // set name - if ( setName ) { - entity.setName( node.name ); - } + if ( setName ) entity.setName( node.name ); // reference transform to parent - if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { + { auto& transform = entity.getComponent>(); transform = node.transform; // is a child - if ( node.parent != &node ) { - auto& parent = entity.getParent().getComponent>(); - transform.reference = &parent; - } + if ( node.index != -1 ) + transform.reference = &entity.getParent().getComponent>(); } - // move colliders -/* - if ( !node.collider.getContainer().empty() ) { - auto& collider = entity.getComponent(); - collider.getContainer().insert( collider.getContainer().end(), node.collider.getContainer().begin(), node.collider.getContainer().end() ); - node.collider.getContainer().clear(); - } -*/ // copy mesh if ( !node.mesh.vertices.empty() ) { auto& mesh = entity.getComponent(); @@ -237,86 +277,18 @@ void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent mesh.indices.reserve( node.mesh.indices.size() + start.indices ); for ( auto& v : node.mesh.vertices ) mesh.vertices.emplace_back( v ); for ( auto& i : node.mesh.indices ) mesh.indices.emplace_back( i + start.indices ); - // attach collider if requested - // if ( (graph.mode & ext::gltf::LoadMode::COLLISION) && !(graph.mode & ext::gltf::LoadMode::AABB) ) { - // copy image + sampler - if ( graph.mode & ext::gltf::LoadMode::RENDER ) { - auto& graphic = entity.getComponent(); - graphic.device = &uf::renderer::device; - graphic.material.device = &uf::renderer::device; - graphic.descriptor.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - - if ( !(graph.mode & ext::gltf::LoadMode::INVERT) ){ - graphic.descriptor.cullMode = VK_CULL_MODE_BACK_BIT; - } else { - graphic.descriptor.cullMode = VK_CULL_MODE_FRONT_BIT; - } - // graphic.descriptor.cullMode = VK_CULL_MODE_NONE; + + if ( !(graph.mode & ext::gltf::LoadMode::SEPARATE) ) { + auto& mesh = graph.root.entity->getComponent(); + ext::gltf::mesh_t expanded = node.mesh; + expanded.expand(); + mesh.vertices.reserve( mesh.vertices.size() + expanded.vertices.size() ); + for ( auto& v : expanded.vertices ) mesh.vertices.emplace_back( v ); + } else if ( graph.mode & ext::gltf::LoadMode::RENDER ) { uf::instantiator::bind("RenderBehavior", entity); - /* - if ( graph.mode & ext::gltf::LoadMode::SEPARATE ) { - if ( graph.mode & ext::gltf::LoadMode::ATLAS ) { - auto& atlas = *graph.atlas; - auto& texture = graphic.material.textures.emplace_back(); - texture.loadFromImage( atlas.getAtlas() ); - } else { - if ( !graph.images.empty() ) { - auto& image = graph.images.front(); - auto& texture = graphic.material.textures.emplace_back(); - texture.loadFromImage( image ); - graph.images.erase( graph.images.begin() ); - } - if ( !graph.samplers.empty() ) { - auto& sampler = graph.samplers.front(); - graphic.material.samplers.emplace_back( sampler ); - graph.samplers.erase( graph.samplers.begin() ); - } - } - graphic.initialize(); - graphic.initializeGeometry( mesh ); - - if ( graph.mode & ext::gltf::LoadMode::COLLISION ) { - auto& collider = ext::bullet::create( entity, mesh, 0 ); - } - } else - */ - { - if ( graph.mode & ext::gltf::LoadMode::ATLAS ) { - auto& atlas = *graph.atlas; - auto& texture = graphic.material.textures.emplace_back(); - texture.loadFromImage( atlas.getAtlas() ); - } else { - for ( auto& image : graph.images ) { - auto& texture = graphic.material.textures.emplace_back(); - texture.loadFromImage( image ); - } - for ( auto& sampler : graph.samplers ) { - graphic.material.samplers.emplace_back( sampler ); - } - } - } - if ( graph.mode & ext::gltf::LoadMode::LOAD ) { - if ( graph.mode & ext::gltf::LoadMode::SKINNED ) { - graphic.material.attachShader("./data/shaders/gltf.stereo.skinned.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - } else { - graphic.material.attachShader("./data/shaders/gltf.stereo.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); - } - graphic.material.attachShader("./data/shaders/gltf.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); - - auto& shader = graphic.material.shaders.back(); - struct SpecializationConstant { - uint32_t textures = 1; - }; - auto* specializationConstants = (SpecializationConstant*) &shader.specializationConstants[0]; - specializationConstants->textures = graphic.material.textures.size(); - for ( auto& binding : shader.descriptorSetLayoutBindings ) { - if ( binding.descriptorCount > 1 ) - binding.descriptorCount = specializationConstants->textures; - } - } else { - graphic.process = false; - } - + initializeGraphics( graph, entity ); + auto& graphic = entity.getComponent(); + // Joints storage buffer if ( graph.mode & ext::gltf::LoadMode::SKINNED && node.skin >= 0 ) { auto& skin = graph.skins[node.skin]; node.jointBufferIndex = graphic.initializeBuffer( @@ -327,26 +299,23 @@ void uf::graph::process( pod::Graph& graph, pod::Node& node, uf::Object& parent true ); } - { - // update mappings - std::vector materials( graph.materials.size() ); - for ( size_t i = 0; i < graph.materials.size(); ++i ) { - materials[i] = graph.materials[i].storage; - materials[i].indexMappedTarget = i; - // graph.materials[i].id.mappedTarget = i; - } - node.materialBufferIndex = graphic.initializeBuffer( - (void*) materials.data(), - materials.size() * sizeof(pod::Material::Storage), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - true - ); + // Materials storage buffer + std::vector materials( graph.materials.size() ); + for ( size_t i = 0; i < graph.materials.size(); ++i ) { + materials[i] = graph.materials[i].storage; + materials[i].indexMappedTarget = i; } + node.materialBufferIndex = graphic.initializeBuffer( + (void*) materials.data(), + materials.size() * sizeof(pod::Material::Storage), + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + true + ); } } - - for ( auto* child : node.children ) uf::graph::process( graph, *child, entity ); + + for ( auto index : node.children ) uf::graph::process( graph, index, entity ); } void uf::graph::override( pod::Graph& graph ) { @@ -354,18 +323,14 @@ void uf::graph::override( pod::Graph& graph ) { graph.settings.animations.override.map.clear(); bool toNeutralPose = graph.sequence.empty(); // store every node's current transform - { - std::function process = [&]( pod::Node& node ){ - graph.settings.animations.override.map[&node].first = node.transform; - graph.settings.animations.override.map[&node].second = node.transform; - if ( toNeutralPose ) { - graph.settings.animations.override.map[&node].second.position = { 0, 0, 0 }; - graph.settings.animations.override.map[&node].second.orientation = { 0, 0, 0, 1 }; - graph.settings.animations.override.map[&node].second.scale = { 1, 1, 1 }; - } - for ( auto* child : node.children ) process( *child ); - }; - process( *graph.node ); + for ( auto& node : graph.nodes ) { + graph.settings.animations.override.map[node.index].first = node.transform; + graph.settings.animations.override.map[node.index].second = node.transform; + if ( toNeutralPose ) { + graph.settings.animations.override.map[node.index].second.position = { 0, 0, 0 }; + graph.settings.animations.override.map[node.index].second.orientation = { 0, 0, 0, 1 }; + graph.settings.animations.override.map[node.index].second.scale = { 1, 1, 1 }; + } } // set our destination transform per node if ( !toNeutralPose ) { @@ -435,12 +400,13 @@ void uf::graph::update( pod::Graph& graph, float delta ) { for ( size_t i = 0; i < sampler.inputs.size() - 1; ++i ) { if ( !(animation->cur >= sampler.inputs[i] && animation->cur <= sampler.inputs[i+1]) ) continue; float a = (animation->cur - sampler.inputs[i]) / (sampler.inputs[i+1] - sampler.inputs[i]); + auto& transform = graph.nodes[channel.node].transform; if ( channel.path == "translation" ) { - channel.node->transform.position = uf::vector::mix( sampler.outputs[i], sampler.outputs[i+1], a ); + transform.position = uf::vector::mix( sampler.outputs[i], sampler.outputs[i+1], a ); } else if ( channel.path == "rotation" ) { - channel.node->transform.orientation = uf::quaternion::normalize( uf::quaternion::slerp(sampler.outputs[i], sampler.outputs[i+1], a) ); + transform.orientation = uf::quaternion::normalize( uf::quaternion::slerp(sampler.outputs[i], sampler.outputs[i+1], a) ); } else if ( channel.path == "scale" ) { - channel.node->transform.scale = uf::vector::mix( sampler.outputs[i], sampler.outputs[i+1], a ); + transform.scale = uf::vector::mix( sampler.outputs[i], sampler.outputs[i+1], a ); } } } @@ -449,9 +415,9 @@ void uf::graph::update( pod::Graph& graph, float delta ) { OVERRIDE: // std::cout << "OVERRIDED: " << graph.settings.animations.override.a << "\t" << -std::numeric_limits::max() << std::endl; for ( auto pair : graph.settings.animations.override.map ) { - pair.first->transform.position = uf::vector::mix( pair.second.first.position, pair.second.second.position, graph.settings.animations.override.a ); - pair.first->transform.orientation = uf::quaternion::normalize( uf::quaternion::slerp(pair.second.first.orientation, pair.second.second.orientation, graph.settings.animations.override.a) ); - pair.first->transform.scale = uf::vector::mix( pair.second.first.scale, pair.second.second.scale, graph.settings.animations.override.a ); + graph.nodes[pair.first].transform.position = uf::vector::mix( pair.second.first.position, pair.second.second.position, graph.settings.animations.override.a ); + graph.nodes[pair.first].transform.orientation = uf::quaternion::normalize( uf::quaternion::slerp(pair.second.first.orientation, pair.second.second.orientation, graph.settings.animations.override.a) ); + graph.nodes[pair.first].transform.scale = uf::vector::mix( pair.second.first.scale, pair.second.second.scale, graph.settings.animations.override.a ); } // finished our overrided interpolation, clear it if ( (graph.settings.animations.override.a += delta * graph.settings.animations.override.speed) >= 1 ) { @@ -459,12 +425,11 @@ OVERRIDE: graph.settings.animations.override.map.clear(); } UPDATE: - // update joint matrices - update( graph, *graph.node ); + for ( auto& node : graph.nodes ) uf::graph::update( graph, node ); } void uf::graph::update( pod::Graph& graph, pod::Node& node ) { if ( node.skin >= 0 ) { - pod::Matrix4f nodeMatrix = matrix( node ); + pod::Matrix4f nodeMatrix = uf::graph::matrix( graph, node.index ); pod::Matrix4f inverseTransform = uf::matrix::inverse( nodeMatrix ); auto& skin = graph.skins[node.skin]; std::vector joints; @@ -474,40 +439,16 @@ void uf::graph::update( pod::Graph& graph, pod::Node& node ) { } if ( graph.settings.animations.override.a >= 0 || !graph.sequence.empty() ) { for ( size_t i = 0; i < skin.joints.size(); ++i ) { - joints[i] = inverseTransform * (matrix(*skin.joints[i]) * skin.inverseBindMatrices[i]); + joints[i] = inverseTransform * (uf::graph::matrix(graph, skin.joints[i]) * skin.inverseBindMatrices[i]); } } if ( node.entity && node.entity->hasComponent() ) { auto& graphic = node.entity->getComponent(); - auto& buffer = graphic.buffers.at(node.jointBufferIndex); graphic.updateBuffer( (void*) joints.data(), joints.size() * sizeof(pod::Matrix4f), buffer, false ); } } - for ( auto child : node.children ) update( graph, *child ); } void uf::graph::destroy( pod::Graph& graph ) { - { - std::function traverse = [&]( pod::Node& node ) { - for ( auto* child : node.children ) traverse( *child ); - if ( uf::MemoryPool::global.size() > 0 ) uf::MemoryPool::global.free( &node, sizeof(node) ); - else delete &node; - }; - traverse( *graph.node ); - /* - std::vector nodes; - std::function traverse = [&]( pod::Node& node ) { - nodes.emplace_back( &node ); - for ( auto* child : node.children ) traverse( *child ); - }; - traverse( *graph.node ); - for ( auto& node : nodes ) { - if ( uf::MemoryPool::global.size() > 0 ) - uf::MemoryPool::global.free( &node, sizeof(node) ); - else - delete node; - } - */ - } delete graph.atlas; } \ No newline at end of file diff --git a/engine/src/ext/gltf/mesh.cpp b/engine/src/ext/gltf/mesh.cpp index 60c37863..7101494a 100644 --- a/engine/src/ext/gltf/mesh.cpp +++ b/engine/src/ext/gltf/mesh.cpp @@ -18,7 +18,7 @@ std::vector ext::gltf::mesh::ID::descriptor = { offsetof(ext::gltf::mesh::ID, tangent) }, { - VK_FORMAT_R32_UINT, + VK_FORMAT_R32G32_SINT, offsetof(ext::gltf::mesh::ID, id) } }; @@ -40,7 +40,7 @@ std::vector ext::gltf::mesh::Skinned::descriptor offsetof(ext::gltf::mesh::Skinned, tangent) }, { - VK_FORMAT_R32_UINT, + VK_FORMAT_R32G32_SINT, offsetof(ext::gltf::mesh::Skinned, id) }, { diff --git a/engine/src/ext/lua/lua.cpp b/engine/src/ext/lua/lua.cpp index b386afa9..0ab1d2f5 100644 --- a/engine/src/ext/lua/lua.cpp +++ b/engine/src/ext/lua/lua.cpp @@ -121,8 +121,10 @@ void ext::lua::initialize() { string["extension"] = []( const std::string& filename ) { return uf::io::extension( filename ); }; - string["resolveURI"] = []( const std::string& filename ) { - return uf::io::resolveURI( filename ); + string["resolveURI"] = []( const std::string& filename, sol::variadic_args va ) { + auto it = va.begin(); + std::string root = it != va.end() ? *(it++) : std::string(""); + return uf::io::resolveURI( filename, root ); }; string["si"] = []( sol::variadic_args va ) { auto it = va.begin(); diff --git a/engine/src/ext/lua/usertypes/vector.cpp b/engine/src/ext/lua/usertypes/vector.cpp index 2a4c72e7..33b664c9 100644 --- a/engine/src/ext/lua/usertypes/vector.cpp +++ b/engine/src/ext/lua/usertypes/vector.cpp @@ -50,6 +50,9 @@ UF_LUA_REGISTER_USERTYPE(pod::Vector3f, UF_LUA_REGISTER_USERTYPE_DEFINE( magnitude, []( const pod::Vector3f& self ) { return uf::vector::magnitude( self ); }), + UF_LUA_REGISTER_USERTYPE_DEFINE( dot, []( const pod::Vector3f& left, const pod::Vector3f& right ) { + return uf::vector::dot( left, right ); + }), UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector3f& self ) { return uf::string::toString( self ); }) @@ -106,6 +109,9 @@ UF_LUA_REGISTER_USERTYPE(pod::Vector4f, UF_LUA_REGISTER_USERTYPE_DEFINE( magnitude, []( const pod::Vector3f& self ) { return uf::vector::magnitude( self ); }), + UF_LUA_REGISTER_USERTYPE_DEFINE( dot, []( const pod::Vector3f& left, const pod::Vector3f& right ) { + return uf::vector::dot( left, right ); + }), UF_LUA_REGISTER_USERTYPE_DEFINE( __tostring, []( pod::Vector4f& self ) { return uf::string::toString( self ); }) diff --git a/ext/behaviors/soundemitter/behavior.cpp b/ext/behaviors/soundemitter/behavior.cpp index b36a90b1..035ea5e0 100644 --- a/ext/behaviors/soundemitter/behavior.cpp +++ b/ext/behaviors/soundemitter/behavior.cpp @@ -19,6 +19,39 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { auto& sMetadata = scene.getComponent(); auto& assetLoader = scene.getComponent(); + if ( !metadata["audio"]["epsilon"].is() ) + metadata["audio"]["epsilon"] = 0.001f; + + auto& sounds = this->getComponent>(); + this->addHook( "sound:Emit.%UID%", [&](ext::json::Value& json){ + metadata["sounds"][sounds.size() ] = json; + uf::Audio& audio = sounds.emplace_back(); + audio.load(json["filename"].as()); + if ( ext::json::isNull(json["volume"]) ) json["volume"] = metadata["audio"]["volume"]; + if ( ext::json::isNull(json["pitch"]) ) json["pitch"] = metadata["audio"]["pitch"]; + if ( ext::json::isNull(json["gain"]) ) json["gain"] = metadata["audio"]["gain"]; + if ( ext::json::isNull(json["rolloffFactor"]) ) json["rolloffFactor"] = metadata["audio"]["rolloffFactor"]; + if ( ext::json::isNull(json["maxDistance"]) ) json["maxDistance"] = metadata["audio"]["maxDistance"]; + if ( ext::json::isNull(json["epsilon"]) ) json["epsilon"] = metadata["audio"]["epsilon"]; + { + float volume = 1.0f; + if ( json["volume"].is() ) { + volume = json["volume"].as(); + } else if ( json["volume"].is() ) { + std::string key = json["volume"].as(); + if ( sMetadata["volumes"][key].is() ) { + volume = sMetadata["volumes"][key].as(); + } + } + audio.setVolume(volume); + } + if ( json["pitch"].is() ) audio.setPitch(json["pitch"].as()); + if ( json["gain"].is() ) audio.setGain(json["gain"].as()); + if ( json["rolloffFactor"].is() ) audio.setRolloffFactor(json["rolloffFactor"].as()); + if ( json["maxDistance"].is() ) audio.setMaxDistance(json["maxDistance"].as()); + + audio.play(); + }); this->addHook( "asset:Load.%UID%", [&](ext::json::Value& json){ std::string filename = json["filename"].as(); @@ -27,53 +60,31 @@ void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { try { audioPointer = &assetLoader.get(filename); } catch ( ... ) {} if ( !audioPointer ) return; - uf::Audio& audio = this->getComponent(); //emitter.add(filename); - audio.load(filename); - { - float volume = 1.0f; - if ( metadata["audio"]["volume"].is() ) { - volume = metadata["audio"]["volume"].as(); - } else if ( metadata["audio"]["volume"].is() ) { - std::string key = metadata["audio"]["volume"].as(); - if ( sMetadata["volumes"][key].is() ) { - volume = sMetadata["volumes"][key].as(); - } - } - audio.setVolume(volume); - } - if ( metadata["audio"]["pitch"].is() ) { - audio.setPitch(metadata["audio"]["pitch"].as()); - } - if ( metadata["audio"]["gain"].is() ) { - audio.setGain(metadata["audio"]["gain"].as()); - } - if ( metadata["audio"]["rolloffFactor"].is() ) { - audio.setRolloffFactor(metadata["audio"]["rolloffFactor"].as()); - } - if ( metadata["audio"]["maxDistance"].is() ) { - audio.setMaxDistance(metadata["audio"]["maxDistance"].as()); - } - audio.play(); + uf::Serializer payload = metadata["audio"]; + payload["filename"] = filename; + this->callHook("sound:Emit.%UID%", payload); }); } void ext::SoundEmitterBehavior::tick( uf::Object& self ) { auto& emitter = this->getComponent(); auto& metadata = this->getComponent(); auto transform = this->getComponent>(); - + auto& sounds = this->getComponent>(); + auto flatten = uf::transform::flatten( transform ); // for ( auto pair : emitter.get() ) { // uf::Audio& audio = pair.second; - { - uf::Audio& audio = this->getComponent(); - if ( metadata["audio"]["spatial"].as() ) { - audio.setPosition( transform.position ); - audio.setOrientation( transform.orientation ); + for ( size_t i = 0; i < sounds.size(); ++i ) { + auto& audio = sounds[i]; + auto& json = metadata["sounds"][i]; + if ( json["spatial"].as() && audio.playing() ) { + audio.setPosition( flatten.position ); + audio.setOrientation( flatten.orientation ); } - if ( metadata["audio"]["loop"].as() ) { + if ( json["loop"].as() ) { float current = audio.getTime(); float end = audio.getDuration(); - float epsilon = 0.005f; + float epsilon = json["epsilon"].is() ? json["epsilon"].as() : 0.005f; if ( current + epsilon >= end || !audio.playing() ) { audio.setTime(0); if ( !audio.playing() ) audio.play();