diff --git a/Blaze.cpp b/Blaze.cpp index e6dfd1d..59066ac 100644 --- a/Blaze.cpp +++ b/Blaze.cpp @@ -70,10 +70,14 @@ SDL_AppResult SDL_AppIterate( void* appstate ) SDL_SetWindowTitle( appState.window, appState.sprintfBuffer ); } - misc.cameraData.modelMatrix = DirectX::XMMatrixMultiply( - misc.cameraData.modelMatrix, - DirectX::XMMatrixRotationY( DirectX::XMConvertToRadians( 60.0f ) * static_cast( deltaTime ) ) ); - memcpy( misc.cameraUniformBufferPtr, &misc.cameraData, sizeof misc.cameraData ); + for ( Transform& transform : misc.modelTransform ) + { + transform.rotation = DirectX::XMQuaternionMultiply( + DirectX::XMQuaternionRotationAxis( + DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ), + DirectX::XMConvertToRadians( 60.0f ) * static_cast( deltaTime ) ), + transform.rotation ); + } uint32_t currentImageIndex; VK_CHECK( vkAcquireNextImageKHR( @@ -155,7 +159,20 @@ SDL_AppResult SDL_AppIterate( void* appstate ) vkCmdBindVertexBuffers( cmd, 0, 1, &misc.vertexBuffer, &offset ); vkCmdBindDescriptorSets( cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, misc.pipelineLayout, 0, 1, &misc.descriptorSet, 0, nullptr ); - vkCmdDraw( cmd, static_cast( misc.vertices.size() ), 1, 0, 0 ); + for ( Transform& localTransform : misc.modelTransform ) + { + DirectX::XMMATRIX worldTransform; + { + auto [x, y, z] = localTransform.position; + auto scale = localTransform.scale; + worldTransform = DirectX::XMMatrixScaling( scale, scale, scale ) * + DirectX::XMMatrixRotationQuaternion( localTransform.rotation ) * + DirectX::XMMatrixTranslation( x, y, z ); + } + vkCmdPushConstants( + cmd, misc.pipelineLayout, VK_SHADER_STAGE_ALL_GRAPHICS, 0, sizeof worldTransform, &worldTransform ); + vkCmdDraw( cmd, static_cast( misc.vertices.size() ), 1, 0, 0 ); + } } vkCmdEndRendering( cmd ); vkCmdPipelineBarrier2( cmd, &misc.renderToPresentDependency ); diff --git a/Blaze.vcxproj b/Blaze.vcxproj index ba9d26d..be1b2e5 100644 --- a/Blaze.vcxproj +++ b/Blaze.vcxproj @@ -103,13 +103,13 @@ - EnableAllWarnings + Level4 true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true stdcpp20 false - false + true Sync false /utf-8 %(AdditionalOptions) @@ -124,7 +124,7 @@ - EnableAllWarnings + Level4 true true true @@ -132,7 +132,7 @@ true stdcpp20 false - false + true /EH- false /utf-8 %(AdditionalOptions) diff --git a/Mesh.slang b/Mesh.slang index df4dc74..df423d2 100644 --- a/Mesh.slang +++ b/Mesh.slang @@ -1,12 +1,12 @@ struct VertexOut { float4 outPosition : SV_Position; + float4 screenPosition : ScreenPosition; float4 vertexColor : CoarseColor; float2 texCoord0 : TexCoord0; }; struct CameraData { - float4x4 model; float4x4 view; float4x4 proj; }; @@ -18,6 +18,13 @@ struct PerFrameData { ParameterBlock perFrameData; +struct PerInstanceData { + float4x4 transform; +} + +[[vk::push_constant]] +uniform ConstantBuffer pcb; + [shader("vertex")] VertexOut VertexMain( uint vertexId: SV_VertexID, @@ -26,7 +33,8 @@ VertexOut VertexMain( float2 texCoord0, ) { VertexOut output; - output.outPosition = mul(perFrameData.camera.proj, mul(perFrameData.camera.view, mul(perFrameData.camera.model, float4(position, 1.0f)))); + output.outPosition = mul(perFrameData.camera.proj, mul(perFrameData.camera.view, mul(pcb.transform, float4(position, 1.0f)))); + output.screenPosition = mul(perFrameData.camera.proj, mul(perFrameData.camera.view, mul(pcb.transform, float4(position, 1.0f)))); output.vertexColor = float4(color, 1.0f); output.texCoord0 = texCoord0 * 2.0f; return output; @@ -34,9 +42,16 @@ VertexOut VertexMain( [shader("fragment")] float4 FragmentMain( + float4 interpolatePosition : ScreenPosition, float4 interpolatedColors : CoarseColor, float2 uv0 : TexCoord0, ) : SV_Target0 { - return float4(perFrameData.texture.Sample(uv0).rgb, 1.0f) * interpolatedColors; + float4 outColor; + if (interpolatePosition.x < 0) { + outColor = float4(perFrameData.texture.SampleLevel(uv0, 0).rgb, 1.0f) * interpolatedColors; + } else { + outColor = float4(perFrameData.texture.Sample(uv0).rgb, 1.0f) * interpolatedColors; + } + return outColor; } diff --git a/MiscData.cpp b/MiscData.cpp index 9f247b0..09d7a4c 100644 --- a/MiscData.cpp +++ b/MiscData.cpp @@ -67,14 +67,20 @@ bool MiscData::init( RenderDevice const& renderDevice ) }; VK_CHECK( vkCreateDescriptorSetLayout( device, &descriptorSetLayoutCreateInfo, nullptr, &descriptorSetLayout ) ); + VkPushConstantRange const pushConstantRange = { + .stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS, + .offset = 0, + .size = sizeof( DirectX::XMMATRIX ), + }; + VkPipelineLayoutCreateInfo const pipelineLayoutCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = 0, .setLayoutCount = 1, .pSetLayouts = &descriptorSetLayout, - .pushConstantRangeCount = 0, - .pPushConstantRanges = nullptr, + .pushConstantRangeCount = 1, + .pPushConstantRanges = &pushConstantRange, }; VK_CHECK( vkCreatePipelineLayout( device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout ) ); @@ -228,7 +234,7 @@ bool MiscData::init( RenderDevice const& renderDevice ) .blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }, }; - std::array constexpr dynamicStates{ VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; + std::array constexpr dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR }; VkPipelineDynamicStateCreateInfo const dynamicStateCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, @@ -378,19 +384,23 @@ bool MiscData::init( RenderDevice const& renderDevice ) height = static_cast( h ); } + // Calculate mips + uint32_t mipLevels = + 1 + static_cast( floorf( log2f( static_cast( std::max( width, height ) ) ) ) ); + VkImageCreateInfo const imageCreateInfo = { - .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, - .pNext = nullptr, - .flags = 0, - .imageType = VK_IMAGE_TYPE_2D, - .format = VK_FORMAT_R8G8B8A8_SRGB, - .extent = { .width = width, .height = height, .depth = 1 }, - .mipLevels = 1, - .arrayLayers = 1, - .samples = VK_SAMPLE_COUNT_1_BIT, - .tiling = VK_IMAGE_TILING_OPTIMAL, - .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = nullptr, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = VK_FORMAT_R8G8B8A8_SRGB, + .extent = { .width = width, .height = height, .depth = 1 }, + .mipLevels = mipLevels, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, @@ -410,10 +420,10 @@ bool MiscData::init( RenderDevice const& renderDevice ) VK_CHECK( vmaCreateImage( renderDevice.gpuAllocator, &imageCreateInfo, &allocationCreateInfo, &texture, &textureAllocation, nullptr ) ); - VkImageSubresourceRange constexpr subresourceRange = { + VkImageSubresourceRange const subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, - .levelCount = 1, + .levelCount = mipLevels, .baseArrayLayer = 0, .layerCount = 1, }; @@ -454,7 +464,7 @@ bool MiscData::init( RenderDevice const& renderDevice ) .compareEnable = false, .compareOp = VK_COMPARE_OP_NEVER, .minLod = 0.0f, - .maxLod = 0.0f, + .maxLod = VK_LOD_CLAMP_NONE, .borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK, .unnormalizedCoordinates = false, }; @@ -506,6 +516,7 @@ bool MiscData::init( RenderDevice const& renderDevice ) // All data is copied to stagingBuffer, don't need this. stbi_image_free( textureData ); + // Staging -> Texture transfer { Frame& frameInUse = renderDevice.frames[0]; @@ -547,19 +558,48 @@ bool MiscData::init( RenderDevice const& renderDevice ) .pImageMemoryBarriers = &creationToTransferImageBarrier, }; - VkImageMemoryBarrier2 const transferToReadyImageBarrier = { - .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, - .pNext = nullptr, - .srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT, - .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, - .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, - .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT, - .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, - .image = texture, - .subresourceRange = subresourceRange, + std::array transferToReadyImageBarriers{ + // transferToReadyImageBarrier + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = mipLevels-1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + }, + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + .dstAccessMask = VK_ACCESS_2_SHADER_SAMPLED_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture, + .subresourceRange = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = mipLevels-1, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }, + } }; VkDependencyInfo const transferToReadyDependency = { @@ -570,10 +610,64 @@ bool MiscData::init( RenderDevice const& renderDevice ) .pMemoryBarriers = nullptr, .bufferMemoryBarrierCount = 0, .pBufferMemoryBarriers = nullptr, - .imageMemoryBarrierCount = 1, - .pImageMemoryBarriers = &transferToReadyImageBarrier, + .imageMemoryBarrierCount = static_cast( transferToReadyImageBarriers.size() ), + .pImageMemoryBarriers = transferToReadyImageBarriers.data(), }; + VkImageSubresourceRange const mipLevelSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + std::array prepareNextMipLevelBarriers{ + // prepareNextMipLevelSrcImageBarrier + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT, + .dstAccessMask = VK_ACCESS_2_TRANSFER_READ_BIT, + .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture, + .subresourceRange = mipLevelSubresource, + }, + // prepareNextMipLevelDstImageBarrier + VkImageMemoryBarrier2{ + .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2, + .pNext = nullptr, + .srcStageMask = VK_PIPELINE_STAGE_2_COPY_BIT, + .srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .dstStageMask = VK_PIPELINE_STAGE_2_BLIT_BIT, + .dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT, + .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .newLayout = VK_IMAGE_LAYOUT_UNDEFINED, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .image = texture, + .subresourceRange = mipLevelSubresource, + } + }; + + VkDependencyInfo const prepareNextMipLevelDependency = { + .sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO, + .pNext = nullptr, + .dependencyFlags = 0, + .memoryBarrierCount = 0, + .pMemoryBarriers = nullptr, + .bufferMemoryBarrierCount = 0, + .pBufferMemoryBarriers = nullptr, + .imageMemoryBarrierCount = static_cast( prepareNextMipLevelBarriers.size() ), + .pImageMemoryBarriers = prepareNextMipLevelBarriers.data(), + }; + + vkBeginCommandBuffer( frameInUse.commandBuffer, &beginInfo ); { VkImageSubresourceLayers imageSubresourceLayers = { @@ -593,11 +687,82 @@ bool MiscData::init( RenderDevice const& renderDevice ) .imageExtent = imageCreateInfo.extent }; + // Start vkCmdPipelineBarrier2( frameInUse.commandBuffer, &creationToTransferDependency ); + // Staging -> Image L0 vkCmdCopyBufferToImage( frameInUse.commandBuffer, stagingBuffer, texture, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region ); + prepareNextMipLevelBarriers[0].subresourceRange.baseMipLevel = 0; + prepareNextMipLevelBarriers[1].subresourceRange.baseMipLevel = 1; + + int32_t mipSrcWidth = static_cast( width ); + int32_t mipSrcHeight = static_cast( height ); + int32_t mipDstWidth = std::max( mipSrcWidth / 2, 1 ); + int32_t mipDstHeight = std::max( mipSrcHeight / 2, 1 ); + + VkImageSubresourceLayers constexpr mipSubresourceLayers = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + VkImageBlit2 imageBlit = { + .sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2, + .pNext = nullptr, + .srcSubresource = mipSubresourceLayers, + .srcOffsets = { { 0, 0, 0 }, { mipSrcWidth, mipSrcHeight, 1 } }, + .dstSubresource = mipSubresourceLayers, + .dstOffsets = { { 0, 0, 0 }, { mipDstWidth, mipDstHeight, 1 } }, + }; + + imageBlit.srcSubresource.mipLevel = 0; + imageBlit.dstSubresource.mipLevel = 1; + imageBlit.srcOffsets[1].x = mipSrcWidth; + imageBlit.srcOffsets[1].y = mipSrcHeight; + imageBlit.dstOffsets[1].x = mipDstWidth; + imageBlit.dstOffsets[1].y = mipDstHeight; + + VkBlitImageInfo2 blitInfo = { + .sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2, + .pNext = nullptr, + .srcImage = texture, + .srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + .dstImage = texture, + .dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + .regionCount = 1, + .pRegions = &imageBlit, + .filter = VK_FILTER_LINEAR, + }; + + // MipMapping + for ( uint32_t dstMipLevel = 1; dstMipLevel < mipLevels; ++dstMipLevel ) + { + vkCmdPipelineBarrier2( frameInUse.commandBuffer, &prepareNextMipLevelDependency ); + vkCmdBlitImage2( frameInUse.commandBuffer, &blitInfo ); + + // Prep for NEXT iteration + + mipSrcWidth = mipDstWidth; + mipSrcHeight = mipDstHeight; + mipDstWidth = std::max( mipSrcWidth / 2, 1 ); + mipDstHeight = std::max( mipSrcHeight / 2, 1 ); + + imageBlit.srcSubresource.mipLevel = dstMipLevel; + imageBlit.dstSubresource.mipLevel = dstMipLevel + 1; + imageBlit.srcOffsets[1].x = mipSrcWidth; + imageBlit.srcOffsets[1].y = mipSrcHeight; + imageBlit.dstOffsets[1].x = mipDstWidth; + imageBlit.dstOffsets[1].y = mipDstHeight; + + // Prep current mip level as source + prepareNextMipLevelBarriers[0].subresourceRange.baseMipLevel = dstMipLevel; + prepareNextMipLevelBarriers[1].subresourceRange.baseMipLevel = dstMipLevel + 1; + } + + // End vkCmdPipelineBarrier2( frameInUse.commandBuffer, &transferToReadyDependency ); } vkEndCommandBuffer( frameInUse.commandBuffer ); @@ -622,13 +787,23 @@ bool MiscData::init( RenderDevice const& renderDevice ) vmaDestroyBuffer( renderDevice.gpuAllocator, stagingBuffer, stagingAllocation ); } + // Model Setup + modelTransform[0].position = { 1.0f, 0.0f, 0.0f }; + modelTransform[0].scale = 1.0f; + modelTransform[0].rotation = + DirectX::XMQuaternionRotationAxis( DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 0.0f ), 0.0f ); + + modelTransform[1].position = { -1.0f, 0.0f, 0.0f }; + modelTransform[1].scale = 1.0f; + modelTransform[1].rotation = + DirectX::XMQuaternionRotationAxis( DirectX::XMVectorSet( 1.0f, 0.0f, 0.0f, 0.0f ), 0.0f ); + // Camera { - cameraPosition = DirectX::XMVectorSet( 0.0f, 0.0f, -5.0f, 1.0f ); - cameraTarget = DirectX::XMVectorSet( 0.0f, 0.0f, 0.0f, 1.0f ); - cameraUp = DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 1.0f ); - cameraData.modelMatrix = DirectX::XMMatrixIdentity(); - cameraData.viewMatrix = DirectX::XMMatrixLookAtLH( cameraPosition, cameraTarget, cameraUp ); + cameraPosition = DirectX::XMVectorSet( 0.0f, 0.0f, -4.0f, 1.0f ); + cameraTarget = DirectX::XMVectorSet( 0.0f, 0.0f, 0.0f, 1.0f ); + cameraUp = DirectX::XMVectorSet( 0.0f, 1.0f, 0.0f, 1.0f ); + cameraData.viewMatrix = DirectX::XMMatrixLookAtLH( cameraPosition, cameraTarget, cameraUp ); cameraData.projectionMatrix = DirectX::XMMatrixPerspectiveFovLH( DirectX::XMConvertToRadians( 70.0f ), 16.0f / 9.0f, 0.1f, 1000.0f ); diff --git a/MiscData.h b/MiscData.h index 5ae7ed7..cd1d18b 100644 --- a/MiscData.h +++ b/MiscData.h @@ -17,49 +17,57 @@ struct Vertex DirectX::XMFLOAT2 texCoord0; }; +struct Transform +{ + DirectX::XMFLOAT3 position; + float scale; + DirectX::XMVECTOR rotation; +}; + struct MiscData { struct CameraData { - DirectX::XMMATRIX modelMatrix; DirectX::XMMATRIX viewMatrix; DirectX::XMMATRIX projectionMatrix; }; - uint64_t previousCounter; + uint64_t previousCounter; - VkDescriptorSetLayout descriptorSetLayout; - VkPipelineLayout pipelineLayout; - VkPipeline meshPipeline; + VkDescriptorSetLayout descriptorSetLayout; + VkPipelineLayout pipelineLayout; + VkPipeline meshPipeline; - VkBuffer vertexBuffer; - VmaAllocation vertexBufferAllocation; - size_t vertexBufferSize; - std::array vertices; + VkBuffer vertexBuffer; + VmaAllocation vertexBufferAllocation; + size_t vertexBufferSize; + std::array vertices; - VkImage texture; - VmaAllocation textureAllocation; - VkImageView textureView; - VkSampler sampler; + VkImage texture; + VmaAllocation textureAllocation; + VkImageView textureView; + VkSampler sampler; - uint64_t _padding; // TODO: Optimize out? + uint64_t _padding; // TODO: Optimize out? - DirectX::XMVECTOR cameraPosition; - DirectX::XMVECTOR cameraTarget; - DirectX::XMVECTOR cameraUp; - CameraData cameraData; - VkBuffer cameraUniformBuffer; - VmaAllocation cameraUniformBufferAllocation; - size_t cameraUniformBufferSize; - uint8_t* cameraUniformBufferPtr; - VkDescriptorPool descriptorPool; - VkDescriptorSet descriptorSet; + std::array modelTransform; - VkImageMemoryBarrier2 acquireToRenderBarrier; - VkDependencyInfo acquireToRenderDependency; - VkImageMemoryBarrier2 renderToPresentBarrier; - VkDependencyInfo renderToPresentDependency; + DirectX::XMVECTOR cameraPosition; + DirectX::XMVECTOR cameraTarget; + DirectX::XMVECTOR cameraUp; + CameraData cameraData; + VkBuffer cameraUniformBuffer; + VmaAllocation cameraUniformBufferAllocation; + size_t cameraUniformBufferSize; + uint8_t* cameraUniformBufferPtr; + VkDescriptorPool descriptorPool; + VkDescriptorSet descriptorSet; - bool init( RenderDevice const& renderDevice ); - void destroy( RenderDevice const& renderDevice ); + VkImageMemoryBarrier2 acquireToRenderBarrier; + VkDependencyInfo acquireToRenderDependency; + VkImageMemoryBarrier2 renderToPresentBarrier; + VkDependencyInfo renderToPresentDependency; + + bool init( RenderDevice const& renderDevice ); + void destroy( RenderDevice const& renderDevice ); };