From 8ea9cf5bef72d4c1a0ffb40ec30d24df03f8b4a2 Mon Sep 17 00:00:00 2001 From: Anish Bhobe Date: Fri, 19 Jul 2024 21:14:24 +0200 Subject: [PATCH] Fixed node orientations. --- aster/config.h | 1 + aster/constants.h | 1 + samples/03_model_render/model_loader.cpp | 83 +++++++++++++++-- samples/03_model_render/model_loader.h | 88 +++++++++++++++++-- samples/03_model_render/model_render.cpp | 4 + samples/03_model_render/pipeline_utils.cpp | 2 +- .../shader/bindless_structs.hlsli | 14 ++- samples/03_model_render/shader/model.vs.hlsl | 18 ++-- 8 files changed, 185 insertions(+), 26 deletions(-) diff --git a/aster/config.h b/aster/config.h index 1c37123..7c912f0 100644 --- a/aster/config.h +++ b/aster/config.h @@ -7,6 +7,7 @@ #define GLM_FORCE_RADIANS #define GLM_FORCE_DEPTH_ZERO_TO_ONE +#define GLM_FORCE_QUATERNIONS_XYZW #define GLFW_INCLUDE_VULKAN #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 diff --git a/aster/constants.h b/aster/constants.h index 0ba78fd..af7e39f 100644 --- a/aster/constants.h +++ b/aster/constants.h @@ -87,6 +87,7 @@ using glm::ivec4; using glm::vec2; using glm::vec3; using glm::vec4; +using glm::quat; using glm::mat2; using glm::mat3; diff --git a/samples/03_model_render/model_loader.cpp b/samples/03_model_render/model_loader.cpp index 93b5757..4a88e45 100644 --- a/samples/03_model_render/model_loader.cpp +++ b/samples/03_model_render/model_loader.cpp @@ -18,6 +18,7 @@ #include "image.h" #include "render_resource_manager.h" +#include #include vec4 @@ -297,14 +298,19 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) eastl::vector meshPrimitives; meshPrimitives.reserve(model.meshes.size()); + // Offset, Count + eastl::vector> meshPrimRanges; + meshPrimRanges.reserve(model.meshes.size()); + u32 vertexOffset = 0; - i32 normalOffset = 0; - i32 texCoord0Offset = 0; - i32 color0Offset = 0; + u32 normalOffset = 0; + u32 texCoord0Offset = 0; + u32 color0Offset = 0; u32 indexOffset = 0; for (auto &mesh : model.meshes) { + meshPrimRanges.emplace_back(meshPrimitives.size(), mesh.primitives.size()); for (auto &prim : mesh.primitives) { u32 vertexCount = 0; @@ -486,11 +492,13 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) meshPrimitives.push_back({ .m_VertexOffset = vertexOffset, - .m_NormalOffset = normalCount > 0 ? normalOffset : -1, - .m_TexCoord0Offset = texCoord0Count > 0 ? texCoord0Offset : -1, + .m_NormalOffset = normalCount > 0 ? Cast(normalOffset) : -1, + .m_TexCoord0Offset = texCoord0Count > 0 ? Cast(texCoord0Offset) : -1, + // TODO: Color offset .m_FirstIndex = indexOffset, .m_IndexCount = indexCount, .m_MaterialIdx = prim.material, + .m_TransformIdx = -1, }); vertexOffset += vertexCount; @@ -508,14 +516,64 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) { if (model.defaultScene >= 0) { + eastl::function processNode = [&processNode, &model, &nodes, &meshPrimRanges, &meshPrimitives](i32 idx, i32 parent) -> void { + INFO("parent {} -> idx {}", parent, idx); + const auto *node = &model.nodes[idx]; + + vec3 nodeTranslation = vec3{0.0f}; + quat nodeRotation = quat{1.0f, 0.0f, 0.0f, 0.0f}; + vec3 nodeScale = vec3{1.0f}; + mat4 nodeMatrix = mat4{1.0f}; + if (node->translation.size() == 3) + { + nodeTranslation = glm::make_vec3(node->translation.data()); + } + if (node->rotation.size() == 4) + { + nodeRotation = glm::make_quat(node->rotation.data()); + } + if (node->scale.size() == 3) + { + nodeScale = glm::make_vec3(node->scale.data()); + } + if (node->matrix.size() == 16) + { + nodeMatrix = glm::make_mat4(node->matrix.data()); + } + const mat4 transform = + translate(mat4(1.0f), nodeTranslation) * mat4_cast(nodeRotation) * scale(mat4(1.0f), nodeScale) * nodeMatrix; + + const u32 nodeArrayIndex = nodes.Add(transform, parent); + if (node->mesh >= 0) + { + auto [start, count] = meshPrimRanges[node->mesh]; + const auto end = start + count; + for (usize i = start; i != end; ++i) + { + meshPrimitives[i].m_TransformIdx = nodeArrayIndex; + } + } + + for (const i32 child : node->children) + { + processNode(child, idx); + } + }; auto *scene = &model.scenes[model.defaultScene]; - for (int rootNodeIdx : scene->nodes) + for (i32 rootNodeIdx : scene->nodes) { - auto *node = &model.nodes[rootNodeIdx]; + processNode(rootNodeIdx, -1); } } } + nodes.Update(); + + StorageBuffer nodeBuffer; + nodeBuffer.Init(pDevice, nodes.GetGlobalTransformByteSize(), true); + nodeBuffer.Write(pDevice, 0, nodes.GetGlobalTransformByteSize(), nodes.GetGlobalTransformPtr()); + BufferHandle nodeHandle = m_ResourceManager->Commit(&nodeBuffer); + #pragma region Staging / Transfer / Uploads StorageBuffer positionBuffer; positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false); @@ -603,14 +661,17 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) buffer.Destroy(pDevice); } + nodes.Update(); + return Model{m_ResourceManager, std::move(textureHandles), std::move(nodes), materialsHandle, positionBufferHandle, normalBufferHandle, - texCoord0BufferHandle, color0Handle, indexBuffer, meshPrimitives}; + texCoord0BufferHandle, color0Handle, indexBuffer, meshPrimitives, nodeHandle}; } Model::Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, Nodes &&nodes, BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, - BufferHandle uv0Handle, BufferHandle vertexColor, const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives) + BufferHandle uv0Handle, BufferHandle vertexColor, const IndexBuffer &indexBuffer, + const eastl::vector &meshPrimitives, BufferHandle nodeHandle) : m_ResourceManager(resourceManager) , m_TextureHandles(std::move(textureHandles)) , m_Nodes(std::move(nodes)) @@ -619,6 +680,7 @@ Model::Model(GpuResourceManager *resourceManager, eastl::vector & , m_NormalHandle(normalHandle) , m_TexCoord0Handle(uv0Handle) , m_VertexColorHandle(vertexColor) + , m_NodeHandle(nodeHandle) , m_IndexBuffer(indexBuffer) , m_MeshPrimitives(meshPrimitives) { @@ -632,6 +694,7 @@ Model::Model(Model &&other) noexcept , m_NormalHandle(other.m_NormalHandle) , m_TexCoord0Handle(other.m_TexCoord0Handle) , m_VertexColorHandle(other.m_VertexColorHandle) + , m_NodeHandle(other.m_NodeHandle) , m_IndexBuffer(other.m_IndexBuffer) , m_MeshPrimitives(std::move(other.m_MeshPrimitives)) { @@ -649,6 +712,7 @@ Model::operator=(Model &&other) noexcept m_NormalHandle = other.m_NormalHandle; m_TexCoord0Handle = other.m_TexCoord0Handle; m_VertexColorHandle = other.m_VertexColorHandle; + m_NodeHandle = std::move(other.m_NodeHandle); m_IndexBuffer = other.m_IndexBuffer; m_MeshPrimitives = std::move(other.m_MeshPrimitives); return *this; @@ -660,6 +724,7 @@ Model::~Model() return; m_IndexBuffer.Destroy(m_ResourceManager->m_Device); + m_ResourceManager->Release(m_NodeHandle); m_ResourceManager->Release(m_VertexColorHandle); m_ResourceManager->Release(m_VertexPositionHandle); m_ResourceManager->Release(m_NormalHandle); diff --git a/samples/03_model_render/model_loader.h b/samples/03_model_render/model_loader.h index 3893111..c43ba58 100644 --- a/samples/03_model_render/model_loader.h +++ b/samples/03_model_render/model_loader.h @@ -27,18 +27,59 @@ struct MeshPrimitive u32 m_FirstIndex; u32 m_IndexCount; i32 m_MaterialIdx; // <0 for invalid + i32 m_TransformIdx; }; struct Nodes { eastl::vector m_Transforms; - eastl::vector m_Parents; + eastl::vector m_GlobalTransforms; + eastl::vector m_Parents_; + bool m_Dirty = true; - void + constexpr static u32 ROOT_BIT = 1u << 31; + constexpr static u32 DIRTY_BIT = 1u << 30; + constexpr static u32 PARENT_MASK = ~(ROOT_BIT | DIRTY_BIT); + + u32 Add(const mat4& transform, i32 parent = -1) { + m_Dirty = true; + u32 index = Count(); m_Transforms.push_back(transform); - m_Parents.push_back(parent); + m_GlobalTransforms.push_back(transform); + const u32 parentVal = (parent < 0 ? ROOT_BIT : parent & PARENT_MASK) | DIRTY_BIT; + m_Parents_.push_back(parentVal); + + return index; + } + + [[nodiscard]] const mat4 & + Get(const u32 index) const + { + return m_Transforms[index]; + } + + void + Set(const u32 index, const mat4 &transform) + { + m_Dirty = true; + m_Transforms[index] = transform; + m_Parents_[index] |= DIRTY_BIT; + } + + [[nodiscard]] const mat4 & + operator[](const u32 index) const + { + return m_Transforms[index]; + } + + [[nodiscard]] mat4 & + operator[](const u32 index) + { + m_Dirty = true; + m_Parents_[index] |= DIRTY_BIT; + return m_Transforms[index]; } [[nodiscard]] u32 @@ -48,16 +89,48 @@ struct Nodes } [[nodiscard]] usize - GetTransformByteSize() const + GetGlobalTransformByteSize() const { return m_Transforms.size() * sizeof m_Transforms[0]; } [[nodiscard]] const mat4 * - GetTransformPtr() const + GetGlobalTransformPtr() const { return m_Transforms.data(); } + + void + Update() + { + if (!m_Dirty) + return; + + auto transformIter = m_Transforms.begin(); + auto globalTransformIter = m_GlobalTransforms.begin(); + auto parentIter = m_Parents_.begin(); + const auto parentEnd = m_Parents_.end(); + + while (parentIter != parentEnd) + { + if (!(*parentIter & ROOT_BIT) && *parentIter & DIRTY_BIT) + { + u32 parent = *parentIter & PARENT_MASK; + *globalTransformIter = m_GlobalTransforms[parent] * *transformIter; + } + else + { + *globalTransformIter = *transformIter; + } + *parentIter &= ~DIRTY_BIT; + + ++parentIter; + ++globalTransformIter; + ++transformIter; + } + + m_Dirty = false; + } }; struct Material @@ -85,13 +158,14 @@ struct Model BufferHandle m_NormalHandle; BufferHandle m_TexCoord0Handle; BufferHandle m_VertexColorHandle; + BufferHandle m_NodeHandle; IndexBuffer m_IndexBuffer; eastl::vector m_MeshPrimitives; Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, Nodes&& nodes, BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, BufferHandle vertexColor, - const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives); + const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives, BufferHandle nodeHandle); Model(Model &&other) noexcept; Model &operator=(Model &&other) noexcept; @@ -103,7 +177,7 @@ struct Model struct ModelLoader { - GpuResourceManager *const m_ResourceManager; + GpuResourceManager *m_ResourceManager; vk::CommandPool m_CommandPool; vk::CommandBuffer m_CommandBuffer; vk::Queue m_TransferQueue; diff --git a/samples/03_model_render/model_render.cpp b/samples/03_model_render/model_render.cpp index 27055be..d3b90e5 100644 --- a/samples/03_model_render/model_render.cpp +++ b/samples/03_model_render/model_render.cpp @@ -220,6 +220,7 @@ main(int, char **) BufferHandle m_Color; BufferHandle m_UvBuffer; BufferHandle m_Materials; + BufferHandle m_Nodes; }; ModelData modelData = { @@ -227,6 +228,7 @@ main(int, char **) .m_Color = model.m_VertexColorHandle, .m_UvBuffer = model.m_TexCoord0Handle, .m_Materials = model.m_MaterialsHandle, + .m_Nodes = model.m_NodeHandle, }; INFO("Starting loop"); @@ -299,6 +301,8 @@ main(int, char **) { cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData, sizeof prim.m_MaterialIdx, &prim.m_MaterialIdx); + cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData + sizeof prim.m_MaterialIdx, + sizeof prim.m_TransformIdx, &prim.m_TransformIdx); cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, Cast(prim.m_VertexOffset), 0); } diff --git a/samples/03_model_render/pipeline_utils.cpp b/samples/03_model_render/pipeline_utils.cpp index 3ffce70..250a489 100644 --- a/samples/03_model_render/pipeline_utils.cpp +++ b/samples/03_model_render/pipeline_utils.cpp @@ -58,7 +58,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain, const GpuResour vk::PushConstantRange pushConstantRange = { .stageFlags = vk::ShaderStageFlagBits::eAll, .offset = 0, - .size = 20, + .size = 28, }; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { diff --git a/samples/03_model_render/shader/bindless_structs.hlsli b/samples/03_model_render/shader/bindless_structs.hlsli index 89cda7e..c426566 100644 --- a/samples/03_model_render/shader/bindless_structs.hlsli +++ b/samples/03_model_render/shader/bindless_structs.hlsli @@ -4,6 +4,11 @@ typedef float2 UVData; typedef float4 NormalData; typedef float4 ColorData; +struct TransformData +{ + float4x4 transform; +}; + struct MaterialData { float m_AlbedoFactor[4]; @@ -23,14 +28,16 @@ struct Block uint colorHandle; uint uvBufferHandle; uint materialBufferHandle; + uint nodeBufferHandle; int m_MaterialIdx; + uint m_NodeIdx; }; struct Camera { - row_major float4x4 model; - row_major float4x4 view; - row_major float4x4 proj; + float4x4 model; + float4x4 view; + float4x4 proj; }; #define INVALID_HANDLE 0xFFFFFFFF @@ -40,6 +47,7 @@ struct Camera [[vk::binding(0, 0)]] StructuredBuffer normalBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer colorBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer materialsBuffer[]; +[[vk::binding(0, 0)]] StructuredBuffer nodeBuffer[]; [[vk::binding(1, 0)]] Texture2D textures[]; [[vk::binding(1, 0)]] SamplerState immutableSamplers[]; diff --git a/samples/03_model_render/shader/model.vs.hlsl b/samples/03_model_render/shader/model.vs.hlsl index 9923a0d..ffea9ec 100644 --- a/samples/03_model_render/shader/model.vs.hlsl +++ b/samples/03_model_render/shader/model.vs.hlsl @@ -10,7 +10,6 @@ struct VS_Output float4 outPosition : POSITION; float4 outColor : COLOR0; float2 outUV : TEXCOORD0; - float outMetal : METAL; float4 position : SV_Position; }; @@ -26,9 +25,9 @@ float2 GetUV(uint bufferId, uint vertexIdx) } } -float3 GetPosition(uint bufferId, uint vertexIdx) +float4 GetPosition(uint bufferId, uint vertexIdx) { - return vertexBuffer[bufferId][vertexIdx].xyz; + return float4(vertexBuffer[bufferId][vertexIdx].xyz, 1.0f); } float4 GetColor(uint bufferId, uint vertexIdx) @@ -36,13 +35,20 @@ float4 GetColor(uint bufferId, uint vertexIdx) return (bufferId != INVALID_HANDLE) ? colorBuffer[bufferId][vertexIdx] : float4(1.0f, 0.0f, 1.0f, 1.0f); } +float4x4 GetModel(uint bufferId, uint index) +{ + return nodeBuffer[bufferId][index].transform; +} + VS_Output main(VS_Input stage_input) { VS_Output output; - output.outMetal = materialsBuffer[pcb.materialBufferHandle][pcb.m_MaterialIdx].m_MetalFactor; - output.outPosition = float4(GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex), 1.0f); + output.outPosition = GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex); output.outUV = GetUV(pcb.uvBufferHandle, stage_input.vertexIndex); output.outColor = GetColor(pcb.colorHandle, stage_input.vertexIndex); - output.position = mul(float4(GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex), 1.0f), mul(camera.model, mul(camera.view, camera.proj))); + + float4 globalPosition = mul(camera.model, mul(GetModel(pcb.nodeBufferHandle, pcb.m_NodeIdx), GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex))); + float4 clipSpace = mul(camera.view, globalPosition); + output.position = mul(camera.proj, clipSpace); return output; }