diff --git a/src/Scene.cpp b/src/Scene.cpp index 31f851e..cf752b3 100644 --- a/src/Scene.cpp +++ b/src/Scene.cpp @@ -2,6 +2,7 @@ #include "ShaderProgram.h" #include "mesh.h" #include "name.h" +#include "relationship.h" #include "transform.h" #include "util/Log.h" @@ -30,19 +31,45 @@ Scene::Scene() // Spawn an entity for every node in scene for (auto const &node : default_scene->nodes) { - auto top_level_entity = m_registry.create(); - m_registry.emplace(top_level_entity, node->name); - m_registry.emplace(top_level_entity, node->transform); + std::function)> spawn_node = + [this, &spawn_node](GltfNode const &node, std::optional parent) { + auto entity = m_registry.create(); + m_registry.emplace(entity, node.name); + m_registry.emplace(entity, node.transform); + m_registry.emplace(entity, GlobalTransform{}); - auto mesh = node->mesh; - if (mesh.has_value()) { - for (auto const &primitive : mesh.value()->primitives) { - auto mesh_entity = m_registry.create(); - m_registry.emplace(mesh_entity, Transform{}); - m_registry.emplace>(mesh_entity, primitive.mesh); - m_registry.emplace>(mesh_entity, primitive.material); - } - } + if (parent.has_value()) { + m_registry.emplace(entity, Parent{.parent = parent.value()}); + } + + std::vector child_entities; + + auto mesh = node.mesh; + if (mesh.has_value()) { + for (auto const &primitive : mesh.value()->primitives) { + auto mesh_entity = m_registry.create(); + m_registry.emplace(mesh_entity, Parent{.parent = entity}); + m_registry.emplace(mesh_entity, Transform{}); + m_registry.emplace(mesh_entity, GlobalTransform{}); + m_registry.emplace>(mesh_entity, primitive.mesh); + m_registry.emplace>(mesh_entity, + primitive.material); + + child_entities.push_back(mesh_entity); + } + } + + // Spawn child nodes + for (auto const &child : node.children) { + auto child_entity = spawn_node(child, entity); + child_entities.push_back(child_entity); + } + + m_registry.emplace(entity, Children{.children = child_entities}); + return entity; + }; + + spawn_node(node, {}); } auto name_view = m_registry.view(); @@ -64,27 +91,45 @@ void Scene::update(std::chrono::duration delta, glm::mat4 viewProjMatrix, glm::vec3 viewPosition) { - auto mesh_view = m_registry.view(); + // Update GlobalTransform components + // TODO: Only do this when the Transform changed. + auto root_transform_view = + m_registry.view(entt::exclude); + auto transform_view = m_registry.view(); + + for (auto [entity, transform, global_transform] : root_transform_view.each()) { + global_transform = transform; + + auto parent_global_transform = global_transform; + if (auto *children = m_registry.try_get(entity)) { + for (auto child : children->children) { + std::function + transform_propagate = + [this, &transform_propagate, &transform_view]( + entt::entity entity, GlobalTransform parent_global_transform) { + auto [transform, global_transform, parent] = transform_view.get(entity); + global_transform.transform = parent_global_transform.transform * + GlobalTransform(transform).transform; + + if (auto *children = m_registry.try_get(entity)) { + for (auto child : children->children) { + transform_propagate(child, global_transform); + } + } + }; + + transform_propagate(child, parent_global_transform); + } + } + } + + auto mesh_view = m_registry.view(); for (auto [entity, mesh, transform] : mesh_view.each()) { shaderprogram->bind(); // Bind modelview matrix uniform { - // Translate * Rotate * Scale * vertex_vec; - // First scaling, then rotation, then translation - - // Translate - glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), transform.translation); - - // Rotate - glm::mat4 rotationMatrix = glm::toMat4(transform.rotation); - - // Scale - glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0f), transform.scale); - - glm::mat4 modelMatrix = translationMatrix * rotationMatrix * scaleMatrix; - - glm::mat4 modelViewProj = viewProjMatrix * modelMatrix; + glm::mat4 modelViewProj = viewProjMatrix * transform.transform; shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj); // shaderprogram->setUniform("u_modelMatrix", modelMatrix); // shaderprogram->setUniform("u_viewPosition", viewPosition); diff --git a/src/gltf_loader.cpp b/src/gltf_loader.cpp index eca6f77..c974783 100644 --- a/src/gltf_loader.cpp +++ b/src/gltf_loader.cpp @@ -105,7 +105,8 @@ static auto load_material(fx::gltf::Material const &material, static auto load_attribute(std::string_view attribute_name, uint32_t attribute_id, - fx::gltf::Document const &gltf) -> std::optional> + fx::gltf::Document const &gltf) + -> std::optional> { auto const &attribute_accessor = gltf.accessors.at(attribute_id); @@ -193,7 +194,8 @@ auto load_gltf_primitive(fx::gltf::Primitive const &gltf_primitive, continue; } - attributes.emplace(vertex_attribute.value().first, std::move(vertex_attribute.value().second)); + attributes.emplace(vertex_attribute.value().first, + std::move(vertex_attribute.value().second)); } // Load indices @@ -328,13 +330,17 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul } // Resolve child hierarchy - for (auto const &gltf_node : gltf.nodes) { + // TODO WRONG!!! does only work for 1 child generation + for (std::size_t i = 0; i < gltf.nodes.size(); ++i) { + auto const &gltf_node = gltf.nodes.at(i); std::vector> children; for (int child_node_id : gltf_node.children) { auto child_node = nodes_map.extract(child_node_id); children.push_back(child_node.mapped()); } - } + auto const &node = nodes_map.at(i); + node->children = std::move(children); + }; std::vector> nodes; nodes.reserve(nodes_map.size()); diff --git a/src/relationship.h b/src/relationship.h new file mode 100644 index 0000000..e56190f --- /dev/null +++ b/src/relationship.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +struct Parent +{ + entt::entity parent; +}; + +struct Children +{ + std::vector children; +}; diff --git a/src/transform.h b/src/transform.h index 85ba841..626ffc5 100644 --- a/src/transform.h +++ b/src/transform.h @@ -10,4 +10,25 @@ struct Transform glm::vec3 scale{1.0, 1.0, 1.0}; }; -using GlobalTransform = Transform; +struct GlobalTransform +{ + GlobalTransform() = default; + GlobalTransform(Transform const &transform) + { + // Translate * Rotate * Scale * vertex_vec; + // First scaling, then rotation, then translation + + // Translate + glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0F), transform.translation); + + // Rotate + glm::mat4 rotationMatrix = glm::toMat4(transform.rotation); + + // Scale + glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0F), transform.scale); + + this->transform = translationMatrix * rotationMatrix * scaleMatrix; + } + + glm::mat4 transform{}; +};