diff --git a/samples/03_model_render/model/BoxVertexColors.glb b/samples/03_model_render/model/BoxVertexColors.glb new file mode 100644 index 0000000..c6394ac --- /dev/null +++ b/samples/03_model_render/model/BoxVertexColors.glb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9c48227f33b0ba2fbcf23b98ebf60d1c8ae0c6e6c5281e0aa3cc58affee10382 +size 1924 diff --git a/samples/03_model_render/model_loader.cpp b/samples/03_model_render/model_loader.cpp index 9dbf2f6..93b5757 100644 --- a/samples/03_model_render/model_loader.cpp +++ b/samples/03_model_render/model_loader.cpp @@ -54,7 +54,7 @@ ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, StagingBuffer *stagingBu usize byteSize = image->image.size(); texture.Init(m_ResourceManager->m_Device, {.width = Cast(image->width), .height = Cast(image->height)}, - vk::Format::eR8G8B8A8Srgb, true, image->name.data()); + vk::Format::eR8G8B8A8Srgb, true, image->name.data()); stagingBuffer->Init(m_ResourceManager->m_Device, byteSize); stagingBuffer->Write(m_ResourceManager->m_Device, 0, byteSize, image->image.data()); @@ -292,6 +292,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) eastl::vector vertexPositions; eastl::vector normalVectors; eastl::vector texCoord0; + eastl::vector color0; eastl::vector indices; eastl::vector meshPrimitives; meshPrimitives.reserve(model.meshes.size()); @@ -299,6 +300,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) u32 vertexOffset = 0; i32 normalOffset = 0; i32 texCoord0Offset = 0; + i32 color0Offset = 0; u32 indexOffset = 0; for (auto &mesh : model.meshes) @@ -307,9 +309,11 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) { u32 vertexCount = 0; u32 indexCount = 0; - i32 normalCount = 0; - i32 texCoord0Count = 0; + u32 normalCount = 0; + u32 texCoord0Count = 0; + u32 color0Count = 0; +#pragma region Position assert(prim.attributes.contains(APosition)); assert(prim.mode == TINYGLTF_MODE_TRIANGLES); { @@ -346,7 +350,8 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) } } } - +#pragma endregion +#pragma region Normal // Normal Coords if (prim.attributes.contains(ANormal)) { @@ -383,7 +388,8 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) } } } - +#pragma endregion +#pragma region UV0 // UV0 if (prim.attributes.contains(ATexCoord0)) { @@ -405,7 +411,38 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) texCoord0.insert(texCoord0.end(), data, data + vertexCount); } } +#pragma endregion +#pragma region Color + if (prim.attributes.contains(AColor0)) + { + tinygltf::Accessor *colorAccessor = &model.accessors[prim.attributes[AColor0]]; + assert(colorAccessor->count <= MaxValue); + + tinygltf::BufferView *colorBufferView = &model.bufferViews[colorAccessor->bufferView]; + tinygltf::Buffer *colorBuffer = &model.buffers[colorBufferView->buffer]; + usize byteOffset = (colorAccessor->byteOffset + colorBufferView->byteOffset); + + color0Count = Cast(colorAccessor->count); + color0.reserve(vertexPositions.size()); + assert(color0Count == vertexCount); + + if (colorAccessor->type == TINYGLTF_TYPE_VEC4) + { + vec4 *data = Recast(colorBuffer->data.data() + byteOffset); + color0.insert(color0.end(), data, data + vertexCount); + } + else if (colorAccessor->type == TINYGLTF_TYPE_VEC3) + { + vec3 *data = Recast(colorBuffer->data.data() + byteOffset); + for (u32 i = 0; i < color0Count; ++i) + { + color0.push_back(vec4(data[i], 1.0f)); + } + } + } +#pragma endregion +#pragma region Indices // Indices if (prim.indices >= 0) { @@ -445,6 +482,7 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) indices.push_back(i); } } +#pragma endregion meshPrimitives.push_back({ .m_VertexOffset = vertexOffset, @@ -459,12 +497,25 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) indexOffset += indexCount; texCoord0Offset += texCoord0Count; normalOffset += normalCount; + color0Offset += color0Count; assert(normalVectors.empty() || normalVectors.size() == vertexPositions.size()); assert(texCoord0.empty() || texCoord0.size() == vertexPositions.size()); } } + Nodes nodes; + { + if (model.defaultScene >= 0) + { + auto *scene = &model.scenes[model.defaultScene]; + for (int rootNodeIdx : scene->nodes) + { + auto *node = &model.nodes[rootNodeIdx]; + } + } + } + #pragma region Staging / Transfer / Uploads StorageBuffer positionBuffer; positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false); @@ -486,41 +537,44 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) texCoord0BufferHandle = m_ResourceManager->Commit(&texCoord0Buffer); } + StorageBuffer color0Buffer; + BufferHandle color0Handle; + if (!color0.empty()) + { + color0Buffer.Init(pDevice, color0.size() * sizeof color0[0], false); + color0Handle = m_ResourceManager->Commit(&color0Buffer); + } + IndexBuffer indexBuffer; indexBuffer.Init(pDevice, indices.size() * sizeof indices[0]); { - vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0}; + auto uploadBufferData = [cmd = this->m_CommandBuffer, &stagingBuffers, pDevice](const Buffer *buffer, void* data) { + vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = buffer->GetSize()}; + StagingBuffer &stagingBuffer = stagingBuffers.push_back(); + stagingBuffer.Init(pDevice, bufferCopy.size); + stagingBuffer.Write(pDevice, 0, bufferCopy.size, data); + cmd.copyBuffer(stagingBuffer.m_Buffer, buffer->m_Buffer, 1, &bufferCopy); + }; - bufferCopy.size = positionBuffer.GetSize(); - StagingBuffer &positionStaging = stagingBuffers.push_back(); - positionStaging.Init(pDevice, bufferCopy.size); - positionStaging.Write(pDevice, 0, bufferCopy.size, vertexPositions.data()); - m_CommandBuffer.copyBuffer(positionStaging.m_Buffer, positionBuffer.m_Buffer, 1, &bufferCopy); + uploadBufferData(&positionBuffer, vertexPositions.data()); if (normalBuffer.IsValid()) { - bufferCopy.size = normalBuffer.GetSize(); - StagingBuffer &normalStaging = stagingBuffers.push_back(); - normalStaging.Init(pDevice, bufferCopy.size); - normalStaging.Write(pDevice, 0, bufferCopy.size, normalVectors.data()); - m_CommandBuffer.copyBuffer(normalStaging.m_Buffer, normalBuffer.m_Buffer, 1, &bufferCopy); + uploadBufferData(&normalBuffer, normalVectors.data()); } if (texCoord0Buffer.IsValid()) { - bufferCopy.size = texCoord0Buffer.GetSize(); - StagingBuffer &textureStaging = stagingBuffers.push_back(); - textureStaging.Init(pDevice, bufferCopy.size); - textureStaging.Write(pDevice, 0, bufferCopy.size, texCoord0.data()); - m_CommandBuffer.copyBuffer(textureStaging.m_Buffer, texCoord0Buffer.m_Buffer, 1, &bufferCopy); + uploadBufferData(&texCoord0Buffer, texCoord0.data()); } - bufferCopy.size = indexBuffer.GetSize(); - StagingBuffer &indexStaging = stagingBuffers.push_back(); - indexStaging.Init(pDevice, bufferCopy.size); - indexStaging.Write(pDevice, 0, bufferCopy.size, indices.data()); - m_CommandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.m_Buffer, 1, &bufferCopy); + if (color0Buffer.IsValid()) + { + uploadBufferData(&color0Buffer, color0.data()); + } + + uploadBufferData(&indexBuffer, indices.data()); } #pragma endregion @@ -549,34 +603,37 @@ ModelLoader::LoadModel(cstr path, cstr name, bool batched) buffer.Destroy(pDevice); } - return Model{m_ResourceManager, std::move(textureHandles), + return Model{m_ResourceManager, std::move(textureHandles), std::move(nodes), materialsHandle, positionBufferHandle, normalBufferHandle, - texCoord0BufferHandle, indexBuffer, meshPrimitives}; + texCoord0BufferHandle, color0Handle, indexBuffer, meshPrimitives}; } -Model::Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, +Model::Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, Nodes &&nodes, BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, - BufferHandle uv0Handle, const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives) + BufferHandle uv0Handle, BufferHandle vertexColor, const IndexBuffer &indexBuffer, const eastl::vector &meshPrimitives) : m_ResourceManager(resourceManager) - , m_TextureHandles(std::move(textureHandles)) - , m_MaterialsHandle(materialsHandle) - , m_VertexPositionHandle(vertexPosHandle) - , m_NormalHandle(normalHandle) - , m_TexCoord0Handle(uv0Handle) - , m_IndexBuffer(indexBuffer) - , m_MeshPrimitives(meshPrimitives) + , m_TextureHandles(std::move(textureHandles)) + , m_Nodes(std::move(nodes)) + , m_MaterialsHandle(materialsHandle) + , m_VertexPositionHandle(vertexPosHandle) + , m_NormalHandle(normalHandle) + , m_TexCoord0Handle(uv0Handle) + , m_VertexColorHandle(vertexColor) + , m_IndexBuffer(indexBuffer) + , m_MeshPrimitives(meshPrimitives) { } Model::Model(Model &&other) noexcept : m_ResourceManager(Take(other.m_ResourceManager)) - , m_TextureHandles(std::move(other.m_TextureHandles)) - , m_MaterialsHandle(other.m_MaterialsHandle) - , m_VertexPositionHandle(other.m_VertexPositionHandle) - , m_NormalHandle(other.m_NormalHandle) - , m_TexCoord0Handle(other.m_TexCoord0Handle) - , m_IndexBuffer(other.m_IndexBuffer) - , m_MeshPrimitives(std::move(other.m_MeshPrimitives)) + , m_TextureHandles(std::move(other.m_TextureHandles)) + , m_MaterialsHandle(other.m_MaterialsHandle) + , m_VertexPositionHandle(other.m_VertexPositionHandle) + , m_NormalHandle(other.m_NormalHandle) + , m_TexCoord0Handle(other.m_TexCoord0Handle) + , m_VertexColorHandle(other.m_VertexColorHandle) + , m_IndexBuffer(other.m_IndexBuffer) + , m_MeshPrimitives(std::move(other.m_MeshPrimitives)) { } @@ -591,6 +648,7 @@ Model::operator=(Model &&other) noexcept m_VertexPositionHandle = other.m_VertexPositionHandle; m_NormalHandle = other.m_NormalHandle; m_TexCoord0Handle = other.m_TexCoord0Handle; + m_VertexColorHandle = other.m_VertexColorHandle; m_IndexBuffer = other.m_IndexBuffer; m_MeshPrimitives = std::move(other.m_MeshPrimitives); return *this; @@ -602,6 +660,7 @@ Model::~Model() return; m_IndexBuffer.Destroy(m_ResourceManager->m_Device); + m_ResourceManager->Release(m_VertexColorHandle); m_ResourceManager->Release(m_VertexPositionHandle); m_ResourceManager->Release(m_NormalHandle); m_ResourceManager->Release(m_TexCoord0Handle); diff --git a/samples/03_model_render/model_loader.h b/samples/03_model_render/model_loader.h index 9437927..3893111 100644 --- a/samples/03_model_render/model_loader.h +++ b/samples/03_model_render/model_loader.h @@ -29,17 +29,48 @@ struct MeshPrimitive i32 m_MaterialIdx; // <0 for invalid }; +struct Nodes +{ + eastl::vector m_Transforms; + eastl::vector m_Parents; + + void + Add(const mat4& transform, i32 parent = -1) + { + m_Transforms.push_back(transform); + m_Parents.push_back(parent); + } + + [[nodiscard]] u32 + Count() const + { + return Cast(m_Transforms.size()); + } + + [[nodiscard]] usize + GetTransformByteSize() const + { + return m_Transforms.size() * sizeof m_Transforms[0]; + } + + [[nodiscard]] const mat4 * + GetTransformPtr() const + { + return m_Transforms.data(); + } +}; + struct Material { - vec4 m_AlbedoFactor; - vec3 m_EmissionFactor; - f32 m_MetalFactor; - f32 m_RoughFactor; - TextureHandle m_AlbedoTex; - TextureHandle m_NormalTex; - TextureHandle m_MetalRoughTex; - TextureHandle m_OcclusionTex; - TextureHandle m_EmissionTex; + vec4 m_AlbedoFactor; // 16 16 + vec3 m_EmissionFactor; // 12 28 + f32 m_MetalFactor; // 04 32 + f32 m_RoughFactor; // 04 36 + TextureHandle m_AlbedoTex; // 04 40 + TextureHandle m_NormalTex; // 04 44 + TextureHandle m_MetalRoughTex; // 04 48 + TextureHandle m_OcclusionTex; // 04 52 + TextureHandle m_EmissionTex; // 04 56 }; struct Model @@ -47,17 +78,19 @@ struct Model GpuResourceManager *m_ResourceManager; eastl::vector m_TextureHandles; + Nodes m_Nodes; BufferHandle m_MaterialsHandle; BufferHandle m_VertexPositionHandle; BufferHandle m_NormalHandle; BufferHandle m_TexCoord0Handle; + BufferHandle m_VertexColorHandle; IndexBuffer m_IndexBuffer; eastl::vector m_MeshPrimitives; - Model(GpuResourceManager *resourceManager, eastl::vector &&textureHandles, - BufferHandle materialsHandle, BufferHandle vertexPosHandle, BufferHandle normalHandle, BufferHandle uv0Handle, + 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); Model(Model &&other) noexcept; @@ -90,6 +123,7 @@ struct ModelLoader constexpr static auto ATangent = "TANGENT"; constexpr static auto ATexCoord0 = "TEXCOORD_0"; constexpr static auto ATexCoord1 = "TEXCOORD_1"; + constexpr static auto AColor0 = "COLOR_0"; constexpr static auto AJoints0 = "JOINTS_0"; constexpr static auto AWeights0 = "WEIGHTS_0"; }; \ No newline at end of file diff --git a/samples/03_model_render/model_render.cpp b/samples/03_model_render/model_render.cpp index b2d2b9e..27055be 100644 --- a/samples/03_model_render/model_render.cpp +++ b/samples/03_model_render/model_render.cpp @@ -27,7 +27,7 @@ #include constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; -constexpr auto MODEL_FILE = "model/BoxTextured.glb"; +constexpr auto MODEL_FILE = "model/OrientationTest.glb"; struct ImageFile { @@ -95,7 +95,7 @@ main(int, char **) Camera camera = { .m_Model = {1.0f}, - .m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)), + .m_View = glm::lookAt(vec3(0.0f, 12.0f, 12.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)), .m_Perspective = glm::perspective( 70_deg, Cast(swapchain.m_Extent.width) / Cast(swapchain.m_Extent.height), 0.1f, 100.0f), }; @@ -217,12 +217,14 @@ main(int, char **) struct ModelData { BufferHandle m_VertexBuffer; + BufferHandle m_Color; BufferHandle m_UvBuffer; BufferHandle m_Materials; }; ModelData modelData = { .m_VertexBuffer = model.m_VertexPositionHandle, + .m_Color = model.m_VertexColorHandle, .m_UvBuffer = model.m_TexCoord0Handle, .m_Materials = model.m_MaterialsHandle, }; @@ -295,7 +297,8 @@ main(int, char **) for (auto &prim : model.m_MeshPrimitives) { - cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData, sizeof prim, &prim); + cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData, + sizeof prim.m_MaterialIdx, &prim.m_MaterialIdx); 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 0558181..3ffce70 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 = 36, + .size = 20, }; vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo = { diff --git a/samples/03_model_render/shader/bindless_structs.hlsli b/samples/03_model_render/shader/bindless_structs.hlsli index 94792c7..89cda7e 100644 --- a/samples/03_model_render/shader/bindless_structs.hlsli +++ b/samples/03_model_render/shader/bindless_structs.hlsli @@ -2,11 +2,12 @@ typedef float4 PositionData; typedef float2 UVData; typedef float4 NormalData; +typedef float4 ColorData; struct MaterialData { - float4 m_AlbedoFactor; - float3 m_EmissionFactor; + float m_AlbedoFactor[4]; + float m_EmissionFactor[3]; float m_MetalFactor; float m_RoughFactor; uint m_AlbedoTex; @@ -19,13 +20,9 @@ struct MaterialData struct Block { uint vertexBufferHandle; + uint colorHandle; uint uvBufferHandle; uint materialBufferHandle; - uint m_VertexOffset; - int m_NormalOffset; - int m_TexCoord0Offset; - uint m_FirstIndex; - uint m_IndexCount; int m_MaterialIdx; }; @@ -41,6 +38,7 @@ struct Camera [[vk::binding(0, 0)]] StructuredBuffer vertexBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer uvBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer normalBuffer[]; +[[vk::binding(0, 0)]] StructuredBuffer colorBuffer[]; [[vk::binding(0, 0)]] StructuredBuffer materialsBuffer[]; [[vk::binding(1, 0)]] Texture2D textures[]; diff --git a/samples/03_model_render/shader/model.ps.hlsl b/samples/03_model_render/shader/model.ps.hlsl index 0955601..9a5caee 100644 --- a/samples/03_model_render/shader/model.ps.hlsl +++ b/samples/03_model_render/shader/model.ps.hlsl @@ -2,6 +2,8 @@ struct FS_Input { + float4 inPosition : POSITION; + float4 inColor : COLOR0; float2 inUV : TEXCOORD0; }; @@ -10,35 +12,27 @@ struct FS_Output float4 outColor : SV_Target0; }; -struct Float4 +float4 ArrayToVector(float arr[4]) { - float4 value; -}; + return float4(arr[0], arr[1], arr[2], arr[3]); +} -float4 GetAlbedo(uint materialBufferId, int materialId, float2 uv0) +float4 GetAlbedo(uint materialBufferId, int materialId, float2 uv) { - if (materialId < 0) + uint albedoTexId = materialsBuffer[materialBufferId][materialId].m_AlbedoTex; + if (albedoTexId == INVALID_HANDLE) { - return float4(1.0f, 0.0f, 1.0f, 1.0f); // Magenta + return ArrayToVector(materialsBuffer[materialBufferId][materialId].m_AlbedoFactor); } else { - float4 albedoFactor = materialsBuffer[materialBufferId][materialId].m_AlbedoFactor; - uint albedoTexId = materialsBuffer[materialBufferId][materialId].m_AlbedoTex; - if (albedoTexId == INVALID_HANDLE) - { - return albedoFactor; - } - else - { - return textures[albedoTexId].Sample(immutableSamplers[albedoTexId], uv0); - } + return textures[albedoTexId].Sample(immutableSamplers[albedoTexId], uv); } } FS_Output main(FS_Input stage_input) { - FS_Output stage_output; - stage_output.outColor = GetAlbedo(pcb.materialBufferHandle, pcb.m_MaterialIdx, stage_input.inUV); - return stage_output; + FS_Output output; + output.outColor = pcb.m_MaterialIdx < 0 ? stage_input.inColor : GetAlbedo(pcb.materialBufferHandle, pcb.m_MaterialIdx, stage_input.inUV); + return output; } diff --git a/samples/03_model_render/shader/model.vs.hlsl b/samples/03_model_render/shader/model.vs.hlsl index 85bef85..9923a0d 100644 --- a/samples/03_model_render/shader/model.vs.hlsl +++ b/samples/03_model_render/shader/model.vs.hlsl @@ -7,7 +7,10 @@ struct VS_Input struct VS_Output { - UVData outUV : TEXCOORD0; + float4 outPosition : POSITION; + float4 outColor : COLOR0; + float2 outUV : TEXCOORD0; + float outMetal : METAL; float4 position : SV_Position; }; @@ -28,10 +31,18 @@ float3 GetPosition(uint bufferId, uint vertexIdx) return vertexBuffer[bufferId][vertexIdx].xyz; } +float4 GetColor(uint bufferId, uint vertexIdx) +{ + return (bufferId != INVALID_HANDLE) ? colorBuffer[bufferId][vertexIdx] : float4(1.0f, 0.0f, 1.0f, 1.0f); +} + VS_Output main(VS_Input stage_input) { - VS_Output stage_output; - stage_output.outUV = GetUV(pcb.uvBufferHandle, stage_input.vertexIndex); - stage_output.position = mul(float4(GetPosition(pcb.vertexBufferHandle, stage_input.vertexIndex), 1.0f), mul(camera.model, mul(camera.view, camera.proj))); - return stage_output; + 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.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))); + return output; }