From 36646a099042188a4cbc434b0d79321ef5d048a3 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 7 Sep 2023 20:52:05 -0400 Subject: [PATCH] Optimization for Skeletal animations --- Nuake/src/Rendering/SceneRenderer.cpp | 7 ++-- Nuake/src/Rendering/Shaders/Shader.cpp | 2 +- Nuake/src/Resource/SkeletalAnimation.h | 32 ++++++++++++++++++ Nuake/src/Resource/SkeletonNode.h | 1 + Nuake/src/Scene/Scene.cpp | 20 ++++++++--- Nuake/src/Scene/Scene.h | 3 +- Nuake/src/Scene/Systems/AnimationSystem.cpp | 37 ++++++++++++--------- 7 files changed, 75 insertions(+), 27 deletions(-) diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 56bf2269..8f74a7ca 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -387,7 +387,7 @@ namespace Nuake // Skinned Models const uint32_t entityIdUniformLocation = gBufferSkinnedMeshShader->FindUniformLocation("u_EntityID"); const uint32_t modelMatrixUniformLocation = gBufferSkinnedMeshShader->FindUniformLocation("u_Model"); - + gBufferSkinnedMeshShader->SetUniformMat4f(modelMatrixUniformLocation, Matrix4(1.0f)); auto skinnedModelView = scene.m_Registry.view(); for (auto e : skinnedModelView) { @@ -404,7 +404,6 @@ namespace Nuake { m->GetMaterial()->Bind(gBufferSkinnedMeshShader); - gBufferSkinnedMeshShader->SetUniformMat4f(modelMatrixUniformLocation, Matrix4(1.0f)); gBufferSkinnedMeshShader->SetUniform1i(entityIdUniformLocation, (uint32_t)e + 1); m->Draw(gBufferSkinnedMeshShader, true); } @@ -482,10 +481,8 @@ namespace Nuake { if (auto entity = scene->GetEntity(child.Name); entity.GetHandle() != -1) { - const Matrix4& globalBoneTransform = entity.GetComponent().GetGlobalTransform(); - const Matrix4 bonespaceTransform = globalBoneTransform * child.Offset; const std::string boneMatrixUniformName = "u_FinalBonesMatrice[" + std::to_string(child.Id) + "]"; - shader->SetUniformMat4f(boneMatrixUniformName, bonespaceTransform); + shader->SetUniformMat4f(boneMatrixUniformName, child.FinalTransform); } SetSkeletonBoneTransformRecursive(child, shader); diff --git a/Nuake/src/Rendering/Shaders/Shader.cpp b/Nuake/src/Rendering/Shaders/Shader.cpp index 17a7fa2d..63e392cf 100644 --- a/Nuake/src/Rendering/Shaders/Shader.cpp +++ b/Nuake/src/Rendering/Shaders/Shader.cpp @@ -295,7 +295,7 @@ namespace Nuake if (addr != -1) { - SetUniformMat4f(addr, std::move(mat)); + SetUniformMat4f(addr, mat); } } diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index 5e649bd9..15824a9f 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -26,24 +26,35 @@ namespace Nuake std::vector m_Rotations = {}; std::vector m_Scales = {}; + Matrix4 m_PositionTransform; + Matrix4 m_RotationTransform; + Matrix4 m_ScaleTransform; + Matrix4 m_FinalTransform; + + bool m_IsEmpty = true; public: BoneTransformTrack(); ~BoneTransformTrack() = default; + bool IsEmpty() const { return m_IsEmpty; } + void PushPositionKeyframe(float timestamp, const Vector3& position) { + m_IsEmpty = false; m_PositionTimestamps.push_back(timestamp); m_Positions.push_back(position); } void PushRotationKeyframe(float timestamp, const Quat& rotation) { + m_IsEmpty = false; m_RotationTimestamps.push_back(timestamp); m_Rotations.push_back(rotation); } void PushScaleKeyframe(float timestamp, const Vector3& scale) { + m_IsEmpty = false; m_ScaleTimestamps.push_back(timestamp); m_Scales.push_back(scale); } @@ -65,6 +76,27 @@ namespace Nuake assert(0); } + void Update(float time) + { + const Matrix4 previousPos = m_PositionTransform; + const Matrix4 previousRot = m_RotationTransform; + const Matrix4 previousSca = m_ScaleTransform; + m_PositionTransform = InterpolatePosition(time); + m_RotationTransform = InterpolateRotation(time); + m_ScaleTransform = InterpolateScale(time); + + bool hasChanged = previousPos != m_PositionTransform || previousRot != m_RotationTransform || previousSca != m_ScaleTransform; + if (hasChanged) + { + m_FinalTransform = m_PositionTransform * m_RotationTransform * m_ScaleTransform; + } + } + + const Matrix4& GetFinalTransform() const + { + return m_FinalTransform; + } + /* Gets the current index on mKeyRotations to interpolate to based on the current animation time*/ int GetRotationIndex(float animationTime) diff --git a/Nuake/src/Resource/SkeletonNode.h b/Nuake/src/Resource/SkeletonNode.h index 90bc5fa2..3cd7e5e9 100644 --- a/Nuake/src/Resource/SkeletonNode.h +++ b/Nuake/src/Resource/SkeletonNode.h @@ -11,6 +11,7 @@ namespace Nuake std::string Name; int ChildrenCount; std::vector Children; + Matrix4 FinalTransform = Matrix4(1.0f); int32_t Id = -1; }; } \ No newline at end of file diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index b94d9973..8ba2d6ec 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -194,14 +194,20 @@ namespace Nuake Entity Scene::GetEntity(const std::string& name) { - std::vector allEntities; - const auto& view = m_Registry.view(); + if (m_EntitiesNameMap.find(name) != m_EntitiesNameMap.end()) + { + return m_EntitiesNameMap[name]; + } + + const auto& view = m_Registry.view(); for (auto e : view) { - const auto& namec = view.get(e); + const auto& [namec] = view.get(e); if (namec.Name == name) { - return Entity{ e, this }; + auto entity = Entity{ e, this }; + m_EntitiesNameMap[name] = entity; + return entity; } } @@ -260,6 +266,7 @@ namespace Nuake nameComponent.ID = id; m_EntitiesIDMap[id] = entity; + m_EntitiesNameMap[entityName] = entity; Logger::Log("Entity created with name: " + nameComponent.Name, "scene", LOG_TYPE::VERBOSE); return entity; @@ -288,6 +295,11 @@ namespace Nuake m_EntitiesIDMap.erase(entity.GetComponent().ID); } + if (m_EntitiesNameMap.find(entity.GetComponent().Name) != m_EntitiesNameMap.end()) + { + m_EntitiesNameMap.erase(entity.GetComponent().Name); + } + entity.Destroy(); m_Registry.shrink_to_fit(); } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index 1053ccc4..cd9afff6 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -38,7 +38,8 @@ namespace Nuake public: Ref m_EditorCamera; entt::registry m_Registry; - std::map m_EntitiesIDMap; + std::unordered_map m_EntitiesIDMap; + std::unordered_map m_EntitiesNameMap; std::string Path = ""; SceneRenderer* m_SceneRenderer; diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index 675e92f3..a3a54f18 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -3,6 +3,8 @@ #include "src/Scene/Scene.h" #include "src/Scene/Entities/Entity.h" #include "src/Scene/Components/SkinnedModelComponent.h" +#include +#include namespace Nuake { @@ -45,37 +47,40 @@ namespace Nuake { const std::string& boneName = bone.Name; + auto& animationTrack = animation->GetTrack(boneName); Entity& boneEntity = m_Scene->GetEntity(boneName); if (boneEntity.GetHandle() != -1) { - auto& animationTrack = animation->GetTrack(boneName); auto& transformComponent = boneEntity.GetComponent(); + bone.FinalTransform = transformComponent.GetGlobalTransform() * bone.Offset; - // Get Update transform - const Matrix4 newPosition = animationTrack.InterpolatePosition(time); - const Matrix4 newRotation = animationTrack.InterpolateRotation(time); - const Matrix4 newScale = animationTrack.InterpolateScale(time); - const Matrix4 finalTransform = newPosition * newRotation * newScale; + if (!animationTrack.IsEmpty()) + { + // Get Update transform + animationTrack.Update(time); - Vector3 localPosition; - Quat localRotation; - Vector3 localScale; - Decompose(finalTransform, localPosition, localRotation, localScale); + const Matrix4& finalTransform = animationTrack.GetFinalTransform(); - transformComponent.SetLocalPosition(localPosition); - transformComponent.SetLocalRotation(localRotation); - transformComponent.SetLocalScale(localScale); - transformComponent.SetLocalTransform(finalTransform); - transformComponent.Dirty = false; + Vector3 localPosition; + Quat localRotation; + Vector3 localScale; + Decompose(finalTransform, localPosition, localRotation, localScale); + + transformComponent.SetLocalPosition(localPosition); + transformComponent.SetLocalRotation(localRotation); + transformComponent.SetLocalScale(localScale); + transformComponent.SetLocalTransform(finalTransform); + transformComponent.Dirty = false; + } } - for (auto& childBone : bone.Children) { UpdateBonePositionTraversal(childBone, animation, time); } } + void AnimationSystem::FixedUpdate(Timestep ts) {