From cddb7caf02384fae6616371bbfdf2e8c0488c3a7 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 31 Aug 2023 10:40:27 -0400 Subject: [PATCH 01/25] Rounded file browser icons --- Editor/src/Windows/FileSystemUI.cpp | 8 +++++--- Nuake/src/Window.cpp | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Editor/src/Windows/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp index ba74e00e..3593cbf3 100644 --- a/Editor/src/Windows/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -62,13 +62,14 @@ namespace Nuake void FileSystemUI::DrawDirectory(Ref directory, uint32_t drawId) { ImGui::PushFont(FontManager::GetFont(Icons)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); const char* icon = ICON_FA_FOLDER; const std::string id = ICON_FA_FOLDER + std::string("##") + directory->name; if (ImGui::Button(id.c_str(), ImVec2(100, 100))) { m_CurrentDirectory = directory; } - + ImGui::PopStyleVar(); const std::string hoverMenuId = std::string("item_hover_menu") + std::to_string(drawId); if (ImGui::IsItemHovered() && ImGui::IsMouseReleased(1)) { @@ -188,6 +189,7 @@ namespace Nuake void FileSystemUI::DrawFile(Ref file, uint32_t drawId) { ImGui::PushFont(EditorInterface::bigIconFont); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); std::string fileExtension = file->GetExtension(); if (fileExtension == ".png" || fileExtension == ".jpg") { @@ -212,7 +214,7 @@ namespace Nuake Editor->Selection = EditorSelection(file); } } - + ImGui::PopStyleVar(); if (ImGui::BeginDragDropSource()) { char pathBuffer[256]; @@ -673,7 +675,7 @@ namespace Nuake { int width = avail.x; ImVec2 buttonSize = ImVec2(80, 80); - int amount = (int)(width / 100); + int amount = (int)(width / 110); if (amount <= 0) amount = 1; int i = 1; // current amount of item per row. diff --git a/Nuake/src/Window.cpp b/Nuake/src/Window.cpp index 5bc39d31..70ae8a97 100644 --- a/Nuake/src/Window.cpp +++ b/Nuake/src/Window.cpp @@ -286,6 +286,7 @@ namespace Nuake s.WindowBorderSize = 0.0f; s.IndentSpacing = 12.0f; s.ChildBorderSize = 0.0f; + s.PopupRounding = 4.0f; ImVec4* colors = ImGui::GetStyle().Colors; colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); From 29ba97454aa968d36615cc9e48e64581974aa669 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Tue, 5 Sep 2023 20:28:10 -0400 Subject: [PATCH 02/25] Added 2D gizmos and better editor styling --- Editor/resources/Shaders/flat.shader | 2 +- Editor/resources/Shaders/gizmo.shader | 12 +-- Editor/src/Misc/GizmoDrawer.cpp | 88 +++++++++++++++++---- Editor/src/Windows/EditorInterface.cpp | 70 ++++++++++------ Editor/src/Windows/EditorInterface.h | 3 + Editor/src/Windows/EditorSelectionPanel.cpp | 4 + Editor/src/Windows/EditorSelectionPanel.h | 3 +- Editor/src/Windows/FileSystemUI.cpp | 2 +- Nuake/src/Rendering/SceneRenderer.cpp | 4 +- Nuake/src/Scene/Entities/Entity.h | 9 ++- Nuake/src/Window.cpp | 6 +- 11 files changed, 150 insertions(+), 53 deletions(-) diff --git a/Editor/resources/Shaders/flat.shader b/Editor/resources/Shaders/flat.shader index c191336d..8f6cb3d8 100644 --- a/Editor/resources/Shaders/flat.shader +++ b/Editor/resources/Shaders/flat.shader @@ -41,5 +41,5 @@ void main() vec3 diffuse = diff * lightDiffuse; scolor = scolor * diffuse; - FragColor = vec4(scolor, 1.0); + FragColor = vec4(u_Color.rgb, 1.0); } \ No newline at end of file diff --git a/Editor/resources/Shaders/gizmo.shader b/Editor/resources/Shaders/gizmo.shader index db6cb6ef..2d4bb2ea 100644 --- a/Editor/resources/Shaders/gizmo.shader +++ b/Editor/resources/Shaders/gizmo.shader @@ -1,18 +1,19 @@ #shader vertex #version 460 core layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; layout(location = 1) in vec2 UV; -uniform mat4 model; -uniform mat4 view; -uniform mat4 projection; +uniform mat4 u_Model; +uniform mat4 u_View; +uniform mat4 u_Projection; out sample vec2 a_UV; void main() { a_UV = UV; - gl_Position = projection * view * model * vec4(Position, 1.0); + gl_Position = u_Projection * u_View * u_Model * vec4(Position, 1.0); } #shader fragment @@ -27,5 +28,6 @@ uniform sampler2D gizmo_texture; void main() { vec4 px_color = texture(gizmo_texture, a_UV).rgba; - FragColor = px_color; + FragColor = px_color * vec4(1, 1, 1, 0.5); + } \ No newline at end of file diff --git a/Editor/src/Misc/GizmoDrawer.cpp b/Editor/src/Misc/GizmoDrawer.cpp index 66f993a9..48268b8e 100644 --- a/Editor/src/Misc/GizmoDrawer.cpp +++ b/Editor/src/Misc/GizmoDrawer.cpp @@ -9,6 +9,7 @@ #include #include +#include #include @@ -17,7 +18,7 @@ #include #include #include - +#include GizmoDrawer::GizmoDrawer() { @@ -275,44 +276,99 @@ void GizmoDrawer::DrawGizmos(Ref scene) glLineWidth(1.0f); RenderList renderList; + auto gizmoShader = ShaderManager::GetShader("resources/Shaders/gizmo.shader"); + gizmoShader->Bind(); + gizmoShader->SetUniformMat4f("u_View", scene->m_EditorCamera->GetTransform()); + gizmoShader->SetUniformMat4f("u_Projection", scene->m_EditorCamera->GetPerspective()); + + RenderCommand::Disable(RendererEnum::FACE_CULL); + // Camera auto camView = scene->m_Registry.view(); for (auto e : camView) { - auto [transform, cam] = scene->m_Registry.get(e); + gizmoShader->SetUniformTex("gizmo_texture", TextureManager::Get()->GetTexture("resources/Gizmos/camera.png").get()); + auto [transform, camera] = scene->m_Registry.get(e); - renderList.AddToRenderList(_gizmos["cam"]->GetMeshes()[0], transform.GetGlobalTransform()); + auto initialTransform = transform.GetGlobalTransform(); + Matrix4 particleTransform = initialTransform; + particleTransform = glm::inverse(scene->m_EditorCamera->GetTransform()); + + // Translation + const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); + particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + + particleTransform = glm::scale(particleTransform, Vector3(0.5, 0.5, 0.5)); + + renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); } - renderList.Flush(flatShader, true); + renderList.Flush(gizmoShader, true); // Lights auto lightView = scene->m_Registry.view(); for (auto e : lightView) { + gizmoShader->SetUniformTex("gizmo_texture", TextureManager::Get()->GetTexture("resources/Gizmos/light.png").get()); auto [transform, light] = scene->m_Registry.get(e); - flatShader->SetUniformVec4("u_Color", Vector4(light.Color, 1.0f)); - renderList.AddToRenderList(_gizmos["light"]->GetMeshes()[0], transform.GetGlobalTransform()); - renderList.Flush(flatShader, true); - } - renderList.Flush(flatShader, true); + auto initialTransform = transform.GetGlobalTransform(); + Matrix4 particleTransform = initialTransform; + particleTransform = glm::inverse(scene->m_EditorCamera->GetTransform()); + // Translation + const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); + particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + + particleTransform = glm::scale(particleTransform, Vector3(0.5, 0.5, 0.5)); + + renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); + } + + renderList.Flush(gizmoShader, true); // Player auto characterControllerView = scene->m_Registry.view(); for (auto e : characterControllerView) { - auto [transformComponent, characterControllerComponent] = scene->m_Registry.get(e); + gizmoShader->SetUniformTex("gizmo_texture", TextureManager::Get()->GetTexture("resources/Gizmos/player.png").get()); + auto [transform, characterControllerComponent] = scene->m_Registry.get(e); - flatShader->SetUniformVec4("u_Color", Vector4(0.0f, 1.0f, 0.4f, 1.0f)); + auto initialTransform = transform.GetGlobalTransform(); + Matrix4 particleTransform = initialTransform; + particleTransform = glm::inverse(scene->m_EditorCamera->GetTransform()); - const auto scaledTransform = glm::scale(transformComponent.GetGlobalTransform(), Vector3(0.25f, 0.25f, 0.25f)); - renderList.AddToRenderList(_gizmos["player"]->GetMeshes()[0], scaledTransform); - renderList.Flush(flatShader, true); + // Translation + const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); + particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + + particleTransform = glm::scale(particleTransform, Vector3(0.5, 0.5, 0.5)); + + renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); } - renderList.Flush(flatShader, true); + renderList.Flush(gizmoShader, true); - RenderCommand::Disable(RendererEnum::FACE_CULL); + // Bones + auto boneView = scene->m_Registry.view(); + for (auto e : boneView) + { + gizmoShader->SetUniformTex("gizmo_texture", TextureManager::Get()->GetTexture("resources/Gizmos/bone.png").get()); + auto [transform, boneComponent] = scene->m_Registry.get(e); + + auto initialTransform = transform.GetGlobalTransform(); + Matrix4 particleTransform = initialTransform; + particleTransform = glm::inverse(scene->m_EditorCamera->GetTransform()); + + // Translation + const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); + particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + + particleTransform = glm::scale(particleTransform, Vector3(0.25, 0.25, 0.25)); + + renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); + } + + renderList.Flush(gizmoShader, true); + RenderCommand::Enable(RendererEnum::DEPTH_TEST); } \ No newline at end of file diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index d6acdcb4..67f42993 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -289,7 +289,9 @@ namespace Nuake { Entity QueueDeletion; void EditorInterface::DrawEntityTree(Entity e) { - ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{ 0.0f, 0.0f }); + + ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanFullWidth; NameComponent& nameComponent = e.GetComponent(); std::string name = nameComponent.Name; @@ -298,8 +300,6 @@ namespace Nuake { if (Selection.Type == EditorSelectionType::Entity && Selection.Entity == e) base_flags |= ImGuiTreeNodeFlags_Selected; - - ImGui::TableNextColumn(); // Write in normal font. @@ -315,10 +315,8 @@ namespace Nuake { { ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(0, 255, 0, 255)); } - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 8)); + bool open = ImGui::TreeNodeEx(name.c_str(), base_flags); - ImGui::PopStyleVar(); if(nameComponent.IsPrefab && e.HasComponent()) ImGui::PopStyleColor(); @@ -414,21 +412,20 @@ namespace Nuake { ImGui::TableNextColumn(); - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{ 0.0f, 0.0f }); + ImGui::TextColored(ImVec4(0.5, 0.5, 0.5, 1.0), GetEntityTypeName(e).c_str()); + + ImGui::TableNextColumn(); { bool& isVisible = e.GetComponent().Visible; char* visibilityIcon = isVisible ? ICON_FA_EYE : ICON_FA_EYE_SLASH; - ImGui::PushStyleColor(ImGuiCol_Button, { 0, 0, 0, 0 }); - if (ImGui::Button(visibilityIcon, { 40, 36 })) + if (ImGui::Button(visibilityIcon, { 40, 0 })) { isVisible = !isVisible; } ImGui::PopStyleColor(); } - - ImGui::PopStyleVar(); - + if (open) { // Caching list to prevent deletion while iterating. @@ -438,7 +435,8 @@ namespace Nuake { ImGui::TreePop(); } - + + ImGui::PopStyleVar(); ImGui::PopFont(); } @@ -1017,6 +1015,7 @@ namespace Nuake { std::string title = ICON_FA_TREE + std::string(" Hierarchy"); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 0)); if (ImGui::Begin(title.c_str())) { // Buttons to add and remove entity. @@ -1038,16 +1037,18 @@ namespace Nuake { ImGui::EndChild(); // Draw a tree of entities. ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(26.f / 255.0f, 26.f / 255.0f, 26.f / 255.0f, 1)); + if (ImGui::BeginChild("Scene tree", ImGui::GetContentRegionAvail(), false)) { - if (ImGui::BeginTable("entity_table", 2, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_SizingStretchProp)) + if (ImGui::BeginTable("entity_table", 3, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingStretchProp)) { - ImGui::TableSetupColumn(" Label", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentEnable); - std::string icon = ICON_FA_EYE; - ImGui::TableSetupColumn((" " + icon).c_str(), ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed, 32); + ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_IndentEnable); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_IndentEnable); + ImGui::TableSetupColumn("Visibility", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed); ImGui::TableHeadersRow(); ImGui::TableNextRow(); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0)); std::vector entities = scene->GetAllEntities(); for (Entity e : entities) { @@ -1060,16 +1061,11 @@ namespace Nuake { // Write in normal font. ImGui::PushFont(normalFont); - // Small icons + name. - std::string label = ICON_FA_CIRCLE + std::string(" ") + name; - // Draw all entity without parents. if (!e.GetComponent().HasParent) { - ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2{ 0.0f, 0.0f }); // Recursively draw childrens. DrawEntityTree(e); - ImGui::PopStyleVar(); } // Pop font. @@ -1079,6 +1075,7 @@ namespace Nuake { //if (ImGui::BeginPopupContextItem()) // ImGui::EndPopup(); } + ImGui::PopStyleVar(); } ImGui::EndTable(); @@ -1110,9 +1107,9 @@ namespace Nuake { QueueDeletion = Entity{ (entt::entity)-1, scene.get() }; } } - ImGui::End(); ImGui::PopStyleVar(); + ImGui::PopStyleVar(); } bool EditorInterface::EntityContainsItself(Entity source, Entity target) @@ -1632,4 +1629,31 @@ namespace Nuake { ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.5f, 0.5f)); FontManager::LoadFonts(); } + + std::string EditorInterface::GetEntityTypeName(const Entity& entity) const + { + std::string entityTypeName = ""; + + if (entity.HasComponent()) + { + entityTypeName = "Light"; + } + + if (entity.HasComponent()) + { + entityTypeName = "Rigidbody"; + } + + if (entity.HasComponent()) + { + entityTypeName = "Character Controller"; + } + + if (entity.HasComponent()) + { + entityTypeName = "Prefab"; + } + + return entityTypeName; + } } diff --git a/Editor/src/Windows/EditorInterface.h b/Editor/src/Windows/EditorInterface.h index f71a9f8c..46b1dacb 100644 --- a/Editor/src/Windows/EditorInterface.h +++ b/Editor/src/Windows/EditorInterface.h @@ -61,5 +61,8 @@ namespace Nuake bool ShouldDrawAxis() const { return m_DrawAxis; } bool ShouldDrawCollision() const { return m_DebugCollisions; } + + private: + std::string GetEntityTypeName(const Entity& entity) const; }; } diff --git a/Editor/src/Windows/EditorSelectionPanel.cpp b/Editor/src/Windows/EditorSelectionPanel.cpp index bb77a732..addbb26a 100644 --- a/Editor/src/Windows/EditorSelectionPanel.cpp +++ b/Editor/src/Windows/EditorSelectionPanel.cpp @@ -104,6 +104,7 @@ void EditorSelectionPanel::DrawEntity(Nuake::Entity entity) mSpritePanel.Draw(entity); mMeshPanel.Draw(entity); mSkinnedModelPanel.Draw(entity); + mBonePanel.Draw(entity); mQuakeMapPanel.Draw(entity); mCameraPanel.Draw(entity); mRigidbodyPanel.Draw(entity); @@ -131,8 +132,11 @@ void EditorSelectionPanel::DrawAddComponentMenu(Nuake::Entity entity) MenuItemComponent("Wren Script", Nuake::WrenScriptComponent) MenuItemComponent("Camera", Nuake::CameraComponent) MenuItemComponent("Light", Nuake::LightComponent) + ImGui::Separator(); MenuItemComponent("Model", Nuake::ModelComponent) MenuItemComponent("Skinned Model", Nuake::SkinnedModelComponent) + MenuItemComponent("Bone", Nuake::BoneComponent) + ImGui::Separator(); MenuItemComponent("Sprite", Nuake::SpriteComponent) MenuItemComponent("Particle Emitter", Nuake::ParticleEmitterComponent) ImGui::Separator(); diff --git a/Editor/src/Windows/EditorSelectionPanel.h b/Editor/src/Windows/EditorSelectionPanel.h index 03f71bc2..1e608200 100644 --- a/Editor/src/Windows/EditorSelectionPanel.h +++ b/Editor/src/Windows/EditorSelectionPanel.h @@ -21,7 +21,7 @@ #include "../ComponentsPanel/SpritePanel.h" #include "../ComponentsPanel/ParticleEmitterPanel.h" #include "../ComponentsPanel/SkinnedModelPanel.h" - +#include "../ComponentsPanel/BonePanel.h" class EditorSelectionPanel { @@ -42,6 +42,7 @@ private: SpritePanel mSpritePanel; CharacterControllerPanel mCharacterControllerPanel; ParticleEmitterPanel mParticleEmitterPanel; + BonePanel mBonePanel; Ref currentFile; Ref selectedResource; diff --git a/Editor/src/Windows/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp index 3593cbf3..5b6a9a48 100644 --- a/Editor/src/Windows/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -228,7 +228,7 @@ namespace Nuake { dragType = "_Map"; } - else if (fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx") + else if (fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx" || fileExtension == ".glb") { dragType = "_Model"; } diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 87f61caa..03cf1ea3 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -117,8 +117,6 @@ namespace Nuake finalOutput = framebuffer.GetTexture(); - - // Copy final output to target framebuffer mToneMapBuffer->QueueResize(framebuffer.GetSize()); mToneMapBuffer->Bind(); @@ -170,7 +168,9 @@ namespace Nuake { auto [lightTransform, light, visibility] = view.get(l); if (light.Type != LightType::Directional || !light.CastShadows || !visibility.Visible) + { continue; + } light.CalculateViewProjection(mView, mProjection); diff --git a/Nuake/src/Scene/Entities/Entity.h b/Nuake/src/Scene/Entities/Entity.h index f51a0837..461b84ed 100644 --- a/Nuake/src/Scene/Entities/Entity.h +++ b/Nuake/src/Scene/Entities/Entity.h @@ -18,7 +18,7 @@ namespace Nuake void AddChild(Entity ent); int GetHandle() const { return (int)m_EntityHandle; } - int GetID() { return GetComponent().ID; } + int GetID() const { return GetComponent().ID; } template bool HasComponent() const @@ -51,6 +51,13 @@ namespace Nuake return component; } + template + T GetComponent() const + { + T component = m_Scene->m_Registry.get(m_EntityHandle); + return component; + } + void Destroy() { m_Scene->m_Registry.destroy(m_EntityHandle); diff --git a/Nuake/src/Window.cpp b/Nuake/src/Window.cpp index 70ae8a97..07af332e 100644 --- a/Nuake/src/Window.cpp +++ b/Nuake/src/Window.cpp @@ -67,7 +67,7 @@ namespace Nuake SetWindowIcon("resources/Images/nuake-logo.png"); glfwMakeContextCurrent(m_Window); - SetVSync(true); + SetVSync(false); Logger::Log("Driver detected " + std::string(((char*)glGetString(GL_VERSION))), "renderer"); @@ -267,7 +267,6 @@ namespace Nuake ImGuiStyle& s = ImGui::GetStyle(); s.WindowMenuButtonPosition = ImGuiDir_None; - s.FrameRounding = 2.0f; s.GrabRounding = 2.0f; s.CellPadding = ImVec2(8, 8); s.WindowPadding = ImVec2(2, 2); @@ -277,7 +276,7 @@ namespace Nuake s.TabRounding = 0; s.WindowRounding = 0; s.ChildRounding = 0; - s.FrameRounding = 0; + s.FrameRounding = 4.0f; s.GrabRounding = 0; s.FramePadding = ImVec2(8, 4); s.ItemSpacing = ImVec2(8, 4); @@ -287,6 +286,7 @@ namespace Nuake s.IndentSpacing = 12.0f; s.ChildBorderSize = 0.0f; s.PopupRounding = 4.0f; + s.FrameBorderSize = 1.0f; ImVec4* colors = ImGui::GetStyle().Colors; colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); From 33e04e92168246a24a111ca8e76d47fd4aeb14a4 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Tue, 5 Sep 2023 20:28:18 -0400 Subject: [PATCH 03/25] Smoother physics --- Nuake/src/Scene/Systems/PhysicsSystem.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/Nuake/src/Scene/Systems/PhysicsSystem.cpp b/Nuake/src/Scene/Systems/PhysicsSystem.cpp index e324500b..dba4dcf4 100644 --- a/Nuake/src/Scene/Systems/PhysicsSystem.cpp +++ b/Nuake/src/Scene/Systems/PhysicsSystem.cpp @@ -32,19 +32,6 @@ namespace Nuake InitializeCharacterControllers(); InitializeQuakeMap(); - // TODO: Triggers - - //auto bspTriggerView = m_Scene->m_Registry.view(); - //for (auto e : bspTriggerView) - //{ - // auto [transform, brush, trigger] = bspTriggerView.get(e); - - // Ref meshShape = CreateRef(brush.Meshes[0]); - // Ref ghostBody = CreateRef(transform.GetGlobalPosition(), meshShape); - // trigger.GhostObject = ghostBody; - - // PhysicsManager::Get()->RegisterGhostBody(ghostBody); - //} Logger::Log("Physic system initialized successfully"); return true; } @@ -56,6 +43,10 @@ namespace Nuake return; } + ApplyForces(); + + PhysicsManager::Get().Step(ts); + auto brushes = m_Scene->m_Registry.view(); for (auto e : brushes) { @@ -121,9 +112,7 @@ namespace Nuake return; InitializeRigidbodies(); - ApplyForces(); - - PhysicsManager::Get().Step(ts); + } void PhysicsSystem::Exit() From e125bf5fdba0d3e57c2bf41a3da041505a1e63d9 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Tue, 5 Sep 2023 20:28:33 -0400 Subject: [PATCH 04/25] Added skeleton creation --- Editor/src/ComponentsPanel/BonePanel.h | 36 ++++++++++++++++ .../src/ComponentsPanel/SkinnedModelPanel.h | 41 ++++++++++++++++--- Nuake/src/Scene/Components/BoneComponent.cpp | 8 ++++ Nuake/src/Scene/Components/BoneComponent.h | 15 +++++++ Nuake/src/Scene/Scene.cpp | 28 +++++++++++++ Nuake/src/Scene/Scene.h | 3 ++ 6 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 Editor/src/ComponentsPanel/BonePanel.h create mode 100644 Nuake/src/Scene/Components/BoneComponent.cpp create mode 100644 Nuake/src/Scene/Components/BoneComponent.h diff --git a/Editor/src/ComponentsPanel/BonePanel.h b/Editor/src/ComponentsPanel/BonePanel.h new file mode 100644 index 00000000..cd80a554 --- /dev/null +++ b/Editor/src/ComponentsPanel/BonePanel.h @@ -0,0 +1,36 @@ +#pragma once +#include "ComponentPanel.h" + +#include +#include +#include +#include + +class BonePanel : ComponentPanel +{ +public: + BonePanel() {} + + void Draw(Nuake::Entity entity) override + { + using namespace Nuake; + + if (!entity.HasComponent()) + return; + + auto& component = entity.GetComponent(); + BeginComponentTable(BONE, BoneComponent); + { + { + ImGui::Text("Name"); + ImGui::TableNextColumn(); + + ImGui::InputText("##BoneName", &component.Name); + ImGui::TableNextColumn(); + + ComponentTableReset(component.Name, ""); + } + } + EndComponentTable(); + } +}; \ No newline at end of file diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h index 9bebded1..66d9b3da 100644 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ b/Editor/src/ComponentsPanel/SkinnedModelPanel.h @@ -12,8 +12,9 @@ class SkinnedModelPanel : ComponentPanel { private: - Scope _modelInspector; - bool _expanded = false; + Scope m_ModelInspector; + bool m_Expanded = false; + std::string m_QueuedModelPath; public: SkinnedModelPanel() @@ -45,9 +46,9 @@ public: { } - if (_expanded) + if (m_Expanded) { - _modelInspector->Draw(); + m_ModelInspector->Draw(); } if (ImGui::BeginDragDropTarget()) @@ -64,13 +65,41 @@ public: } else { - component.ModelPath = fullPath; - component.LoadModel(); + m_QueuedModelPath = fullPath; + ImGui::OpenPopup("Create Skeleton"); } } ImGui::EndDragDropTarget(); } + if (ImGui::BeginPopupModal("Create Skeleton", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + ImGui::SetItemDefaultFocus(); + ImGui::Text("Would you like to create the skeleton structure in the scene tree?"); + ImGui::Separator(); + + if (ImGui::Button("OK", ImVec2(120, 0))) + { + component.ModelPath = m_QueuedModelPath; + component.LoadModel(); + + Scene* scene = entity.GetScene(); + scene->CreateSkeleton(entity); + + ImGui::CloseCurrentPopup(); + } + + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + + if (ImGui::Button("Cancel", ImVec2(120, 0))) + { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + ImGui::TableNextColumn(); ComponentTableReset(component.ModelPath, ""); } diff --git a/Nuake/src/Scene/Components/BoneComponent.cpp b/Nuake/src/Scene/Components/BoneComponent.cpp new file mode 100644 index 00000000..d97d1a95 --- /dev/null +++ b/Nuake/src/Scene/Components/BoneComponent.cpp @@ -0,0 +1,8 @@ +#include "src/Core/Core.h" + +#include "BoneComponent.h" + +namespace Nuake +{ + +} \ No newline at end of file diff --git a/Nuake/src/Scene/Components/BoneComponent.h b/Nuake/src/Scene/Components/BoneComponent.h new file mode 100644 index 00000000..2bb08862 --- /dev/null +++ b/Nuake/src/Scene/Components/BoneComponent.h @@ -0,0 +1,15 @@ +#pragma once +#include "src/Core/Core.h" + + +namespace Nuake +{ + class BoneComponent + { + public: + BoneComponent() = default; + ~BoneComponent() = default; + + std::string Name; + }; +} \ No newline at end of file diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 58750a01..2a8d575c 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -24,6 +24,7 @@ #include "src/Scene/Components/WrenScriptComponent.h" #include "src/Scene/Components/BSPBrushComponent.h" #include "src/Scene/Components/InterfaceComponent.h" +#include "src/Scene/Components/SkinnedModelComponent.h" #include #include @@ -448,4 +449,31 @@ namespace Nuake return true; } + + void Scene::CreateSkeleton(Entity& entity) + { + // We cannot create a component if the entity doesn't have a skinned model + if (!entity.HasComponent()) + { + const std::string msg = "Cannot create a skeleton on entity: " + std::to_string(entity.GetID()); + Logger::Log(msg); + return; + } + + SkinnedModelComponent& component = entity.GetComponent(); + for (Ref& model : component.ModelResource->GetMeshes()) + { + auto& bones = model->GetBones(); + if (bones.size() > 0) + { + for (auto& bone : bones) + { + auto& parentComponent = entity.GetComponent(); + + Entity boneEntity = CreateEntity(bone.Name); + entity.AddChild(boneEntity); + } + } + } + } } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index 33e03ac2..2d2cf74b 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -89,5 +89,8 @@ namespace Nuake json Serialize() override; bool Deserialize(const json& j) override; + + // Component specific utilies + void CreateSkeleton(Entity& entity); }; } From 37f1186c797a175e7c6732823991c1cc144c5aae Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Tue, 5 Sep 2023 21:49:21 -0400 Subject: [PATCH 05/25] Added Bone label --- Editor/src/Windows/EditorInterface.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 67f42993..1175d027 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -1649,6 +1649,11 @@ namespace Nuake { entityTypeName = "Character Controller"; } + if (entity.HasComponent()) + { + entityTypeName = "Bone"; + } + if (entity.HasComponent()) { entityTypeName = "Prefab"; From 0e5d17da7520dcec603779e99b9a3b4abfbfb774 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Tue, 5 Sep 2023 21:49:40 -0400 Subject: [PATCH 06/25] Started animation parsing and resource --- Nuake/src/Rendering/Mesh/Animation.cpp | 10 +++++++ Nuake/src/Resource/ModelLoader.cpp | 39 ++++++++++++++++++++++++-- Nuake/src/Resource/ModelLoader.h | 2 ++ Nuake/src/Resource/SkeletalAnimation.h | 17 ++++++++--- Nuake/src/Resource/SkeletonNode.h | 14 +++++++++ Nuake/src/Resource/SkinnedModel.h | 8 ++++++ Nuake/src/Scene/Scene.cpp | 32 +++++++++++++++++---- Nuake/src/Scene/Scene.h | 1 + 8 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 Nuake/src/Rendering/Mesh/Animation.cpp create mode 100644 Nuake/src/Resource/SkeletonNode.h diff --git a/Nuake/src/Rendering/Mesh/Animation.cpp b/Nuake/src/Rendering/Mesh/Animation.cpp new file mode 100644 index 00000000..1bbab93e --- /dev/null +++ b/Nuake/src/Rendering/Mesh/Animation.cpp @@ -0,0 +1,10 @@ +#include + +namespace Nuake +{ + class Animation + { + Animation() = default; + + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index d7b26160..199b2b73 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -7,7 +7,7 @@ #include "src/Resource/SkinnedModel.h" #include "src/Resource/Model.h" - +#include "src/Resource/SkeletalAnimation.h" namespace Nuake { @@ -70,7 +70,7 @@ namespace Nuake if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { std::string assimpErrorMsg = std::string(importer.GetErrorString()); - std::string logMsg = "[Failed to load model] - " + assimpErrorMsg; + std::string logMsg = "Failed to load model: " + assimpErrorMsg; Logger::Log(logMsg, "model", WARNING); return model; @@ -78,6 +78,24 @@ namespace Nuake ProcessSkinnedNode(scene->mRootNode, scene); + if (scene->HasAnimations()) + { + SkeletalAnimation animation; + + for (uint32_t i = 0; i < scene->mNumAnimations; i++) + { + aiAnimation* aiAnim = scene->mAnimations[i]; + const float duration = aiAnim->mDuration; + const float ticksPerSecond = aiAnim->mTicksPerSecond; + + // Read data + SkeletonNode rootSkeletonNode; + ProcessAnimationNode(rootSkeletonNode, scene->mRootNode); + + model->SetSkeletonRootNode(rootSkeletonNode); + } + } + for (const auto& mesh : m_SkinnedMeshes) { model->AddMesh(mesh); @@ -177,7 +195,6 @@ namespace Nuake Ref mesh = CreateRef(); mesh->AddSurface(vertices, indices, bones); mesh->SetMaterial(material); - return mesh; } @@ -320,6 +337,22 @@ namespace Nuake } } + void ModelLoader::ProcessAnimationNode(SkeletonNode& dest, const aiNode* src) + { + assert(src); + + dest.Name = src->mName.data; + dest.Transform = ConvertMatrixToGLMFormat(src->mTransformation); + dest.ChildrenCount = src->mNumChildren; + + for (uint32_t i = 0; i < dest.ChildrenCount; i++) + { + SkeletonNode newNode; + ProcessAnimationNode(newNode, src->mChildren[i]); + dest.Children.push_back(std::move(newNode)); + } + } + std::vector ModelLoader::ProcessIndices(aiMesh* mesh) { auto indices = std::vector(); diff --git a/Nuake/src/Resource/ModelLoader.h b/Nuake/src/Resource/ModelLoader.h index 32340eb6..a0a8e092 100644 --- a/Nuake/src/Resource/ModelLoader.h +++ b/Nuake/src/Resource/ModelLoader.h @@ -7,6 +7,7 @@ #include "src/Rendering/Textures/Texture.h" #include "src/Rendering/Vertex.h" +#include "src/Resource/SkeletonNode.h" #include "assimp/Importer.hpp" #include @@ -46,6 +47,7 @@ namespace Nuake Ref ProcessSkinnedMesh(aiMesh* node, const aiScene* scene); std::vector ProcessSkinnedVertices(aiMesh* mesh); void SetVertexBoneData(SkinnedVertex& vertex, int boneId, float weight); + void ProcessAnimationNode(SkeletonNode& dest, const aiNode* src); static inline Matrix4 ConvertMatrixToGLMFormat(const aiMatrix4x4& from) { diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index af3109f8..668495be 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -3,16 +3,25 @@ namespace Nuake { - class Animation + struct SkeletonAnimationBoneAnimation + { + std::string Name; + Vector3 Positions; + Quat Rotations; + Vector3 Scalings; + }; + + class SkeletalAnimation { private: float m_Duration; int m_TicksPerSecond; + std::vector m_Bones; - //std::map m_BoneInfoMap; + public: - Animation() = default; - Animation(); + SkeletalAnimation() = default; + ~SkeletalAnimation() = default; Bone& FindBone(const std::string& boneName); diff --git a/Nuake/src/Resource/SkeletonNode.h b/Nuake/src/Resource/SkeletonNode.h new file mode 100644 index 00000000..7c8e2277 --- /dev/null +++ b/Nuake/src/Resource/SkeletonNode.h @@ -0,0 +1,14 @@ +#pragma once +#include "src/Core/Core.h" +#include "src/Core/Maths.h" + +namespace Nuake +{ + struct SkeletonNode + { + Matrix4 Transform; + std::string Name; + int ChildrenCount; + std::vector Children; + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/SkinnedModel.h b/Nuake/src/Resource/SkinnedModel.h index 96278d72..fa4cc819 100644 --- a/Nuake/src/Resource/SkinnedModel.h +++ b/Nuake/src/Resource/SkinnedModel.h @@ -3,6 +3,7 @@ #include "src/Rendering/Mesh/SkinnedMesh.h" #include "src/Resource/Resource.h" #include "src/Resource/Serializable.h" +#include "src/Resource/SkeletonNode.h" namespace Nuake @@ -12,11 +13,18 @@ namespace Nuake private: std::vector> m_Meshes; + SkeletonNode m_SkeletonRoot; + public: SkinnedModel(); SkinnedModel(const std::string path); ~SkinnedModel(); + void SetSkeletonRootNode(SkeletonNode& root) + { + m_SkeletonRoot = std::move(root); + } + void AddMesh(Ref mesh); std::vector>& GetMeshes(); diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 2a8d575c..e65b6ff3 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -31,6 +31,7 @@ #include #include #include "src/Core/OS.h" +#include "Components/BoneComponent.h" namespace Nuake { @@ -213,7 +214,7 @@ namespace Nuake std::string Scene::GetUniqueEntityName(const std::string& name) { std::string entityName; - if (GetEntity(name) == Entity()) + if (!EntityExists(name)) { return name; } @@ -289,6 +290,11 @@ namespace Nuake m_Registry.shrink_to_fit(); } + bool Scene::EntityExists(const std::string& name) + { + return GetEntity(name).GetHandle() != -1; + } + Ref Scene::GetCurrentCamera() { if (Engine::IsPlayMode()) @@ -463,17 +469,31 @@ namespace Nuake SkinnedModelComponent& component = entity.GetComponent(); for (Ref& model : component.ModelResource->GetMeshes()) { - auto& bones = model->GetBones(); - if (bones.size() > 0) + for (auto& bone : model->GetBones()) { - for (auto& bone : bones) - { - auto& parentComponent = entity.GetComponent(); + auto& parentComponent = entity.GetComponent(); + Logger::Log("bone found:" + bone.Name, "debug", VERBOSE); + if (EntityExists(bone.Name) == false) + { Entity boneEntity = CreateEntity(bone.Name); + boneEntity.AddComponent(); + + Vector3 position; + Quat rotation; + Vector3 scale; + Decompose(bone.Offset, position, rotation, scale); + + auto& transformComponent = entity.GetComponent(); + transformComponent.SetLocalPosition(position); + transformComponent.SetLocalRotation(rotation); + transformComponent.SetLocalScale(scale); + transformComponent.SetLocalTransform(bone.Offset); + entity.AddChild(boneEntity); } } } } + } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index 2d2cf74b..09a09128 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -65,6 +65,7 @@ namespace Nuake Entity CreateEntity(const std::string& name); Entity CreateEntity(const std::string& name, int id); void DestroyEntity(Entity entity); + bool EntityExists(const std::string& name); std::vector GetAllEntities(); Entity GetEntity(const std::string& name); From 422cddf5b0f6f77a83e1d454eab4103292215307 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 08:48:32 -0400 Subject: [PATCH 07/25] Added skeleton hierarchy --- Nuake/src/Rendering/Mesh/SkinnedMesh.cpp | 6 ++++ Nuake/src/Rendering/Mesh/SkinnedMesh.h | 6 ++++ Nuake/src/Resource/ModelLoader.cpp | 18 +++++++++- Nuake/src/Resource/ModelLoader.h | 1 + Nuake/src/Resource/SkeletalAnimation.h | 12 +++++++ Nuake/src/Resource/SkinnedModel.h | 1 + Nuake/src/Scene/Scene.cpp | 42 ++++++++++-------------- Nuake/src/Scene/Scene.h | 4 +++ 8 files changed, 64 insertions(+), 26 deletions(-) diff --git a/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp b/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp index 49db585a..daf6a61a 100644 --- a/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp +++ b/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp @@ -11,6 +11,7 @@ #include "src/Rendering/Buffers/VertexArray.h" #include "src/Rendering/Buffers/VertexBufferLayout.h" + #include namespace Nuake @@ -199,4 +200,9 @@ namespace Nuake SetupMesh(); return true; } + + void SkinnedMesh::SetSkeletalAnimation(Ref skeletalAnimation) + { + m_SkeletalAnimation = skeletalAnimation; + } } diff --git a/Nuake/src/Rendering/Mesh/SkinnedMesh.h b/Nuake/src/Rendering/Mesh/SkinnedMesh.h index 7c0a2017..9ce765bf 100644 --- a/Nuake/src/Rendering/Mesh/SkinnedMesh.h +++ b/Nuake/src/Rendering/Mesh/SkinnedMesh.h @@ -3,6 +3,7 @@ #include "src/Rendering/AABB.h" #include "src/Resource/Resource.h" #include "src/Resource/Serializable.h" +#include "src/Resource/SkeletalAnimation.h" #include "src/Rendering/Vertex.h" #include "src/Rendering/Mesh/Bone.h" @@ -39,7 +40,12 @@ namespace Nuake json Serialize() override; bool Deserialize(const json& j) override; + void SetSkeletalAnimation(Ref animation); + Ref GetSkeletalAnimation() const { return m_SkeletalAnimation; } + private: + Ref m_SkeletalAnimation; + Ref m_Material = nullptr; std::vector m_Indices; std::vector m_Vertices; diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index 199b2b73..157ac835 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -77,7 +77,6 @@ namespace Nuake } ProcessSkinnedNode(scene->mRootNode, scene); - if (scene->HasAnimations()) { SkeletalAnimation animation; @@ -353,6 +352,23 @@ namespace Nuake } } + void ModelLoader::ProcessSkeleton(SkeletonNode& des, const aiNode* src) + { + // Create a Bone object for this node + SkeletonNode bone; + bone.Name = src->mName.C_Str(); + bone.Transform = ConvertMatrixToGLMFormat(src->mTransformation); + + des.ChildrenCount++; + des.Children.push_back(bone); + + // Recursively process child nodes (bones) + for (uint32_t i = 0; i < src->mNumChildren; i++) + { + ProcessSkeleton(bone, src->mChildren[i]); + } + } + std::vector ModelLoader::ProcessIndices(aiMesh* mesh) { auto indices = std::vector(); diff --git a/Nuake/src/Resource/ModelLoader.h b/Nuake/src/Resource/ModelLoader.h index a0a8e092..6c2cba9e 100644 --- a/Nuake/src/Resource/ModelLoader.h +++ b/Nuake/src/Resource/ModelLoader.h @@ -48,6 +48,7 @@ namespace Nuake std::vector ProcessSkinnedVertices(aiMesh* mesh); void SetVertexBoneData(SkinnedVertex& vertex, int boneId, float weight); void ProcessAnimationNode(SkeletonNode& dest, const aiNode* src); + void ProcessSkeleton(SkeletonNode& des, const aiNode* src); static inline Matrix4 ConvertMatrixToGLMFormat(const aiMatrix4x4& from) { diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index 668495be..ad78d0e2 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -11,12 +11,24 @@ namespace Nuake Vector3 Scalings; }; + struct BoneTransformTrack + { + std::vector positionTimestamps = {}; + std::vector rotationTimestamps = {}; + std::vector scaleTimestamps = {}; + + std::vector positions = {}; + std::vector rotations = {}; + std::vector scales = {}; + }; + class SkeletalAnimation { private: float m_Duration; int m_TicksPerSecond; + std::unordered_map m_Tracks; std::vector m_Bones; public: diff --git a/Nuake/src/Resource/SkinnedModel.h b/Nuake/src/Resource/SkinnedModel.h index fa4cc819..93930cec 100644 --- a/Nuake/src/Resource/SkinnedModel.h +++ b/Nuake/src/Resource/SkinnedModel.h @@ -20,6 +20,7 @@ namespace Nuake SkinnedModel(const std::string path); ~SkinnedModel(); + SkeletonNode& GetSkeletonRootNode() { return m_SkeletonRoot; } void SetSkeletonRootNode(SkeletonNode& root) { m_SkeletonRoot = std::move(root); diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index e65b6ff3..2d888c34 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -466,33 +466,25 @@ namespace Nuake return; } - SkinnedModelComponent& component = entity.GetComponent(); - for (Ref& model : component.ModelResource->GetMeshes()) + auto& component = entity.GetComponent(); + auto& skeletonRoot = component.ModelResource->GetSkeletonRootNode(); + + Entity skeletonRootEntity = CreateEntity(skeletonRoot.Name); + skeletonRootEntity.AddComponent(); + entity.AddChild(skeletonRootEntity); + + CreateSkeletonTraverse(skeletonRootEntity, skeletonRoot); + } + + void Scene::CreateSkeletonTraverse(Entity& entity, SkeletonNode& skeletonNode) + { + for (auto& c : skeletonNode.Children) { - for (auto& bone : model->GetBones()) - { - auto& parentComponent = entity.GetComponent(); + Entity boneEntity = CreateEntity(c.Name); + boneEntity.AddComponent(); + entity.AddChild(boneEntity); - Logger::Log("bone found:" + bone.Name, "debug", VERBOSE); - if (EntityExists(bone.Name) == false) - { - Entity boneEntity = CreateEntity(bone.Name); - boneEntity.AddComponent(); - - Vector3 position; - Quat rotation; - Vector3 scale; - Decompose(bone.Offset, position, rotation, scale); - - auto& transformComponent = entity.GetComponent(); - transformComponent.SetLocalPosition(position); - transformComponent.SetLocalRotation(rotation); - transformComponent.SetLocalScale(scale); - transformComponent.SetLocalTransform(bone.Offset); - - entity.AddChild(boneEntity); - } - } + CreateSkeletonTraverse(boneEntity, c); } } diff --git a/Nuake/src/Scene/Scene.h b/Nuake/src/Scene/Scene.h index 09a09128..1053ccc4 100644 --- a/Nuake/src/Scene/Scene.h +++ b/Nuake/src/Scene/Scene.h @@ -17,6 +17,7 @@ namespace Nuake { + class SkeletonNode; class Entity; class SceneRenderer; @@ -93,5 +94,8 @@ namespace Nuake // Component specific utilies void CreateSkeleton(Entity& entity); + + private: + void CreateSkeletonTraverse(Entity& entity, SkeletonNode& skeletonNode); }; } From 00c7b975e2141e5634d0f7000d5474ff5a5ba28a Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 09:20:02 -0400 Subject: [PATCH 08/25] Fixed billboard not taking into account parent rotation --- Editor/src/Misc/GizmoDrawer.cpp | 9 ++++---- Nuake/src/Core/Core.h | 1 + Nuake/src/Resource/Animator.cpp | 29 ++++++++++++++++++++++++++ Nuake/src/Resource/Animator.h | 28 +++++++++++++++++++++++++ Nuake/src/Resource/SkeletalAnimation.h | 1 + 5 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 Nuake/src/Resource/Animator.cpp create mode 100644 Nuake/src/Resource/Animator.h diff --git a/Editor/src/Misc/GizmoDrawer.cpp b/Editor/src/Misc/GizmoDrawer.cpp index 48268b8e..cf3521d4 100644 --- a/Editor/src/Misc/GizmoDrawer.cpp +++ b/Editor/src/Misc/GizmoDrawer.cpp @@ -296,7 +296,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) // Translation const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); - particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + particleTransform[3] = initialTransform[3]; particleTransform = glm::scale(particleTransform, Vector3(0.5, 0.5, 0.5)); @@ -317,7 +317,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) // Translation const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); - particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + particleTransform[3] = initialTransform[3]; particleTransform = glm::scale(particleTransform, Vector3(0.5, 0.5, 0.5)); @@ -339,7 +339,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) // Translation const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); - particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); + particleTransform[3] = initialTransform[3]; particleTransform = glm::scale(particleTransform, Vector3(0.5, 0.5, 0.5)); @@ -361,8 +361,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) // Translation const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); - particleTransform[3] = Vector4(particleGlobalPosition, 1.0f); - + particleTransform[3] = initialTransform[3]; particleTransform = glm::scale(particleTransform, Vector3(0.25, 0.25, 0.25)); renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); diff --git a/Nuake/src/Core/Core.h b/Nuake/src/Core/Core.h index 181d234a..9b73304f 100644 --- a/Nuake/src/Core/Core.h +++ b/Nuake/src/Core/Core.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include diff --git a/Nuake/src/Resource/Animator.cpp b/Nuake/src/Resource/Animator.cpp new file mode 100644 index 00000000..c369bf19 --- /dev/null +++ b/Nuake/src/Resource/Animator.cpp @@ -0,0 +1,29 @@ +#include "Animator.h" + +#include "src/Core/Logger.h" + +namespace Nuake +{ + Animator::Animator(std::vector& animations) + { + m_AnimationCount = animations.size(); + m_CurrentAnimation = 0; + + m_Animations = animations; + m_CurrentTime = 0.0f; + m_DeltaTime = 0.0f; + } + + void Animator::PlayAnimation(uint32_t index) + { + if (index < m_AnimationCount) + { + m_CurrentAnimation = index; + } + else + { + m_CurrentAnimation = m_AnimationCount - 1; + Logger::Log("Animation index out of range", "animator", WARNING); + } + } +} \ No newline at end of file diff --git a/Nuake/src/Resource/Animator.h b/Nuake/src/Resource/Animator.h new file mode 100644 index 00000000..72a56a37 --- /dev/null +++ b/Nuake/src/Resource/Animator.h @@ -0,0 +1,28 @@ +#pragma once +#include "src/Core/Core.h" +#include "SkeletalAnimation.h" + +namespace Nuake +{ + class Animator + { + private: + float m_CurrentTime; + float m_DeltaTime; + + uint32_t m_CurrentAnimation; + uint32_t m_AnimationCount; + std::vector m_Animations; + + public: + Animator(std::vector& animations); + ~Animator() = default; + + void Update(float deltaTime); + void PlayAnimation(uint32_t index); + + void CalculateBoneTransform(Matrix4& parentTransform); + + std::vector& GetFinalBoneMatrices(); + }; +} \ No newline at end of file diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index ad78d0e2..a08a1d2e 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -1,4 +1,5 @@ #pragma once +#include "src/Core/Core.h" #include namespace Nuake From 290f0e03b53cd64be07f91330ff5538704bb06d7 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 17:47:14 -0400 Subject: [PATCH 09/25] Scaled down bones --- Editor/src/Misc/GizmoDrawer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/src/Misc/GizmoDrawer.cpp b/Editor/src/Misc/GizmoDrawer.cpp index cf3521d4..c883d3de 100644 --- a/Editor/src/Misc/GizmoDrawer.cpp +++ b/Editor/src/Misc/GizmoDrawer.cpp @@ -362,7 +362,7 @@ void GizmoDrawer::DrawGizmos(Ref scene) // Translation const Vector3& particleGlobalPosition = transform.GetGlobalPosition(); particleTransform[3] = initialTransform[3]; - particleTransform = glm::scale(particleTransform, Vector3(0.25, 0.25, 0.25)); + particleTransform = glm::scale(particleTransform, Vector3(0.1, 0.1, 0.1)); renderList.AddToRenderList(Renderer::QuadMesh, particleTransform); } From fb5069ba5ea9dfaadf61087e020fa7f17bf97816 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 17:48:50 -0400 Subject: [PATCH 10/25] Properly transform bones --- Nuake/src/Rendering/SceneRenderer.cpp | 37 +++++++++++++++++++-------- Nuake/src/Rendering/SceneRenderer.h | 2 ++ Nuake/src/Resource/ModelLoader.cpp | 28 ++++++++++++-------- Nuake/src/Resource/ModelLoader.h | 27 ++++++------------- Nuake/src/Resource/SkeletonNode.h | 2 ++ 5 files changed, 57 insertions(+), 39 deletions(-) diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 03cf1ea3..62760762 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -359,6 +359,8 @@ namespace Nuake gBufferSkinnedMeshShader->SetUniformMat4f("u_Projection", mProjection); gBufferSkinnedMeshShader->SetUniformMat4f("u_View", mView); + RenderCommand::Disable(RendererEnum::FACE_CULL); + // Skinned Models const uint32_t entityIdUniformLocation = gBufferSkinnedMeshShader->FindUniformLocation("u_EntityID"); const uint32_t modelMatrixUniformLocation = gBufferSkinnedMeshShader->FindUniformLocation("u_Model"); @@ -367,22 +369,19 @@ namespace Nuake for (auto e : skinnedModelView) { auto [transform, mesh, visibility] = skinnedModelView.get(e); + auto& meshResource = mesh.ModelResource; - if (mesh.ModelResource && visibility.Visible) + if (meshResource && visibility.Visible) { + auto& rootBoneNode = meshResource->GetSkeletonRootNode(); + + SetSkeletonBoneTransformRecursive(rootBoneNode, gBufferSkinnedMeshShader); + for (auto& m : mesh.ModelResource->GetMeshes()) { m->GetMaterial()->Bind(gBufferSkinnedMeshShader); - uint32_t boneId = 0; - for (auto& b : m->GetBones()) - { - const std::string boneMatrixUniformName = "u_FinalBonesMatrice[" + std::to_string(boneId) + "]"; - gBufferSkinnedMeshShader->SetUniformMat4f(boneMatrixUniformName, b.Offset); - boneId++; - } - - gBufferSkinnedMeshShader->SetUniformMat4f(modelMatrixUniformLocation, transform.GetGlobalTransform()); + gBufferSkinnedMeshShader->SetUniformMat4f(modelMatrixUniformLocation, Matrix4(1.0f)); gBufferSkinnedMeshShader->SetUniform1i(entityIdUniformLocation, (uint32_t)e + 1); m->Draw(gBufferSkinnedMeshShader, true); } @@ -452,4 +451,22 @@ namespace Nuake void SceneRenderer::PostProcessPass(const Scene& scene) { } + + void SceneRenderer::SetSkeletonBoneTransformRecursive(SkeletonNode& skeletonNode, Shader* shader) + { + auto scene = Engine::GetCurrentScene(); + for (auto& child : skeletonNode.Children) + { + 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); + } + + SetSkeletonBoneTransformRecursive(child, shader); + } + } + } \ No newline at end of file diff --git a/Nuake/src/Rendering/SceneRenderer.h b/Nuake/src/Rendering/SceneRenderer.h index 1e4d9d72..267359ad 100644 --- a/Nuake/src/Rendering/SceneRenderer.h +++ b/Nuake/src/Rendering/SceneRenderer.h @@ -39,5 +39,7 @@ namespace Nuake void GBufferPass(Scene& scene); void ShadingPass(Scene& scene); void PostProcessPass(const Scene& scene); + + void SetSkeletonBoneTransformRecursive(SkeletonNode& skeletonNode, Shader* shader); }; } \ No newline at end of file diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index 157ac835..57cfe60d 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -50,8 +50,13 @@ namespace Nuake return model; } + + std::unordered_map bonesNameIDMap; Ref ModelLoader::LoadSkinnedModel(const std::string& path, bool absolute) { + bonesNameIDMap = std::unordered_map(); + m_BoneMap = std::unordered_map(); + m_SkinnedMeshes.clear(); Ref model = CreateRef(path); @@ -137,7 +142,6 @@ namespace Nuake auto& indices = ProcessIndices(node); auto& material = ProcessMaterials(scene, node); auto& bones = std::vector(); - auto& bonesMap = std::unordered_map(); if (node->HasBones()) { @@ -148,7 +152,7 @@ namespace Nuake const std::string& boneName = bone->mName.C_Str(); int32_t boneId = -1; - if (bonesMap.find(boneName) == bonesMap.end()) + if (m_BoneMap.find(boneName) == m_BoneMap.end()) { boneId = boneCounter; boneCounter++; @@ -157,11 +161,12 @@ namespace Nuake newBone.Offset = ConvertMatrixToGLMFormat(bone->mOffsetMatrix); bones.push_back(newBone); - bonesMap[boneName] = newBone; + bonesNameIDMap[boneName] = boneId; + m_BoneMap[boneName] = newBone; } else { - boneId = bonesMap[boneName].Id; + boneId = m_BoneMap[boneName].Id; } assert(boneId != -1); @@ -171,7 +176,7 @@ namespace Nuake { aiVertexWeight vertexWeight = bone->mWeights[j]; const uint32_t vertexWeightVertexId = vertexWeight.mVertexId; - + SetVertexBoneData(vertices[vertexWeightVertexId], boneId, vertexWeight.mWeight); //BoneVertexWeight boneVertexWeight @@ -215,20 +220,20 @@ namespace Nuake auto vertices = std::vector(); for (uint32_t i = 0; i < mesh->mNumVertices; i++) { - Vertex vertex; + Vertex vertex {}; Vector3 current; // Position current.x = mesh->mVertices[i].x; - current.y = mesh->mVertices[i].z; - current.z = mesh->mVertices[i].y; + current.y = mesh->mVertices[i].y; + current.z = mesh->mVertices[i].z; vertex.position = current; // Normals current.x = mesh->mNormals[i].x; - current.y = mesh->mNormals[i].z; - current.z = mesh->mNormals[i].y; + current.y = mesh->mNormals[i].y; + current.z = mesh->mNormals[i].z; vertex.normal = current; // Tangents @@ -343,6 +348,8 @@ namespace Nuake dest.Name = src->mName.data; dest.Transform = ConvertMatrixToGLMFormat(src->mTransformation); dest.ChildrenCount = src->mNumChildren; + dest.Id = bonesNameIDMap[dest.Name]; + dest.Offset = m_BoneMap[dest.Name].Offset; for (uint32_t i = 0; i < dest.ChildrenCount; i++) { @@ -358,6 +365,7 @@ namespace Nuake SkeletonNode bone; bone.Name = src->mName.C_Str(); bone.Transform = ConvertMatrixToGLMFormat(src->mTransformation); + bone.Id = bonesNameIDMap[bone.Name]; des.ChildrenCount++; des.Children.push_back(bone); diff --git a/Nuake/src/Resource/ModelLoader.h b/Nuake/src/Resource/ModelLoader.h index 6c2cba9e..598be588 100644 --- a/Nuake/src/Resource/ModelLoader.h +++ b/Nuake/src/Resource/ModelLoader.h @@ -33,6 +33,8 @@ namespace Nuake std::string modelDir; std::vector> m_Meshes; std::vector> m_SkinnedMeshes; + std::unordered_map m_BoneIDMap; + std::unordered_map m_BoneMap; void ProcessNode(aiNode* node, const aiScene* scene); Ref ProcessMesh(aiMesh* node, const aiScene* scene); @@ -52,27 +54,14 @@ namespace Nuake static inline Matrix4 ConvertMatrixToGLMFormat(const aiMatrix4x4& from) { - Matrix4 result; - for (auto i = 0; i < 3; i++) - { - for (auto j = 0; j < 3; j++) - { - result[i][j] = from[i][j]; - } - } + Matrix4 to; - // The rest would be zero, other than the 4,4. - result[0][3] = 0.0f; - result[1][3] = 0.0f; - result[2][3] = 0.0f; + to[0][0] = from.a1; to[0][1] = from.b1; to[0][2] = from.c1; to[0][3] = from.d1; + to[1][0] = from.a2; to[1][1] = from.b2; to[1][2] = from.c2; to[1][3] = from.d2; + to[2][0] = from.a3; to[2][1] = from.b3; to[2][2] = from.c3; to[2][3] = from.d3; + to[3][0] = from.a4; to[3][1] = from.b4; to[3][2] = from.c4; to[3][3] = from.d4; - result[3][0] = 0.0f; - result[3][1] = 0.0f; - result[3][2] = 0.0f; - - result[3][3] = 1.0f; - - return result; + return to; } }; } \ No newline at end of file diff --git a/Nuake/src/Resource/SkeletonNode.h b/Nuake/src/Resource/SkeletonNode.h index 7c8e2277..90bc5fa2 100644 --- a/Nuake/src/Resource/SkeletonNode.h +++ b/Nuake/src/Resource/SkeletonNode.h @@ -7,8 +7,10 @@ namespace Nuake struct SkeletonNode { Matrix4 Transform; + Matrix4 Offset; std::string Name; int ChildrenCount; std::vector Children; + int32_t Id = -1; }; } \ No newline at end of file From 3dc97cafa7277755e988a93a4e24914ab467ebcd Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 17:49:05 -0400 Subject: [PATCH 11/25] Animation system --- Nuake/src/Rendering/Renderer.cpp | 2 +- Nuake/src/Resource/ModelLoader.cpp | 64 ++++++++++-- Nuake/src/Resource/SkeletalAnimation.cpp | 104 ++++++++++++++++++ Nuake/src/Resource/SkeletalAnimation.h | 110 +++++++++++++++++--- Nuake/src/Resource/SkinnedModel.cpp | 37 +++++++ Nuake/src/Resource/SkinnedModel.h | 9 ++ Nuake/src/Scene/Scene.cpp | 25 +++++ Nuake/src/Scene/Systems/AnimationSystem.cpp | 89 ++++++++++++++++ Nuake/src/Scene/Systems/AnimationSystem.h | 24 +++++ 9 files changed, 444 insertions(+), 20 deletions(-) create mode 100644 Nuake/src/Resource/SkeletalAnimation.cpp create mode 100644 Nuake/src/Scene/Systems/AnimationSystem.cpp create mode 100644 Nuake/src/Scene/Systems/AnimationSystem.h diff --git a/Nuake/src/Rendering/Renderer.cpp b/Nuake/src/Rendering/Renderer.cpp index da239a74..c6490846 100644 --- a/Nuake/src/Rendering/Renderer.cpp +++ b/Nuake/src/Rendering/Renderer.cpp @@ -53,7 +53,7 @@ namespace Nuake { Vector3(-0.5f, 0.5f, 0.5f), Vector2(1, 1), Vector3(-1, 0, 0) } }; - std::vector CubeIndices + std::vector CubeIndices { 0, 1, 3, 3, 1, 2, 1, 5, 2, 2, 5, 6, diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index 57cfe60d..855c368b 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -84,20 +84,70 @@ namespace Nuake ProcessSkinnedNode(scene->mRootNode, scene); if (scene->HasAnimations()) { - SkeletalAnimation animation; + std::vector> animations = std::vector>(); + // Parse animations for (uint32_t i = 0; i < scene->mNumAnimations; i++) { aiAnimation* aiAnim = scene->mAnimations[i]; - const float duration = aiAnim->mDuration; - const float ticksPerSecond = aiAnim->mTicksPerSecond; - // Read data - SkeletonNode rootSkeletonNode; - ProcessAnimationNode(rootSkeletonNode, scene->mRootNode); + const std::string animationName = aiAnim->mName.data; + const float animationDuration = aiAnim->mDuration; + const float animationTicksPerSecond = aiAnim->mTicksPerSecond; + auto animation = CreateRef(animationName, animationDuration, animationTicksPerSecond); - model->SetSkeletonRootNode(rootSkeletonNode); + // Here we iterate over every channel(each channel represents a bone) and fill the SkeletalAnimation + // object with every keyframe. We essentially just convert every assimp vector, quat, string to our own types. + for (uint32_t j = 0; j < aiAnim->mNumChannels; j++) + { + aiNodeAnim* animChannel = aiAnim->mChannels[j]; + const std::string channelName = animChannel->mNodeName.data; // this should be a bone name + + // Create the track + BoneTransformTrack& track = animation->GetTrack(channelName); + + // Create every keyframe in the current channel + // Position + for (uint32_t p = 0; p < animChannel->mNumPositionKeys; p++) + { + aiVectorKey positionKey = animChannel->mPositionKeys[p]; + const float keyTime = positionKey.mTime; + const aiVector3D assimpKeyValue = positionKey.mValue; + const Vector3 keyValue = Vector3(assimpKeyValue.x, assimpKeyValue.y, assimpKeyValue.z); + + track.PushPositionKeyframe(keyTime, keyValue); + } + + // Rotation + for (uint32_t r = 0; r < animChannel->mNumRotationKeys; r++) + { + aiQuatKey rotationKey = animChannel->mRotationKeys[r]; + const float keyTime = rotationKey.mTime; + const aiQuaterniont assimpKeyValue = rotationKey.mValue; + const Quat keyValue = Quat(assimpKeyValue.w, assimpKeyValue.x, assimpKeyValue.y, assimpKeyValue.z); + + track.PushRotationKeyframe(keyTime, keyValue); + } + + // Scaling + for (uint32_t s = 0; s < animChannel->mNumScalingKeys; s++) + { + aiVectorKey scaleKey = animChannel->mScalingKeys[s]; + const float keyTime = scaleKey.mTime; + const aiVector3D assimpKeyValue = scaleKey.mValue; + const Vector3 keyValue = Vector3(assimpKeyValue.x, assimpKeyValue.y, assimpKeyValue.z); + + track.PushScaleKeyframe(keyTime, keyValue); + } + } + + animations.push_back(animation); } + + SkeletonNode rootSkeletonNode; + ProcessAnimationNode(rootSkeletonNode, scene->mRootNode); + model->SetSkeletonRootNode(std::move(rootSkeletonNode)); + model->SetAnimations(std::move(animations)); } for (const auto& mesh : m_SkinnedMeshes) diff --git a/Nuake/src/Resource/SkeletalAnimation.cpp b/Nuake/src/Resource/SkeletalAnimation.cpp new file mode 100644 index 00000000..c2cfd7ee --- /dev/null +++ b/Nuake/src/Resource/SkeletalAnimation.cpp @@ -0,0 +1,104 @@ +#include "SkeletalAnimation.h" + +namespace Nuake +{ + BoneTransformTrack::BoneTransformTrack() + { + m_Positions = std::vector(); + m_Rotations = std::vector(); + m_Scales = std::vector(); + + m_PositionTimestamps = std::vector(); + m_RotationTimestamps = std::vector(); + m_ScaleTimestamps = std::vector(); + } + + float BoneTransformTrack::GetScaleFactor(float lastTime, float nextTime, float animationTime) + { + float scaleFactor = 0.0f; + float midWayLength = animationTime - lastTime; + float framesDiff = nextTime - lastTime; + scaleFactor = midWayLength / framesDiff; + return scaleFactor; + } + + Nuake::Matrix4 BoneTransformTrack::InterpolatePosition(float time) + { + if (m_Positions.size() == 0) + { + return Matrix4(1.0f); + } + + if (m_Positions.size() == 1) + { + return glm::translate(Matrix4(1.0f), m_Positions[0]); + } + + int p0Index = GetPositionIndex(time); + int p1Index = p0Index + 1; + float scaleFactor = GetScaleFactor(m_PositionTimestamps[p0Index], m_PositionTimestamps[p1Index], time); + glm::vec3 finalPosition = glm::mix(m_Positions[p0Index], m_Positions[p1Index], scaleFactor); + return glm::translate(Matrix4(1.0f), finalPosition); + } + + Nuake::Matrix4 BoneTransformTrack::InterpolateRotation(float time) + { + if (m_Rotations.size() == 0) + { + return Matrix4(1.0f); + } + + if (m_Rotations.size() == 1) + { + auto rotation = glm::normalize(m_Rotations[0]); + return glm::toMat4(rotation); + } + + int p0Index = GetRotationIndex(time); + int p1Index = p0Index + 1; + float scaleFactor = GetScaleFactor(m_RotationTimestamps[p0Index], + m_RotationTimestamps[p1Index], time); + glm::quat finalRotation = glm::slerp(m_Rotations[p0Index], + m_Rotations[p1Index], scaleFactor); + finalRotation = glm::normalize(finalRotation); + return glm::toMat4(finalRotation); + } + + Nuake::Matrix4 BoneTransformTrack::InterpolateScale(float time) + { + if (m_Scales.size() == 0) + { + return Matrix4(1.0f); + } + + if (1 == m_Scales.size()) + return glm::scale(glm::mat4(1.0f), m_Scales[0]); + + int p0Index = GetScaleIndex(time); + int p1Index = p0Index + 1; + float scaleFactor = GetScaleFactor(m_ScaleTimestamps[p0Index], + m_ScaleTimestamps[p1Index], time); + glm::vec3 finalScale = glm::mix(m_Scales[p0Index], m_Scales[p1Index], scaleFactor); + return glm::scale(glm::mat4(1.0f), finalScale); + } + + SkeletalAnimation::SkeletalAnimation(const std::string& name, float duration, float ticksPerSecond) + { + m_Name = name; + m_Duration = duration; + m_TicksPerSecond = ticksPerSecond; + m_CurrentTime = 0.0f; + m_Loop = true; + } + + BoneTransformTrack& SkeletalAnimation::GetTrack(const std::string& name) + { + if (m_Tracks.find(name) != m_Tracks.end()) + { + return m_Tracks[name]; + } + + m_Tracks[name] = BoneTransformTrack(); + return m_Tracks[name]; + } +} \ No newline at end of file diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index a08a1d2e..42c2e941 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -12,32 +12,118 @@ namespace Nuake Vector3 Scalings; }; - struct BoneTransformTrack + class BoneTransformTrack { - std::vector positionTimestamps = {}; - std::vector rotationTimestamps = {}; - std::vector scaleTimestamps = {}; + private: + std::vector m_PositionTimestamps = {}; + std::vector m_RotationTimestamps = {}; + std::vector m_ScaleTimestamps = {}; - std::vector positions = {}; - std::vector rotations = {}; - std::vector scales = {}; + std::vector m_Positions = {}; + std::vector m_Rotations = {}; + std::vector m_Scales = {}; + + public: + BoneTransformTrack(); + ~BoneTransformTrack() = default; + + void PushPositionKeyframe(float timestamp, const Vector3& position) + { + m_PositionTimestamps.push_back(timestamp); + m_Positions.push_back(position); + } + + void PushRotationKeyframe(float timestamp, const Quat& rotation) + { + m_RotationTimestamps.push_back(timestamp); + m_Rotations.push_back(rotation); + } + + void PushScaleKeyframe(float timestamp, const Vector3& scale) + { + m_ScaleTimestamps.push_back(timestamp); + m_Scales.push_back(scale); + } + + int GetPositionIndex(float animationTime) + { + if (m_Positions.size() == 0) + { + return 0; + } + + for (int index = 0; index < m_Positions.size() - 1; index++) + { + if (animationTime < m_PositionTimestamps[index + 1]) + { + return index; + } + } + assert(0); + } + + /* Gets the current index on mKeyRotations to interpolate to based on the + current animation time*/ + int GetRotationIndex(float animationTime) + { + for (int index = 0; index < m_Rotations.size() - 1; ++index) + { + if (animationTime < m_RotationTimestamps[index + 1]) + { + return index; + } + } + assert(0); + } + + /* Gets the current index on mKeyScalings to interpolate to based on the + current animation time */ + int GetScaleIndex(float animationTime) + { + for (int index = 0; index < m_Scales.size() - 1; ++index) + { + if (animationTime < m_ScaleTimestamps[index + 1]) + { + return index; + } + } + assert(0); + } + + float GetScaleFactor(float lastTime, float nextTime, float animationTime); + Matrix4 InterpolatePosition(float time); + Matrix4 InterpolateRotation(float time); + Matrix4 InterpolateScale(float time); }; class SkeletalAnimation { private: - float m_Duration; - int m_TicksPerSecond; - std::unordered_map m_Tracks; - std::vector m_Bones; + float m_CurrentTime; + float m_Duration; + float m_TicksPerSecond; + std::string m_Name; + bool m_Loop; public: SkeletalAnimation() = default; + SkeletalAnimation(const std::string& name, float duration, float ticksPerSecond); + ~SkeletalAnimation() = default; - Bone& FindBone(const std::string& boneName); + void SetCurrentTime(float time) + { + m_CurrentTime = fmod(time, m_Duration); + } + float GetCurrentTime() const { return m_CurrentTime; } + void SetDuration(float duration) { m_Duration = duration; } + float GetDuration() const { return m_Duration; } float GetTicksPerSecond() const { return m_TicksPerSecond; } + void SetTicksPerSecond(float ticks) { m_TicksPerSecond = ticks; } + + BoneTransformTrack& GetTrack(const std::string& name); + std::unordered_map& GetTracks() { return m_Tracks; } }; } diff --git a/Nuake/src/Resource/SkinnedModel.cpp b/Nuake/src/Resource/SkinnedModel.cpp index a638fa91..a6bf06d3 100644 --- a/Nuake/src/Resource/SkinnedModel.cpp +++ b/Nuake/src/Resource/SkinnedModel.cpp @@ -27,6 +27,43 @@ namespace Nuake return m_Meshes; } + void SkinnedModel::SetAnimations(const std::vector> animations) + { + m_NumAnimation = static_cast(animations.size()); + m_CurrentAnimation = 0; + m_Animations = animations; + } + + void SkinnedModel::AddAnimation(Ref animation) + { + m_NumAnimation++; + m_Animations.push_back(std::move(animation)); + } + + Ref SkinnedModel::GetCurrentAnimation() + { + if (m_CurrentAnimation < m_NumAnimation) + { + return m_Animations[m_CurrentAnimation]; + } + + Logger::Log("Cannot get animation if no animation exists", "skinned model", WARNING); + return nullptr; + } + + void SkinnedModel::PlayAnimation(uint32_t animationId) + { + if (animationId >= m_NumAnimation) + { + Logger::Log("Cannot play animation, index out of range", "skinned model", CRITICAL); + return; + } + + GetCurrentAnimation()->SetCurrentTime(0.0f); // Reset previous animation + + m_CurrentAnimation = animationId; + } + json SkinnedModel::Serialize() { BEGIN_SERIALIZE(); diff --git a/Nuake/src/Resource/SkinnedModel.h b/Nuake/src/Resource/SkinnedModel.h index 93930cec..99711080 100644 --- a/Nuake/src/Resource/SkinnedModel.h +++ b/Nuake/src/Resource/SkinnedModel.h @@ -15,6 +15,10 @@ namespace Nuake SkeletonNode m_SkeletonRoot; + uint32_t m_CurrentAnimation = 0; + uint32_t m_NumAnimation = 0; + std::vector> m_Animations; + public: SkinnedModel(); SkinnedModel(const std::string path); @@ -29,6 +33,11 @@ namespace Nuake void AddMesh(Ref mesh); std::vector>& GetMeshes(); + void SetAnimations(const std::vector> animations); + void AddAnimation(Ref animation); + Ref GetCurrentAnimation(); + void PlayAnimation(uint32_t animationId); + json Serialize() override; bool Deserialize(const json& j) override; }; diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 2d888c34..b94d9973 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -4,6 +4,7 @@ #include "src/Scene/Systems/TransformSystem.h" #include "src/Scene/Systems/QuakeMapBuilder.h" #include "src/Scene/Systems/ParticleSystem.h" +#include "src/Scene/Systems/AnimationSystem.h" #include "src/Rendering/SceneRenderer.h" #include "Scene.h" @@ -49,6 +50,7 @@ namespace Nuake // Adding systems - Order is important m_Systems.push_back(CreateRef(this)); m_Systems.push_back(CreateRef(this)); + m_Systems.push_back(CreateRef(this)); m_Systems.push_back(CreateRef(this)); m_Systems.push_back(CreateRef(this)); @@ -473,6 +475,17 @@ namespace Nuake skeletonRootEntity.AddComponent(); entity.AddChild(skeletonRootEntity); + Vector3 bonePosition; + Quat boneRotation; + Vector3 boneScale; + Decompose(skeletonRoot.Transform, bonePosition, boneRotation, boneScale); + + auto& transformComponent = skeletonRootEntity.GetComponent(); + transformComponent.SetLocalPosition(bonePosition); + transformComponent.SetLocalRotation(boneRotation); + transformComponent.SetLocalScale(boneScale); + transformComponent.SetLocalTransform(skeletonRoot.Transform); + CreateSkeletonTraverse(skeletonRootEntity, skeletonRoot); } @@ -484,6 +497,18 @@ namespace Nuake boneEntity.AddComponent(); entity.AddChild(boneEntity); + Vector3 bonePosition; + Quat boneRotation; + Vector3 boneScale; + Decompose(c.Transform, bonePosition, boneRotation, boneScale); + + auto& transformComponent = boneEntity.GetComponent(); + transformComponent.SetLocalPosition(bonePosition); + transformComponent.SetLocalRotation(boneRotation); + transformComponent.SetLocalScale(boneScale); + transformComponent.SetLocalTransform(c.Transform); + transformComponent.Dirty = false; + CreateSkeletonTraverse(boneEntity, c); } } diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp new file mode 100644 index 00000000..7c934f70 --- /dev/null +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -0,0 +1,89 @@ +#include "AnimationSystem.h" + +#include "src/Scene/Scene.h" +#include "src/Scene/Entities/Entity.h" +#include "src/Scene/Components/SkinnedModelComponent.h" + +namespace Nuake +{ + AnimationSystem::AnimationSystem(Scene* scene) + { + m_Scene = scene; + } + + bool AnimationSystem::Init() + { + return true; + } + + void AnimationSystem::Update(Timestep ts) + { + auto view = m_Scene->m_Registry.view(); + for (auto e : view) + { + auto [transformComponent, skinnedComponent] = view.get(e); + + auto& model = skinnedComponent.ModelResource; + if (!model) + { + continue; + } + + Ref animation = model->GetCurrentAnimation(); + float newAnimationTime = animation->GetCurrentTime() + (ts * animation->GetTicksPerSecond()); + animation->SetCurrentTime(newAnimationTime); + + auto& rootBone = model->GetSkeletonRootNode(); + UpdateBonePositionTraversal(rootBone, animation, animation->GetCurrentTime()); + } + } + + void AnimationSystem::UpdateBonePositionTraversal(SkeletonNode& bone, Ref animation, float time) + { + const std::string& boneName = bone.Name; + + + Entity& boneEntity = m_Scene->GetEntity(boneName); + if (boneEntity.GetHandle() != -1) + { + auto& animationTrack = animation->GetTrack(boneName); + auto& transformComponent = boneEntity.GetComponent(); + + // 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; + + Vector3 localPosition; + Quat localRotation; + Vector3 localScale; + Decompose(finalTransform, localPosition, localRotation, localScale); + + transformComponent.SetLocalPosition(localPosition); + transformComponent.SetLocalRotation(localRotation); + transformComponent.SetLocalScale(localScale); + transformComponent.SetLocalTransform(finalTransform); + } + + for (auto& childBone : bone.Children) + { + UpdateBonePositionTraversal(childBone, animation, time); + } + } + + void AnimationSystem::FixedUpdate(Timestep ts) + { + + } + + void AnimationSystem::EditorUpdate() + { + + } + + void AnimationSystem::Exit() + { + + } +} diff --git a/Nuake/src/Scene/Systems/AnimationSystem.h b/Nuake/src/Scene/Systems/AnimationSystem.h new file mode 100644 index 00000000..57361dad --- /dev/null +++ b/Nuake/src/Scene/Systems/AnimationSystem.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include + +#include "src/Resource/SkeletonNode.h" +#include "src/Resource/SkeletalAnimation.h" + +namespace Nuake +{ + class AnimationSystem : public System + { + public: + AnimationSystem(Scene* scene); + bool Init() override; + void Update(Timestep ts) override; + void Draw() override {} + void EditorUpdate() override; + void FixedUpdate(Timestep ts) override; + void Exit() override; + + private: + void UpdateBonePositionTraversal(SkeletonNode& bone, Ref animation, float time); + }; +} From 62017e0bd8ee612ae65233ba76c4a75aaaacc469 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 18:48:51 -0400 Subject: [PATCH 12/25] Increased max bones to 200 --- Editor/resources/Shaders/gbuffer_skinned.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/resources/Shaders/gbuffer_skinned.shader b/Editor/resources/Shaders/gbuffer_skinned.shader index c13922ce..4712d27d 100644 --- a/Editor/resources/Shaders/gbuffer_skinned.shader +++ b/Editor/resources/Shaders/gbuffer_skinned.shader @@ -13,7 +13,7 @@ uniform mat4 u_Model; uniform mat4 u_View; uniform mat4 u_Projection; -const int MAX_BONES = 100; +const int MAX_BONES = 200; const int MAX_BONES_INFLUENCE = 4; uniform mat4 u_FinalBonesMatrice[MAX_BONES]; From 8718540ac609d7961b21210beec3c50e487f59ea Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 18:49:11 -0400 Subject: [PATCH 13/25] Added animation selection --- .../src/ComponentsPanel/SkinnedModelPanel.h | 56 +++++++++++++++++++ Nuake/src/Resource/SkeletalAnimation.h | 1 + Nuake/src/Resource/SkinnedModel.h | 6 ++ 3 files changed, 63 insertions(+) diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h index 66d9b3da..eaf8e838 100644 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ b/Editor/src/ComponentsPanel/SkinnedModelPanel.h @@ -102,6 +102,62 @@ public: ImGui::TableNextColumn(); ComponentTableReset(component.ModelPath, ""); + + if (component.ModelResource) + { + auto& model = component.ModelResource; + ImGui::TableNextColumn(); + + { + ImGui::Text("Playing"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##playing", &model->IsPlaying); + + ImGui::TableNextColumn(); + ComponentTableReset(model->IsPlaying, true); + ImGui::TableNextColumn(); + } + + { + ImGui::Text("Type"); + ImGui::TableNextColumn(); + + uint32_t animIndex = model->GetCurrentAnimationIndex(); + uint32_t oldAnimIndex = animIndex; + auto& animations = model->GetAnimations(); + if (ImGui::BeginCombo("Type", model->GetCurrentAnimation()->GetName().c_str())) + { + for (int n = 0; n < model->GetAnimationsCount(); n++) + { + bool is_selected = (animIndex == n); + if (ImGui::Selectable(animations[n]->GetName().c_str(), is_selected)) + { + animIndex = n; + } + + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + if (animIndex != oldAnimIndex) + { + model->PlayAnimation(animIndex); + } + + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetLabel = std::string(ICON_FA_UNDO) + "##ResetAnimId"; + if (ImGui::Button(resetLabel.c_str())) + { + model->PlayAnimation(0); + } + ImGui::PopStyleColor(); + } + } + } EndComponentTable(); } diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index 42c2e941..4ea0419f 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -123,6 +123,7 @@ namespace Nuake float GetTicksPerSecond() const { return m_TicksPerSecond; } void SetTicksPerSecond(float ticks) { m_TicksPerSecond = ticks; } + const std::string& GetName() const { return m_Name; } BoneTransformTrack& GetTrack(const std::string& name); std::unordered_map& GetTracks() { return m_Tracks; } }; diff --git a/Nuake/src/Resource/SkinnedModel.h b/Nuake/src/Resource/SkinnedModel.h index 99711080..70e30a52 100644 --- a/Nuake/src/Resource/SkinnedModel.h +++ b/Nuake/src/Resource/SkinnedModel.h @@ -20,6 +20,8 @@ namespace Nuake std::vector> m_Animations; public: + bool IsPlaying = true; + SkinnedModel(); SkinnedModel(const std::string path); ~SkinnedModel(); @@ -33,10 +35,14 @@ namespace Nuake void AddMesh(Ref mesh); std::vector>& GetMeshes(); + std::vector> GetAnimations() const { return m_Animations; } void SetAnimations(const std::vector> animations); void AddAnimation(Ref animation); + Ref GetCurrentAnimation(); void PlayAnimation(uint32_t animationId); + uint32_t GetCurrentAnimationIndex() const { return m_CurrentAnimation; } + uint32_t GetAnimationsCount() const { return m_NumAnimation; } json Serialize() override; bool Deserialize(const json& j) override; From fe9a32c8903288f67dffe498e328d55267e9d443 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 18:49:19 -0400 Subject: [PATCH 14/25] Removed useless code --- Nuake/src/Rendering/Mesh/SkinnedMesh.cpp | 10 ---------- Nuake/src/Rendering/Mesh/SkinnedMesh.h | 1 - 2 files changed, 11 deletions(-) diff --git a/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp b/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp index daf6a61a..2dad3af8 100644 --- a/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp +++ b/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp @@ -20,7 +20,6 @@ namespace Nuake { m_Vertices = vertices; m_Indices = indices; - m_Bones = bones; SetupMesh(); CalculateAABB(); @@ -41,11 +40,6 @@ namespace Nuake return m_Indices; } - std::vector& SkinnedMesh::GetBones() - { - return m_Bones; - } - Ref SkinnedMesh::GetMaterial() inline const { return m_Material; @@ -129,10 +123,6 @@ namespace Nuake j["Material"] = m_Material->Serialize(); j["Indices"] = m_Indices; - for (uint32_t i = 0; i < m_Bones.size(); i++) - { - //j["Bones"][i] = m_Bones[i]; - } json v; for (uint32_t i = 0; i < m_Vertices.size(); i++) { diff --git a/Nuake/src/Rendering/Mesh/SkinnedMesh.h b/Nuake/src/Rendering/Mesh/SkinnedMesh.h index 9ce765bf..b7d5cb1c 100644 --- a/Nuake/src/Rendering/Mesh/SkinnedMesh.h +++ b/Nuake/src/Rendering/Mesh/SkinnedMesh.h @@ -49,7 +49,6 @@ namespace Nuake Ref m_Material = nullptr; std::vector m_Indices; std::vector m_Vertices; - std::vector m_Bones; Scope m_VertexBuffer; Scope m_VertexArray; From 0062a0f81b352e0903c6a31bf7b6cd5e5c3baea3 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 18:49:25 -0400 Subject: [PATCH 15/25] Fix viewport selection --- Editor/src/Windows/EditorInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 1175d027..c4e184ad 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -252,7 +252,7 @@ namespace Nuake { m_IsViewportFocused = ImGui::IsWindowFocused(); - if (m_IsHoveringViewport && Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_1) && !ImGuizmo::IsUsing()) + if (m_IsHoveringViewport && Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_1) && !ImGuizmo::IsUsing() && m_IsViewportFocused) { const auto windowPosNuake = Vector2(windowPos.x, windowPos.y); auto& gbuffer = Engine::GetCurrentScene()->m_SceneRenderer->GetGBuffer(); From 10c92feaa364fbc9fd4ca0e94a49d44e476dcbc9 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 18:49:35 -0400 Subject: [PATCH 16/25] Edge case fixes --- Nuake/src/Resource/ModelLoader.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index 855c368b..eed7afa5 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -380,6 +380,18 @@ namespace Nuake void ModelLoader::SetVertexBoneData(SkinnedVertex& vertex, int boneID, float weight) { + for (int i = 0; i < MAX_BONE_INFLUENCE; ++i) + { + if (vertex.boneIDs[i] == boneID) { + return; + } + } + + if (weight == 0.0f) + { + return; + } + for (int i = 0; i < MAX_BONE_INFLUENCE; ++i) { if (vertex.boneIDs[i] < 0) From 1628214370ff8bb0c21bd5e3c7f3e1eef35f18c3 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 20:05:10 -0400 Subject: [PATCH 17/25] Animation serialization progress --- .../src/ComponentsPanel/SkinnedModelPanel.h | 12 ++- Nuake/src/Rendering/Mesh/SkinnedMesh.cpp | 26 ++++--- Nuake/src/Rendering/Mesh/SkinnedMesh.h | 6 -- Nuake/src/Resource/ModelLoader.cpp | 3 +- Nuake/src/Resource/SkeletalAnimation.cpp | 76 +++++++++++++++++++ Nuake/src/Resource/SkeletalAnimation.h | 22 +++++- Nuake/src/Resource/SkinnedModel.cpp | 16 ++++ Nuake/src/Scene/Components/BoneComponent.h | 15 ++++ Nuake/src/Scene/Entities/Entity.cpp | 9 ++- Nuake/src/Scene/Systems/AnimationSystem.cpp | 11 ++- 10 files changed, 170 insertions(+), 26 deletions(-) diff --git a/Editor/src/ComponentsPanel/SkinnedModelPanel.h b/Editor/src/ComponentsPanel/SkinnedModelPanel.h index eaf8e838..cdba235d 100644 --- a/Editor/src/ComponentsPanel/SkinnedModelPanel.h +++ b/Editor/src/ComponentsPanel/SkinnedModelPanel.h @@ -119,8 +119,9 @@ public: ImGui::TableNextColumn(); } + if(model->GetCurrentAnimation()) { - ImGui::Text("Type"); + ImGui::Text("Animation"); ImGui::TableNextColumn(); uint32_t animIndex = model->GetCurrentAnimationIndex(); @@ -131,7 +132,14 @@ public: for (int n = 0; n < model->GetAnimationsCount(); n++) { bool is_selected = (animIndex == n); - if (ImGui::Selectable(animations[n]->GetName().c_str(), is_selected)) + std::string animName = animations[n]->GetName(); + + if (animName.empty()) + { + animName = "Empty"; + } + + if (ImGui::Selectable(animName.c_str(), is_selected)) { animIndex = n; } diff --git a/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp b/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp index 2dad3af8..8d97a2d4 100644 --- a/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp +++ b/Nuake/src/Rendering/Mesh/SkinnedMesh.cpp @@ -145,6 +145,12 @@ namespace Nuake v["Bitangent"]["y"] = m_Vertices[i].bitangent.y; v["Bitangent"]["z"] = m_Vertices[i].bitangent.z; + for (uint32_t b = 0; b < MAX_BONE_INFLUENCE; b++) + { + v["Weight"][b] = m_Vertices[i].weights[b]; + v["BoneIDs"][b] = m_Vertices[i].boneIDs[b]; + } + j["Vertices"][i] = v; } @@ -177,10 +183,17 @@ namespace Nuake vertex.uv = { 0.0, 0.0 }; } DESERIALIZE_VEC3(v["Position"], vertex.position) - DESERIALIZE_VEC3(v["Normal"], vertex.normal) - DESERIALIZE_VEC3(v["Tangent"], vertex.tangent) - DESERIALIZE_VEC3(v["Bitangent"], vertex.bitangent) - vertices.push_back(vertex); + DESERIALIZE_VEC3(v["Normal"], vertex.normal) + DESERIALIZE_VEC3(v["Tangent"], vertex.tangent) + DESERIALIZE_VEC3(v["Bitangent"], vertex.bitangent) + + for (uint32_t i = 0; i < MAX_BONE_INFLUENCE; i++) + { + vertex.weights[i] = v["Weight"][i]; + vertex.boneIDs[i] = v["boneIDs"][i]; + } + + vertices.push_back(vertex); } } ); @@ -190,9 +203,4 @@ namespace Nuake SetupMesh(); return true; } - - void SkinnedMesh::SetSkeletalAnimation(Ref skeletalAnimation) - { - m_SkeletalAnimation = skeletalAnimation; - } } diff --git a/Nuake/src/Rendering/Mesh/SkinnedMesh.h b/Nuake/src/Rendering/Mesh/SkinnedMesh.h index b7d5cb1c..c8af79f7 100644 --- a/Nuake/src/Rendering/Mesh/SkinnedMesh.h +++ b/Nuake/src/Rendering/Mesh/SkinnedMesh.h @@ -26,7 +26,6 @@ namespace Nuake void AddSurface(std::vector vertices, std::vector indices, std::vector bones); std::vector& GetVertices(); std::vector& GetIndices(); - std::vector& GetBones(); Ref GetMaterial() inline const; void SetMaterial(Ref material); @@ -40,12 +39,7 @@ namespace Nuake json Serialize() override; bool Deserialize(const json& j) override; - void SetSkeletalAnimation(Ref animation); - Ref GetSkeletalAnimation() const { return m_SkeletalAnimation; } - private: - Ref m_SkeletalAnimation; - Ref m_Material = nullptr; std::vector m_Indices; std::vector m_Vertices; diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index eed7afa5..41e3fc6e 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -67,7 +67,8 @@ namespace Nuake aiProcess_Triangulate | aiProcess_GenSmoothNormals | aiProcess_FixInfacingNormals | - aiProcess_CalcTangentSpace; + aiProcess_CalcTangentSpace | + aiProcess_OptimizeGraph; modelDir = absolute ? path + "/../" : FileSystem::Root + path + "/../"; const std::string filePath = absolute ? path : FileSystem::Root + path; diff --git a/Nuake/src/Resource/SkeletalAnimation.cpp b/Nuake/src/Resource/SkeletalAnimation.cpp index c2cfd7ee..80e5d180 100644 --- a/Nuake/src/Resource/SkeletalAnimation.cpp +++ b/Nuake/src/Resource/SkeletalAnimation.cpp @@ -82,6 +82,47 @@ namespace Nuake return glm::scale(glm::mat4(1.0f), finalScale); } + json BoneTransformTrack::Serialize() + { + BEGIN_SERIALIZE(); + for (uint32_t i = 0; i < m_PositionTimestamps.size(); i++) + { + j["m_PositionTimestamps"][i] = m_PositionTimestamps[i]; + } + + for (uint32_t i = 0; i < m_Positions.size(); i++) + { + j["m_Positions"][i] = SERIALIZE_VEC3(m_Positions[i]); + } + + for (uint32_t i = 0; i < m_RotationTimestamps.size(); i++) + { + j["m_RotationTimestamps"][i] = m_RotationTimestamps[i]; + } + + for (uint32_t i = 0; i < m_Rotations.size(); i++) + { + j["m_Rotations"][i] = SERIALIZE_VEC4(m_Rotations[i]); + } + + for (uint32_t i = 0; i < m_ScaleTimestamps.size(); i++) + { + j["m_ScaleTimestamps"][i] = m_ScaleTimestamps[i]; + } + + for (uint32_t i = 0; i < m_Scales.size(); i++) + { + j["m_Scales"][i] = SERIALIZE_VEC3(m_Scales[i]); + } + + END_SERIALIZE(); + } + + bool BoneTransformTrack::Deserialize(const json& j) + { + return true; + } + SkeletalAnimation::SkeletalAnimation(const std::string& name, float duration, float ticksPerSecond) { m_Name = name; @@ -101,4 +142,39 @@ namespace Nuake m_Tracks[name] = BoneTransformTrack(); return m_Tracks[name]; } + + json SkeletalAnimation::Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_VAL(m_Name); + SERIALIZE_VAL(m_Duration); + SERIALIZE_VAL(m_TicksPerSecond); + SERIALIZE_VAL(m_CurrentTime); + SERIALIZE_VAL(m_Loop); + + for (auto& t : m_Tracks) + { + j["Tracks"][t.first] = t.second.Serialize(); + } + + return json(); + } + + bool SkeletalAnimation::Deserialize(const json& j) + { + m_Name = j["m_Name"]; + m_Duration = j["m_Duration"]; + m_TicksPerSecond = j["m_TicksPerSecond"]; + m_CurrentTime = j["m_CurrentTime"]; + m_Loop = j["m_Loop"]; + + for (auto& [trackName, trackData]: j["Tracks"].items()) + { + BoneTransformTrack track; + track.Deserialize(j["Tracks"][trackName]); + m_Tracks[trackName] = std::move(track); + } + return true; + } + } \ No newline at end of file diff --git a/Nuake/src/Resource/SkeletalAnimation.h b/Nuake/src/Resource/SkeletalAnimation.h index 4ea0419f..5e649bd9 100644 --- a/Nuake/src/Resource/SkeletalAnimation.h +++ b/Nuake/src/Resource/SkeletalAnimation.h @@ -2,6 +2,9 @@ #include "src/Core/Core.h" #include +#include "src/Resource/Serializable.h" +#include "src/Resource/Resource.h" + namespace Nuake { struct SkeletonAnimationBoneAnimation @@ -94,9 +97,12 @@ namespace Nuake Matrix4 InterpolatePosition(float time); Matrix4 InterpolateRotation(float time); Matrix4 InterpolateScale(float time); + + json Serialize(); + bool Deserialize(const json& j); }; - class SkeletalAnimation + class SkeletalAnimation : public Resource, ISerializable { private: std::unordered_map m_Tracks; @@ -104,7 +110,7 @@ namespace Nuake float m_Duration; float m_TicksPerSecond; std::string m_Name; - bool m_Loop; + bool m_Loop = false; public: SkeletalAnimation() = default; @@ -114,7 +120,14 @@ namespace Nuake void SetCurrentTime(float time) { - m_CurrentTime = fmod(time, m_Duration); + if (m_Loop) + { + m_CurrentTime = fmod(time, m_Duration); + } + else + { + m_CurrentTime = time; + } } float GetCurrentTime() const { return m_CurrentTime; } @@ -126,5 +139,8 @@ namespace Nuake const std::string& GetName() const { return m_Name; } BoneTransformTrack& GetTrack(const std::string& name); std::unordered_map& GetTracks() { return m_Tracks; } + + json Serialize() override; + bool Deserialize(const json& j) override; }; } diff --git a/Nuake/src/Resource/SkinnedModel.cpp b/Nuake/src/Resource/SkinnedModel.cpp index a6bf06d3..ac71f490 100644 --- a/Nuake/src/Resource/SkinnedModel.cpp +++ b/Nuake/src/Resource/SkinnedModel.cpp @@ -78,7 +78,19 @@ namespace Nuake { j["Meshes"][i] = m_Meshes[i]->Serialize(); } + + j["m_CurrentAnimation"] = m_CurrentAnimation; + j["m_NumAnimation"] = m_NumAnimation; + + uint32_t a = 0; + for (auto& animation : m_Animations) + { + j["m_Animations"][a] = animation->Serialize(); + } + } + + END_SERIALIZE(); } @@ -91,6 +103,10 @@ namespace Nuake ModelLoader loader; auto otherModel = loader.LoadSkinnedModel(j["Path"], false); m_Meshes = otherModel->GetMeshes(); + m_Animations = otherModel->GetAnimations(); + m_SkeletonRoot = otherModel->GetSkeletonRootNode(); + m_NumAnimation = m_Animations.size(); + m_CurrentAnimation = 0; this->Path = j["Path"]; } diff --git a/Nuake/src/Scene/Components/BoneComponent.h b/Nuake/src/Scene/Components/BoneComponent.h index 2bb08862..824484b9 100644 --- a/Nuake/src/Scene/Components/BoneComponent.h +++ b/Nuake/src/Scene/Components/BoneComponent.h @@ -1,5 +1,6 @@ #pragma once #include "src/Core/Core.h" +#include "src/Resource/Serializable.h" namespace Nuake @@ -11,5 +12,19 @@ namespace Nuake ~BoneComponent() = default; std::string Name; + + json Serialize() + { + BEGIN_SERIALIZE(); + SERIALIZE_VAL(Name); + END_SERIALIZE(); + } + + bool Deserialize(const json& j) + { + Name = j["Name"]; + + return true; + } }; } \ No newline at end of file diff --git a/Nuake/src/Scene/Entities/Entity.cpp b/Nuake/src/Scene/Entities/Entity.cpp index 2e1b4928..3b6f7c25 100644 --- a/Nuake/src/Scene/Entities/Entity.cpp +++ b/Nuake/src/Scene/Entities/Entity.cpp @@ -16,6 +16,8 @@ #include "src/Scene/Components/CapsuleColliderComponent.h" #include "src/Scene/Components/SpriteComponent.h" #include "src/Scene/Components/ParticleEmitterComponent.h" +#include "src/Scene/Components/BoneComponent.h" +#include "src/Scene/Components/SkinnedModelComponent.h" namespace Nuake { @@ -69,7 +71,10 @@ namespace Nuake SERIALIZE_OBJECT_REF_LBL("QuakeMapComponent", GetComponent()) if (HasComponent()) SERIALIZE_OBJECT_REF_LBL("RigidBodyComponent", GetComponent()) - + if (HasComponent()) + SERIALIZE_OBJECT_REF_LBL("SkinnedModelComponent", GetComponent()) + if (HasComponent()) + SERIALIZE_OBJECT_REF_LBL("BoneComponent", GetComponent()) END_SERIALIZE(); } @@ -98,6 +103,8 @@ namespace Nuake DESERIALIZE_COMPONENT(SphereColliderComponent) DESERIALIZE_COMPONENT(RigidBodyComponent) DESERIALIZE_COMPONENT(BSPBrushComponent) + DESERIALIZE_COMPONENT(BoneComponent) + DESERIALIZE_COMPONENT(SkinnedModelComponent) return true; } diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index 7c934f70..9242115d 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -30,11 +30,14 @@ namespace Nuake } Ref animation = model->GetCurrentAnimation(); - float newAnimationTime = animation->GetCurrentTime() + (ts * animation->GetTicksPerSecond()); - animation->SetCurrentTime(newAnimationTime); + if (animation && model->IsPlaying) + { + float newAnimationTime = animation->GetCurrentTime() + (ts * animation->GetTicksPerSecond()); + animation->SetCurrentTime(newAnimationTime); - auto& rootBone = model->GetSkeletonRootNode(); - UpdateBonePositionTraversal(rootBone, animation, animation->GetCurrentTime()); + auto& rootBone = model->GetSkeletonRootNode(); + UpdateBonePositionTraversal(rootBone, animation, animation->GetCurrentTime()); + } } } From 0fcca4325f13e00f00889697ac4314b9ae8e2593 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Wed, 6 Sep 2023 20:20:43 -0400 Subject: [PATCH 18/25] Transform Optimization --- Nuake/src/Scene/Systems/AnimationSystem.cpp | 1 + Nuake/src/Scene/Systems/TransformSystem.cpp | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index 9242115d..675e92f3 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -67,6 +67,7 @@ namespace Nuake transformComponent.SetLocalRotation(localRotation); transformComponent.SetLocalScale(localScale); transformComponent.SetLocalTransform(finalTransform); + transformComponent.Dirty = false; } for (auto& childBone : bone.Children) diff --git a/Nuake/src/Scene/Systems/TransformSystem.cpp b/Nuake/src/Scene/Systems/TransformSystem.cpp index 8569987b..9986e892 100644 --- a/Nuake/src/Scene/Systems/TransformSystem.cpp +++ b/Nuake/src/Scene/Systems/TransformSystem.cpp @@ -78,20 +78,33 @@ namespace Nuake Quat globalOrientation = transform.GetLocalRotation(); Vector3 globalScale = transform.GetLocalScale(); +#ifndef FRAME_PERFECT_TRANSFORM ParentComponent parentComponent = currentParent.GetComponent(); - while (parentComponent.HasParent) + if (parentComponent.HasParent) { TransformComponent& transformComponent = parentComponent.Parent.GetComponent(); - globalPosition = transformComponent.GetLocalPosition() + (globalPosition); + globalPosition = transformComponent.GetGlobalPosition() + (globalPosition); + globalScale *= transformComponent.GetGlobalScale(); + globalOrientation = transformComponent.GetGlobalRotation() * globalOrientation; + globalTransform = transformComponent.GetGlobalTransform() * globalTransform; + } +#else + while (parentComponent.HasParent) + { + TransformComponent& transformComponent = parentComponent.Parent.GetComponent(); + + globalPosition = transformComponent.GetLocalPosition() + (globalPosition); + globalScale *= transformComponent.GetLocalScale(); globalOrientation = transformComponent.GetLocalRotation() * globalOrientation; globalTransform = transformComponent.GetLocalTransform() * globalTransform; - + NameComponent& nameComponent = parentComponent.Parent.GetComponent(); parentComponent = parentComponent.Parent.GetComponent(); } +#endif // FRAME_PERFECT_TRANSFORM transform.SetGlobalPosition(globalPosition); transform.SetGlobalRotation(globalOrientation); From 97a477ac20b4c68cdc987394eae486fd3e8ac87f Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 7 Sep 2023 08:31:18 -0400 Subject: [PATCH 19/25] Bumped assimp --- Nuake/dependencies/assimp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Nuake/dependencies/assimp b/Nuake/dependencies/assimp index 199aa5dd..9519a62d 160000 --- a/Nuake/dependencies/assimp +++ b/Nuake/dependencies/assimp @@ -1 +1 @@ -Subproject commit 199aa5dd663402d4d3461876c9846c45b616699d +Subproject commit 9519a62dd20799c5493c638d1ef5a6f484e5faf1 From 6a73249da7313e1ad37cbd4649c11d54ce84a0fb Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 7 Sep 2023 20:50:50 -0400 Subject: [PATCH 20/25] Added toggle for SSAO --- Editor/src/Windows/EditorInterface.cpp | 15 +++++++++++++++ Nuake/src/Rendering/PostFX/SSAO.cpp | 10 ++++++++++ Nuake/src/Rendering/PostFX/SSAO.h | 1 + Nuake/src/Rendering/SceneRenderer.cpp | 11 +++++++++-- 4 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index c4e184ad..481e5004 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -761,6 +761,21 @@ namespace Nuake { ImGui::TableSetupColumn("set", 0, 0.6); ImGui::TableSetupColumn("reset", 0, 0.1); + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("SSAO"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##SSAOEnabled", &env->SSAOEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSAO = ICON_FA_UNDO + std::string("##resetSSAO"); + if (ImGui::Button(resetSSAO.c_str())) env->SSAOEnabled = false; + ImGui::PopStyleColor(); + } ImGui::TableNextColumn(); { // Title diff --git a/Nuake/src/Rendering/PostFX/SSAO.cpp b/Nuake/src/Rendering/PostFX/SSAO.cpp index 757f0f5b..5b7f7c7b 100644 --- a/Nuake/src/Rendering/PostFX/SSAO.cpp +++ b/Nuake/src/Rendering/PostFX/SSAO.cpp @@ -40,6 +40,16 @@ namespace Nuake _ssaoBlurFramebuffer->QueueResize(size); } + void SSAO::Clear() + { + _ssaoBlurFramebuffer->Bind(); + { + RenderCommand::SetClearColor({ 1, 1, 1, 1}); + _ssaoBlurFramebuffer->Clear(); + } + _ssaoBlurFramebuffer->Unbind(); + } + void SSAO::GenerateKernel() { std::uniform_real_distribution randomFloats(0.0, 1.0); // random floats between [0.0, 1.0] diff --git a/Nuake/src/Rendering/PostFX/SSAO.h b/Nuake/src/Rendering/PostFX/SSAO.h index 5c37cc4a..d3737143 100644 --- a/Nuake/src/Rendering/PostFX/SSAO.h +++ b/Nuake/src/Rendering/PostFX/SSAO.h @@ -33,6 +33,7 @@ namespace Nuake float Falloff = 0.002f; float Strength = 0.2f; void Resize(const Vector2& size); + void Clear(); SSAO(); void Draw(FrameBuffer* gBuffer, const Matrix4& projection, const Matrix4& view); Ref GetOuput() const; diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 62760762..01b75a21 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -56,8 +56,15 @@ namespace Nuake // SSAO const auto& sceneEnv = scene.GetEnvironment(); - sceneEnv->mSSAO->Resize(framebuffer.GetSize()); - sceneEnv->mSSAO->Draw(mGBuffer.get(), mProjection, mView); + if (sceneEnv->SSAOEnabled) + { + sceneEnv->mSSAO->Resize(framebuffer.GetSize()); + sceneEnv->mSSAO->Draw(mGBuffer.get(), mProjection, mView); + } + else + { + sceneEnv->mSSAO->Clear(); + } mShadingBuffer->QueueResize(framebuffer.GetSize()); ShadingPass(scene); From 9733d90aefd0a6255eb60249bd9010c1298e2803 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 7 Sep 2023 20:51:18 -0400 Subject: [PATCH 21/25] Added toggle for SSR --- Editor/src/Windows/EditorInterface.cpp | 19 ++++++++++-- Nuake/src/Rendering/SceneRenderer.cpp | 42 ++++++++++++++++++-------- Nuake/src/Scene/Lighting/Environment.h | 2 ++ 3 files changed, 48 insertions(+), 15 deletions(-) diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 481e5004..0196ef75 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -867,10 +867,25 @@ namespace Nuake { ImGui::TableSetupColumn("set", 0, 0.6); ImGui::TableSetupColumn("reset", 0, 0.1); - ImGui::TableNextColumn(); - SSR* ssr = scene->m_SceneRenderer->mSSR.get(); { + ImGui::TableNextColumn(); + // Title + ImGui::Text("SSR"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##SSREnabled", &env->SSREnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSR = ICON_FA_UNDO + std::string("##resetSSR"); + if (ImGui::Button(resetSSR.c_str())) env->SSREnabled = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); // Title ImGui::Text("SSR RayStep"); ImGui::TableNextColumn(); diff --git a/Nuake/src/Rendering/SceneRenderer.cpp b/Nuake/src/Rendering/SceneRenderer.cpp index 01b75a21..56bf2269 100644 --- a/Nuake/src/Rendering/SceneRenderer.cpp +++ b/Nuake/src/Rendering/SceneRenderer.cpp @@ -76,7 +76,7 @@ namespace Nuake sceneEnv->mBloom->Resize(framebuffer.GetSize()); sceneEnv->mBloom->Draw(); - finalOutput = scene.GetEnvironment()->mBloom->GetOutput(); + finalOutput = sceneEnv->mBloom->GetOutput(); } const auto view = scene.m_Registry.view(); @@ -88,7 +88,7 @@ namespace Nuake lightList.push_back(lc); } - if (scene.GetEnvironment()->VolumetricEnabled) + if (sceneEnv->VolumetricEnabled) { sceneEnv->mVolumetric->Resize(framebuffer.GetSize()); sceneEnv->mVolumetric->SetDepth(mGBuffer->GetTexture(GL_DEPTH_ATTACHMENT).get()); @@ -139,20 +139,36 @@ namespace Nuake } mToneMapBuffer->Unbind(); - mSSR->Resize(framebuffer.GetSize()); - mSSR->Draw(mGBuffer.get(), framebuffer.GetTexture(), mView, mProjection, scene.GetCurrentCamera()); - - framebuffer.Bind(); + if (sceneEnv->SSREnabled) { - RenderCommand::Clear(); - Shader* shader = ShaderManager::GetShader("resources/Shaders/combine.shader"); - shader->Bind(); + mSSR->Resize(framebuffer.GetSize()); + mSSR->Draw(mGBuffer.get(), framebuffer.GetTexture(), mView, mProjection, scene.GetCurrentCamera()); - shader->SetUniformTex("u_Source", mToneMapBuffer->GetTexture().get(), 0); - shader->SetUniformTex("u_Source2", mSSR->OutputFramebuffer->GetTexture().get(), 1); - Renderer::DrawQuad(); + framebuffer.Bind(); + { + RenderCommand::Clear(); + Shader* shader = ShaderManager::GetShader("resources/Shaders/combine.shader"); + shader->Bind(); + + shader->SetUniformTex("u_Source", mToneMapBuffer->GetTexture().get(), 0); + shader->SetUniformTex("u_Source2", mSSR->OutputFramebuffer->GetTexture().get(), 1); + Renderer::DrawQuad(); + } + framebuffer.Unbind(); + } + else + { + framebuffer.Bind(); + { + RenderCommand::Clear(); + Shader* shader = ShaderManager::GetShader("resources/Shaders/copy.shader"); + shader->Bind(); + + shader->SetUniformTex("u_Source", mToneMapBuffer->GetTexture().get(), 0); + Renderer::DrawQuad(); + } + framebuffer.Unbind(); } - framebuffer.Unbind(); RenderCommand::Enable(RendererEnum::DEPTH_TEST); Renderer::EndDraw(); diff --git a/Nuake/src/Scene/Lighting/Environment.h b/Nuake/src/Scene/Lighting/Environment.h index 33918997..55e41f07 100644 --- a/Nuake/src/Scene/Lighting/Environment.h +++ b/Nuake/src/Scene/Lighting/Environment.h @@ -42,6 +42,8 @@ namespace Nuake bool SSAOEnabled = true; Scope mSSAO; + bool SSREnabled = false; + Vector3 ClearColor; glm::vec4 m_AmbientColor; From fb9179dde2f9d5c449aab8751aea94f4a16b66e3 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 7 Sep 2023 20:51:28 -0400 Subject: [PATCH 22/25] Fixed updated assimp --- Nuake/dependencies/assimp_p5.lua | 3 ++- Nuake/dependencies/build/assimp/config.h | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Nuake/dependencies/assimp_p5.lua b/Nuake/dependencies/assimp_p5.lua index 0d1a386e..c87cc532 100644 --- a/Nuake/dependencies/assimp_p5.lua +++ b/Nuake/dependencies/assimp_p5.lua @@ -96,7 +96,8 @@ project 'assimp' 'ASSIMP_BUILD_NO_TERRAGEN_IMPORTER', 'ASSIMP_BUILD_NO_X_IMPORTER', 'ASSIMP_BUILD_NO_X3D_IMPORTER', - 'ASSIMP_BUILD_NO_XGL_IMPORTER' + 'ASSIMP_BUILD_NO_XGL_IMPORTER', + 'ASSIMP_BUILD_NO_IQM_IMPORTER' } -- Exporters defines { diff --git a/Nuake/dependencies/build/assimp/config.h b/Nuake/dependencies/build/assimp/config.h index c7ba9c08..63e664ae 100644 --- a/Nuake/dependencies/build/assimp/config.h +++ b/Nuake/dependencies/build/assimp/config.h @@ -547,6 +547,15 @@ enum aiComponent // Various stuff to fine-tune the behaviour of specific importer plugins. // ########################################################################### +// --------------------------------------------------------------------------- +/** @brief Importers which parse JSON may use this to obtain a pointer to a + * rapidjson::IRemoteSchemaDocumentProvider. + * + * The default value is nullptr + * Property type: void* + */ +#define AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER \ + "IMPORT_SCHEMA_DOCUMENT_PROVIDER" // --------------------------------------------------------------------------- /** @brief Set whether the fbx importer will merge all geometry layers present @@ -682,6 +691,15 @@ enum aiComponent #define AI_CONFIG_FBX_CONVERT_TO_M \ "AI_CONFIG_FBX_CONVERT_TO_M" + // --------------------------------------------------------------------------- + /** @brief Will enable the skeleton struct to store bone data. + * + * This will decouple the bone coupling to the mesh. This feature is + * experimental. + */ +#define AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER \ + "AI_CONFIG_FBX_USE_SKELETON_BONE_CONTAINER" + // --------------------------------------------------------------------------- /** @brief Set the vertex animation keyframe to be imported * From 36646a099042188a4cbc434b0d79321ef5d048a3 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Thu, 7 Sep 2023 20:52:05 -0400 Subject: [PATCH 23/25] 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) { From 190c36b910a7ab236a9328543ff4d69770189140 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Fri, 8 Sep 2023 00:33:57 -0400 Subject: [PATCH 24/25] Crude optimizations From testing with model of around 50 bones, I could get 64+ animated models on the screen with 150fps+ --- Nuake/src/Resource/SkeletonNode.h | 1 + Nuake/src/Scene/Components/SkinnedModelComponent.h | 6 +++++- Nuake/src/Scene/Scene.cpp | 6 +++++- Nuake/src/Scene/Systems/AnimationSystem.cpp | 9 ++++++--- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Nuake/src/Resource/SkeletonNode.h b/Nuake/src/Resource/SkeletonNode.h index 3cd7e5e9..32b54a3b 100644 --- a/Nuake/src/Resource/SkeletonNode.h +++ b/Nuake/src/Resource/SkeletonNode.h @@ -13,5 +13,6 @@ namespace Nuake std::vector Children; Matrix4 FinalTransform = Matrix4(1.0f); int32_t Id = -1; + int32_t EntityHandle = 0; }; } \ No newline at end of file diff --git a/Nuake/src/Scene/Components/SkinnedModelComponent.h b/Nuake/src/Scene/Components/SkinnedModelComponent.h index e536275f..0e6bdb53 100644 --- a/Nuake/src/Scene/Components/SkinnedModelComponent.h +++ b/Nuake/src/Scene/Components/SkinnedModelComponent.h @@ -24,7 +24,11 @@ namespace Nuake { BEGIN_SERIALIZE(); SERIALIZE_VAL(ModelPath); - SERIALIZE_OBJECT(ModelResource); + + if (ModelResource) + { + SERIALIZE_OBJECT(ModelResource); + } END_SERIALIZE(); } diff --git a/Nuake/src/Scene/Scene.cpp b/Nuake/src/Scene/Scene.cpp index 8ba2d6ec..59fb078d 100644 --- a/Nuake/src/Scene/Scene.cpp +++ b/Nuake/src/Scene/Scene.cpp @@ -484,9 +484,11 @@ namespace Nuake auto& skeletonRoot = component.ModelResource->GetSkeletonRootNode(); Entity skeletonRootEntity = CreateEntity(skeletonRoot.Name); - skeletonRootEntity.AddComponent(); + skeletonRootEntity.AddComponent().Name = skeletonRoot.Name; + skeletonRoot.EntityHandle = skeletonRootEntity.GetHandle(); entity.AddChild(skeletonRootEntity); + Vector3 bonePosition; Quat boneRotation; Vector3 boneScale; @@ -509,6 +511,8 @@ namespace Nuake boneEntity.AddComponent(); entity.AddChild(boneEntity); + c.EntityHandle = boneEntity.GetHandle(); + Vector3 bonePosition; Quat boneRotation; Vector3 boneScale; diff --git a/Nuake/src/Scene/Systems/AnimationSystem.cpp b/Nuake/src/Scene/Systems/AnimationSystem.cpp index a3a54f18..75e8a4a2 100644 --- a/Nuake/src/Scene/Systems/AnimationSystem.cpp +++ b/Nuake/src/Scene/Systems/AnimationSystem.cpp @@ -50,12 +50,14 @@ namespace Nuake auto& animationTrack = animation->GetTrack(boneName); Entity& boneEntity = m_Scene->GetEntity(boneName); - if (boneEntity.GetHandle() != -1) + Entity& boneEnt = Entity{ (entt::entity)bone.EntityHandle, m_Scene }; + ///assert(boneEnt.GetHandle() == boneEntity.GetHandle()); + if (boneEnt.GetHandle() != 0) { - auto& transformComponent = boneEntity.GetComponent(); + auto& transformComponent = boneEnt.GetComponent(); bone.FinalTransform = transformComponent.GetGlobalTransform() * bone.Offset; - if (!animationTrack.IsEmpty()) + //if (!animationTrack.IsEmpty()) { // Get Update transform animationTrack.Update(time); @@ -74,6 +76,7 @@ namespace Nuake transformComponent.Dirty = false; } } + for (auto& childBone : bone.Children) { UpdateBonePositionTraversal(childBone, animation, time); From a5cf290f4c575ad5ea97588737f1bb646b428c6c Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Fri, 8 Sep 2023 17:04:52 -0400 Subject: [PATCH 25/25] SetName of materials --- Nuake/src/Resource/ModelLoader.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Nuake/src/Resource/ModelLoader.cpp b/Nuake/src/Resource/ModelLoader.cpp index 41e3fc6e..d9ab3048 100644 --- a/Nuake/src/Resource/ModelLoader.cpp +++ b/Nuake/src/Resource/ModelLoader.cpp @@ -461,8 +461,11 @@ namespace Nuake return nullptr; aiMaterial* materialNode = scene->mMaterials[mesh->mMaterialIndex]; - Ref material = CreateRef(); + + aiString materialName; + materialNode->Get(AI_MATKEY_NAME, materialName); + material->SetName(std::string(materialName.C_Str())); aiString str; if (materialNode->GetTextureCount(aiTextureType_DIFFUSE) > 0)