Implement hierarchical relationships between entities

This commit is contained in:
2022-10-20 22:10:20 +02:00
parent 2cb49c1b9c
commit 0c18186f63
4 changed files with 118 additions and 33 deletions

View File

@@ -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<Name>(top_level_entity, node->name);
m_registry.emplace<Transform>(top_level_entity, node->transform);
std::function<entt::entity(GltfNode const &, std::optional<entt::entity>)> spawn_node =
[this, &spawn_node](GltfNode const &node, std::optional<entt::entity> parent) {
auto entity = m_registry.create();
m_registry.emplace<Name>(entity, node.name);
m_registry.emplace<Transform>(entity, node.transform);
m_registry.emplace<GlobalTransform>(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<Transform>(mesh_entity, Transform{});
m_registry.emplace<entt::resource<Mesh>>(mesh_entity, primitive.mesh);
m_registry.emplace<entt::resource<Material>>(mesh_entity, primitive.material);
}
}
if (parent.has_value()) {
m_registry.emplace<Parent>(entity, Parent{.parent = parent.value()});
}
std::vector<entt::entity> 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<Parent>(mesh_entity, Parent{.parent = entity});
m_registry.emplace<Transform>(mesh_entity, Transform{});
m_registry.emplace<GlobalTransform>(mesh_entity, GlobalTransform{});
m_registry.emplace<entt::resource<Mesh>>(mesh_entity, primitive.mesh);
m_registry.emplace<entt::resource<Material>>(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<Children>(entity, Children{.children = child_entities});
return entity;
};
spawn_node(node, {});
}
auto name_view = m_registry.view<Name>();
@@ -64,27 +91,45 @@ void Scene::update(std::chrono::duration<float> delta,
glm::mat4 viewProjMatrix,
glm::vec3 viewPosition)
{
auto mesh_view = m_registry.view<GpuMesh, Transform>();
// Update GlobalTransform components
// TODO: Only do this when the Transform changed.
auto root_transform_view =
m_registry.view<Transform const, GlobalTransform>(entt::exclude<Parent>);
auto transform_view = m_registry.view<Transform const, GlobalTransform, Parent const>();
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<Children>(entity)) {
for (auto child : children->children) {
std::function<void(entt::entity entity, GlobalTransform parent_global_transform)>
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<Children>(entity)) {
for (auto child : children->children) {
transform_propagate(child, global_transform);
}
}
};
transform_propagate(child, parent_global_transform);
}
}
}
auto mesh_view = m_registry.view<GpuMesh, GlobalTransform>();
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);

View File

@@ -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<std::pair<std::size_t,VertexAttributeData>>
fx::gltf::Document const &gltf)
-> std::optional<std::pair<std::size_t, VertexAttributeData>>
{
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<entt::resource<GltfNode>> 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<entt::resource<GltfNode>> nodes;
nodes.reserve(nodes_map.size());

13
src/relationship.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <entt/entt.hpp>
struct Parent
{
entt::entity parent;
};
struct Children
{
std::vector<entt::entity> children;
};

View File

@@ -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{};
};