diff --git a/CMakeLists.txt b/CMakeLists.txt index 651b4d3c..262afbe4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,9 @@ add_subdirectory(editor) include(cmake/compile_shaders.cmake) compile_shader(SOURCE_FILE "${SHADERS_PATH}/default.vert" OUTPUT_FILE_NAME "${SHADERS_PATH}/vert.spv") compile_shader(SOURCE_FILE "${SHADERS_PATH}/default.frag" OUTPUT_FILE_NAME "${SHADERS_PATH}/frag.spv") -compile_shader(SOURCE_FILE "${SHADERS_PATH}/ui.vert" OUTPUT_FILE_NAME "${SHADERS_PATH}/ui.vert.spv") -compile_shader(SOURCE_FILE "${SHADERS_PATH}/ui.frag" OUTPUT_FILE_NAME "${SHADERS_PATH}/ui.frag.spv") -compile_shader(SOURCE_FILE "${SHADERS_PATH}/line.vert" OUTPUT_FILE_NAME "${SHADERS_PATH}/line.vert.spv") -compile_shader(SOURCE_FILE "${SHADERS_PATH}/line.frag" OUTPUT_FILE_NAME "${SHADERS_PATH}/line.frag.spv") +compile_shader(SOURCE_FILE "${SHADERS_PATH}/ui.vert" OUTPUT_FILE_NAME "${SHADERS_PATH}/ui.vert.spv") +compile_shader(SOURCE_FILE "${SHADERS_PATH}/ui.frag" OUTPUT_FILE_NAME "${SHADERS_PATH}/ui.frag.spv") +compile_shader(SOURCE_FILE "${SHADERS_PATH}/line.vert" OUTPUT_FILE_NAME "${SHADERS_PATH}/line.vert.spv") +compile_shader(SOURCE_FILE "${SHADERS_PATH}/line.frag" OUTPUT_FILE_NAME "${SHADERS_PATH}/line.frag.spv") +compile_shader(SOURCE_FILE "${SHADERS_PATH}/shadow.vert" OUTPUT_FILE_NAME "${SHADERS_PATH}/shadow.vert.spv") +compile_shader(SOURCE_FILE "${SHADERS_PATH}/shadow.frag" OUTPUT_FILE_NAME "${SHADERS_PATH}/shadow.frag.spv") diff --git a/assets/shaders/default.frag b/assets/shaders/default.frag index 571859cb..5fdefe1f 100644 --- a/assets/shaders/default.frag +++ b/assets/shaders/default.frag @@ -5,11 +5,25 @@ #extension GL_ARB_gpu_shader_int64 : enable layout(set = 0, binding = 2) uniform sampler2D textures[256]; +layout(set = 0, binding = 3) uniform sampler2D shadowMap; + +layout(set = 0, binding = 0) uniform UniformBufferObject +{ + mat4 u_projectionMat; + mat4 u_viewMat; + vec4 u_cameraPos; + mat4 u_lightViewProj; + vec4 u_lightDirection; + vec4 u_lightColor; + vec4 u_shadowParams; +} +ubo; layout(location = 0) in VS_OUT { vec4 fColor; vec2 fTexCoord; + vec4 fLightSpacePos; flat int fDiffSampl; flat int fExtraSampl; @@ -18,10 +32,57 @@ fs_in; layout(location = 0) out vec4 outColor; +float +ComputeShadow(vec4 lightSpacePos) +{ + vec3 projCoords = lightSpacePos.xyz / max(lightSpacePos.w, 0.0001); + projCoords = projCoords * 0.5 + 0.5; + + if (projCoords.z <= 0.0 || projCoords.z >= 1.0) + { + return 0.0; + } + + if (projCoords.x < 0.0 || projCoords.x > 1.0 || projCoords.y < 0.0 || projCoords.y > 1.0) + { + return 0.0; + } + + float shadow = 0.0; + float bias = ubo.u_shadowParams.z; + vec2 texelSize = 1.0 / vec2(textureSize(shadowMap, 0)); + + for (int x = -1; x <= 1; ++x) + { + for (int y = -1; y <= 1; ++y) + { + float closestDepth = texture(shadowMap, projCoords.xy + vec2(x, y) * texelSize).r; + shadow += (projCoords.z - bias) > closestDepth ? 1.0 : 0.0; + } + } + + return shadow / 9.0; +} + void main(void) { vec4 base = texture(textures[fs_in.fDiffSampl], fs_in.fTexCoord); vec4 mask = texture(textures[fs_in.fExtraSampl], fs_in.fTexCoord); - outColor = fs_in.fColor * base * mask; + vec4 surface = fs_in.fColor * base * mask; + + if (surface.a <= 0.01) + { + discard; + } + + vec3 lightDir = normalize(ubo.u_lightDirection.xyz); + float diffuse = max(dot(vec3(0.0, 0.0, 1.0), lightDir), 0.0); + float shadow = ComputeShadow(fs_in.fLightSpacePos); + float ambient = ubo.u_shadowParams.x; + float shadowStrength = ubo.u_shadowParams.y; + float visibility = 1.0 - shadow * shadowStrength; + + vec3 lighting = vec3(ambient) + visibility * diffuse * ubo.u_lightColor.rgb; + outColor = vec4(surface.rgb * lighting, surface.a); } diff --git a/assets/shaders/default.vert b/assets/shaders/default.vert index 642bc71f..b0a57673 100644 --- a/assets/shaders/default.vert +++ b/assets/shaders/default.vert @@ -8,6 +8,10 @@ layout(set = 0, binding = 0) uniform UniformBufferObject mat4 u_projectionMat; mat4 u_viewMat; vec4 u_cameraPos; + mat4 u_lightViewProj; + vec4 u_lightDirection; + vec4 u_lightColor; + vec4 u_shadowParams; } ubo; @@ -30,6 +34,7 @@ layout(location = 0) out VS_OUT { vec4 fColor; vec2 fTexCoord; + vec4 fLightSpacePos; flat int fDiffSampl; flat int fExtraSampl; @@ -54,6 +59,8 @@ main(void) mat4 modelMat = curInstanceData.modelMat; vec3 position = a_position; + vec4 worldPosition = modelMat * vec4(position.xyz, 1.0f); - gl_Position = ubo.u_projectionMat * ubo.u_viewMat * modelMat * vec4(position.xyz, 1.0f); + vs_out.fLightSpacePos = ubo.u_lightViewProj * worldPosition; + gl_Position = ubo.u_projectionMat * ubo.u_viewMat * worldPosition; } diff --git a/assets/shaders/shadow.frag b/assets/shaders/shadow.frag new file mode 100644 index 00000000..43df59ce --- /dev/null +++ b/assets/shaders/shadow.frag @@ -0,0 +1,24 @@ +#version 460 + +layout(set = 0, binding = 2) uniform sampler2D textures[256]; + +layout(location = 0) in VS_OUT +{ + vec2 fTexCoord; + + flat int fDiffSampl; + flat int fExtraSampl; +} +fs_in; + +void +main(void) +{ + vec4 base = texture(textures[fs_in.fDiffSampl], fs_in.fTexCoord); + vec4 mask = texture(textures[fs_in.fExtraSampl], fs_in.fTexCoord); + + if ((base * mask).a <= 0.01) + { + discard; + } +} diff --git a/assets/shaders/shadow.vert b/assets/shaders/shadow.vert new file mode 100644 index 00000000..a45d26e3 --- /dev/null +++ b/assets/shaders/shadow.vert @@ -0,0 +1,53 @@ +#version 460 + +#extension GL_ARB_shader_storage_buffer_object : require +#extension GL_ARB_gpu_shader_int64 : enable + +layout(set = 0, binding = 0) uniform UniformBufferObject +{ + mat4 u_projectionMat; + mat4 u_viewMat; + vec4 u_cameraPos; + mat4 u_lightViewProj; + vec4 u_lightDirection; + vec4 u_lightColor; + vec4 u_shadowParams; +} +ubo; + +struct BufferData +{ + mat4 modelMat; + vec4 color; + vec4 texSamples; +}; + +layout(std430, set = 0, binding = 1) readonly buffer Block +{ + BufferData Transforms[]; +}; + +layout(location = 0) in vec3 a_position; +layout(location = 1) in vec3 a_texCoordDrawID; + +layout(location = 0) out VS_OUT +{ + vec2 fTexCoord; + + flat int fDiffSampl; + flat int fExtraSampl; +} +vs_out; + +void +main(void) +{ + float drawID = a_texCoordDrawID.z; + BufferData curInstanceData = Transforms[int(drawID)]; + + vs_out.fTexCoord = a_texCoordDrawID.xy; + vs_out.fDiffSampl = int(curInstanceData.texSamples.x); + vs_out.fExtraSampl = int(curInstanceData.texSamples.y); + + gl_Position = ubo.u_lightViewProj * curInstanceData.modelMat * vec4(a_position.xyz, 1.0f); +} diff --git a/editor/editor.cpp b/editor/editor.cpp index 9c5cc2c2..9871eccc 100644 --- a/editor/editor.cpp +++ b/editor/editor.cpp @@ -989,15 +989,11 @@ Editor::Render(VkCommandBuffer cmdBuffer) gizmo_.Render(); - - vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderData.pipeline); - - auto offsets = std::to_array< const VkDeviceSize >({0}); - vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderData.pipelineLayout, - 0, 1, &renderData.descriptorSets[renderer::Data::currentFrame_], 0, - nullptr); - renderer::QuadShader::PushConstants pushConstants = {}; - pushConstants.selectedIdx = -1.0f; + + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderData.pipeline); + + renderer::QuadShader::PushConstants pushConstants = {}; + pushConstants.selectedIdx = -1.0f; if (currentSelectedGameObject_ != Object::INVALID_ID) { @@ -1006,38 +1002,19 @@ Editor::Render(VkCommandBuffer cmdBuffer) pushConstants.selectedIdx = static_cast< float >(tmpIdx); } - vkCmdPushConstants(cmdBuffer, renderData.pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, - sizeof(renderer::QuadShader::PushConstants), &pushConstants); - - const auto renderAllLayers = renderLayerToDraw_ == -1; - for (int32_t layer = renderer::NUM_LAYERS - 1; layer >= 0; --layer) - { - const auto idx = static_cast< size_t >(layer); - const auto& numObjects = renderData.numMeshes.at(idx); - - const auto renderThisLayer = - (renderAllLayers or layer == 0) ? true : renderLayerToDraw_ == layer; - - if (numObjects == 0 or !renderThisLayer) - { - continue; - } - - vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &renderData.vertexBuffer.at(idx).buffer_, - offsets.data()); - - vkCmdBindIndexBuffer(cmdBuffer, renderData.indexBuffer.at(idx).buffer_, 0, - VK_INDEX_TYPE_UINT32); - - vkCmdDrawIndexed(cmdBuffer, numObjects * renderer::INDICES_PER_SPRITE, 1, 0, 0, 0); - } - - // DRAW LINES - vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - renderer::EditorData::linePipeline_); - - vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &renderer::EditorData::lineVertexBuffer.buffer_, - offsets.data()); + renderer::DrawQuadMeshes(cmdBuffer, renderData.pipelineLayout, + renderData.descriptorSets[renderer::Data::currentFrame_], + renderLayerToDraw_, true, &pushConstants, + sizeof(renderer::QuadShader::PushConstants), + VK_SHADER_STAGE_VERTEX_BIT); + + // DRAW LINES + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + renderer::EditorData::linePipeline_); + + auto offsets = std::to_array< const VkDeviceSize >({0}); + vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &renderer::EditorData::lineVertexBuffer.buffer_, + offsets.data()); vkCmdBindIndexBuffer(cmdBuffer, renderer::EditorData::lineIndexBuffer.buffer_, 0, VK_INDEX_TYPE_UINT32); diff --git a/engine/game/game.cpp b/engine/game/game.cpp index e31d727c..def916b0 100644 --- a/engine/game/game.cpp +++ b/engine/game/game.cpp @@ -379,46 +379,18 @@ Game::HandleReverseLogic() } } -void -Game::Render(VkCommandBuffer cmdBuffer) -{ - RenderFirstPass(); - RenderSecondPass(); +void +Game::Render(VkCommandBuffer cmdBuffer) +{ + RenderFirstPass(); + RenderSecondPass(); auto& renderData = renderer::Data::renderData_.at(renderer::GetCurrentlyBoundType()); - - vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderData.pipeline); - - - auto offsets = std::to_array< const VkDeviceSize >({0}); - - vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderData.pipelineLayout, 0, - 1, &renderData.descriptorSets[renderer::Data::currentFrame_], 0, - nullptr); - - for (int32_t layer = renderer::NUM_LAYERS - 1; layer >= 0; --layer) - { - const auto idx = static_cast< size_t >(layer); - - const auto& numObjects = renderData.numMeshes.at(idx); - if (numObjects == 0) - { - continue; - } - - vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &renderData.vertexBuffer.at(idx).buffer_, - offsets.data()); - - vkCmdBindIndexBuffer(cmdBuffer, renderData.indexBuffer.at(idx).buffer_, 0, - VK_INDEX_TYPE_UINT32); - - // const auto numObjects = - // renderer::GetNumMeshes(renderer::ApplicationType::GAME); numObjects_ = - // numObjects.second - numObjects.first; - vkCmdDrawIndexed(cmdBuffer, renderData.numMeshes.at(idx) * renderer::INDICES_PER_SPRITE, 1, 0, - 0, 0); - } -} + + vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, renderData.pipeline); + renderer::DrawQuadMeshes(cmdBuffer, renderData.pipelineLayout, + renderData.descriptorSets[renderer::Data::currentFrame_]); +} } // namespace looper diff --git a/engine/renderer/helpers.hpp b/engine/renderer/helpers.hpp index e8b4bdb1..c8bd603a 100644 --- a/engine/renderer/helpers.hpp +++ b/engine/renderer/helpers.hpp @@ -349,12 +349,21 @@ FindSupportedFormat(const std::vector< VkFormat >& candidates, VkImageTiling til return {}; } -VkFormat -FindDepthFormat() -{ - return FindSupportedFormat({VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, - VK_IMAGE_TILING_OPTIMAL, - VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); -} - -} // namespace looper::renderer +VkFormat +FindDepthFormat() +{ + return FindSupportedFormat({VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT); +} + +VkFormat +FindShadowDepthFormat() +{ + return FindSupportedFormat( + {VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT}, + VK_IMAGE_TILING_OPTIMAL, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); +} + +} // namespace looper::renderer diff --git a/engine/renderer/renderer.cpp b/engine/renderer/renderer.cpp index e9da391f..8efc9c2e 100644 --- a/engine/renderer/renderer.cpp +++ b/engine/renderer/renderer.cpp @@ -14,12 +14,13 @@ #include -#include -#include -#include - -#include -#include +#include +#include +#include +#include + +#include +#include namespace looper::renderer { @@ -180,7 +181,9 @@ CreatePipeline(std::string_view vertexShader, std::string_view fragmentShader, P vkCreatePipelineLayout(Data::vk_device, &pipelineLayoutInfo, nullptr, &pipeLineLayout), "failed to create pipeline layout!"); - std::vector< VkDynamicState > dynamicStateEnables = {VK_DYNAMIC_STATE_LINE_WIDTH}; + std::vector< VkDynamicState > dynamicStateEnables = {VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo{}; pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; @@ -246,8 +249,8 @@ CreateVertexBuffer(size_t bufferSize, const std::vector< DataT >& vertices) } template < auto INDICES_PER_OBJECT > -Buffer -CreateIndexBuffer(std::vector< IndexType >& indices, const size_t numObjects) +Buffer +CreateIndexBuffer(std::vector< IndexType >& indices, const size_t numObjects) { if (!numObjects) { @@ -298,9 +301,323 @@ CreateIndexBuffer(std::vector< IndexType >& indices, const size_t numObjects) Buffer::CopyBuffer(stagingBuffer.buffer_, indexBuffer.buffer_, bufferSize); stagingBuffer.Destroy(); - - return indexBuffer; -} + + return indexBuffer; +} + +glm::mat4 +CalculateLightViewProj(RenderData& renderData) +{ + glm::mat4 view = renderData.viewMat; + glm::mat4 proj = renderData.projMat; + + if (view[3][3] == 0.0f) + { + view = glm::mat4(1.0f); + } + + if (proj[0][0] == 0.0f || proj[1][1] == 0.0f) + { + proj = glm::mat4(1.0f); + } + + const glm::mat4 inverseView = glm::inverse(view); + const glm::vec3 cameraPosition = glm::vec3(inverseView[3]); + + const auto lightDir = glm::normalize(glm::vec3(renderData.lightDirection)); + const auto halfWidth = glm::max(1.0f, 1.0f / glm::abs(proj[0][0])); + const auto halfHeight = glm::max(1.0f, 1.0f / glm::abs(proj[1][1])); + const auto halfExtent = glm::sqrt(halfWidth * halfWidth + halfHeight * halfHeight) + 128.0f; + const auto lightDistance = halfExtent * 2.0f + 512.0f; + + auto up = glm::vec3(0.0f, 1.0f, 0.0f); + if (glm::abs(glm::dot(lightDir, up)) > 0.99f) + { + up = glm::vec3(1.0f, 0.0f, 0.0f); + } + + const auto lightPosition = cameraPosition - lightDir * lightDistance; + const auto lightView = glm::lookAt(lightPosition, cameraPosition, up); + const auto lightProj = + glm::ortho(-halfExtent, halfExtent, -halfExtent, halfExtent, 0.1f, lightDistance * 3.0f); + + renderData.lightViewProjMat = lightProj * lightView; + return renderData.lightViewProjMat; +} + +void +CreateShadowSampler() +{ + auto& renderData = Data::renderData_.at(boundApplication_); + + if (renderData.shadowSampler != VK_NULL_HANDLE) + { + vkDestroySampler(Data::vk_device, renderData.shadowSampler, nullptr); + } + + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_NEAREST; + samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxAnisotropy = 1.0f; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + samplerInfo.minLod = 0.0f; + samplerInfo.maxLod = 1.0f; + samplerInfo.mipLodBias = 0.0f; + + vk_check_error(vkCreateSampler(Data::vk_device, &samplerInfo, nullptr, &renderData.shadowSampler), + "Failed to create shadow sampler!"); +} + +void +CreateShadowResources() +{ + auto& renderData = Data::renderData_.at(boundApplication_); + const auto depthFormat = FindShadowDepthFormat(); + + CreateShadowSampler(); + + for (uint32_t frame = 0; frame < MAX_FRAMES_IN_FLIGHT; ++frame) + { + if (renderData.shadowImageViews.at(frame) != VK_NULL_HANDLE) + { + vkDestroyImageView(Data::vk_device, renderData.shadowImageViews.at(frame), nullptr); + renderData.shadowImageViews.at(frame) = VK_NULL_HANDLE; + } + + if (renderData.shadowImages.at(frame) != VK_NULL_HANDLE) + { + vmaDestroyImage(Data::vk_hAllocator, renderData.shadowImages.at(frame), + renderData.shadowImageAllocations.at(frame)); + renderData.shadowImages.at(frame) = VK_NULL_HANDLE; + renderData.shadowImageMemories.at(frame) = VK_NULL_HANDLE; + renderData.shadowImageAllocations.at(frame) = {}; + } + + const auto image = Texture::CreateImage( + renderData.shadowMapExtent.width, renderData.shadowMapExtent.height, 1, + VK_SAMPLE_COUNT_1_BIT, depthFormat, VK_IMAGE_TILING_OPTIMAL, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + renderData.shadowImages.at(frame) = image.textureImage_; + renderData.shadowImageMemories.at(frame) = image.textureImageMemory_; + renderData.shadowImageAllocations.at(frame) = image.allocation_; + renderData.shadowImageViews.at(frame) = + Texture::CreateImageView(renderData.shadowImages.at(frame), depthFormat, + VK_IMAGE_ASPECT_DEPTH_BIT, 1); + } +} + +void +CreateShadowRenderPass() +{ + auto& renderData = Data::renderData_.at(boundApplication_); + + VkAttachmentDescription depthAttachment = {}; + depthAttachment.format = FindShadowDepthFormat(); + depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + + VkAttachmentReference depthAttachmentRef = {}; + depthAttachmentRef.attachment = 0; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + std::array< VkSubpassDependency, 2 > dependencies = {}; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependencies[0].dstAccessMask = + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &depthAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = static_cast< uint32_t >(dependencies.size()); + renderPassInfo.pDependencies = dependencies.data(); + + vk_check_error(vkCreateRenderPass(Data::vk_device, &renderPassInfo, nullptr, + &renderData.shadowRenderPass), + "failed to create shadow render pass!"); +} + +void +CreateShadowFramebuffers() +{ + auto& renderData = Data::renderData_.at(boundApplication_); + + for (auto& framebuffer : renderData.shadowFramebuffers) + { + if (framebuffer != VK_NULL_HANDLE) + { + vkDestroyFramebuffer(Data::vk_device, framebuffer, nullptr); + framebuffer = VK_NULL_HANDLE; + } + } + + for (uint32_t frame = 0; frame < MAX_FRAMES_IN_FLIGHT; ++frame) + { + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = renderData.shadowRenderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &renderData.shadowImageViews.at(frame); + framebufferInfo.width = renderData.shadowMapExtent.width; + framebufferInfo.height = renderData.shadowMapExtent.height; + framebufferInfo.layers = 1; + + vk_check_error(vkCreateFramebuffer(Data::vk_device, &framebufferInfo, nullptr, + &renderData.shadowFramebuffers.at(frame)), + "Failed to create shadow framebuffer!"); + } +} + +void +CreateShadowPipeline() +{ + auto& renderData = Data::renderData_.at(boundApplication_); + auto [vertexInfo, fragmentInfo] = + VulkanShader::CreateShader(Data::vk_device, "shadow.vert.spv", "shadow.frag.spv"); + auto shaderStages = std::to_array({vertexInfo.shaderInfo, fragmentInfo.shaderInfo}); + + auto bindingDescription = Vertex::getBindingDescription(); + auto attributeDescriptions = Vertex::getAttributeDescriptions(); + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.vertexAttributeDescriptionCount = + static_cast< uint32_t >(attributeDescriptions.size()); + vertexInputInfo.pVertexBindingDescriptions = &bindingDescription; + vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + VkViewport viewport = {}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast< float >(renderData.shadowMapExtent.width); + viewport.height = static_cast< float >(renderData.shadowMapExtent.height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset = {0, 0}; + scissor.extent = renderData.shadowMapExtent; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_NONE; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + rasterizer.depthBiasEnable = VK_TRUE; + rasterizer.depthBiasConstantFactor = 1.25f; + rasterizer.depthBiasSlopeFactor = 1.75f; + rasterizer.depthBiasClamp = 0.0f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + depthStencil.depthBoundsTestEnable = VK_FALSE; + depthStencil.stencilTestEnable = VK_FALSE; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.attachmentCount = 0; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &renderData.descriptorSetLayout; + + vk_check_error(vkCreatePipelineLayout(Data::vk_device, &pipelineLayoutInfo, nullptr, + &renderData.shadowPipelineLayout), + "failed to create shadow pipeline layout!"); + + std::array< VkDynamicState, 3 > dynamicStates = {VK_DYNAMIC_STATE_LINE_WIDTH, + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR}; + + VkPipelineDynamicStateCreateInfo dynamicStateInfo = {}; + dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateInfo.dynamicStateCount = static_cast< uint32_t >(dynamicStates.size()); + dynamicStateInfo.pDynamicStates = dynamicStates.data(); + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = static_cast< uint32_t >(shaderStages.size()); + pipelineInfo.pStages = shaderStages.data(); + pipelineInfo.pDynamicState = &dynamicStateInfo; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pDepthStencilState = &depthStencil; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.layout = renderData.shadowPipelineLayout; + pipelineInfo.renderPass = renderData.shadowRenderPass; + pipelineInfo.subpass = 0; + + vk_check_error(vkCreateGraphicsPipelines(Data::vk_device, VK_NULL_HANDLE, 1, &pipelineInfo, + nullptr, &renderData.shadowPipeline), + "failed to create shadow pipeline!"); + + vertexInfo.Destroy(); + fragmentInfo.Destroy(); +} void @@ -499,11 +816,12 @@ CreateColorResources() VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - renderData.colorImage = image.textureImage_; - renderData.colorImageMemory = image.textureImageMemory_; - renderData.colorImageView = Texture::CreateImageView( - renderData.colorImage, renderData.swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1); -} + renderData.colorImage = image.textureImage_; + renderData.colorImageMemory = image.textureImageMemory_; + renderData.colorImageAllocation = image.allocation_; + renderData.colorImageView = Texture::CreateImageView( + renderData.colorImage, renderData.swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1); +} void CreateDepthResources() @@ -515,12 +833,13 @@ CreateDepthResources() renderData.swapChainExtent.width, renderData.swapChainExtent.height, 1, renderer::Data::msaaSamples, depthFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - renderData.depthImage = image.textureImage_; - renderData.depthImageMemory = image.textureImageMemory_; - renderData.depthImageView = - Texture::CreateImageView(renderData.depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1); -} + + renderData.depthImage = image.textureImage_; + renderData.depthImageMemory = image.textureImageMemory_; + renderData.depthImageAllocation = image.allocation_; + renderData.depthImageView = + Texture::CreateImageView(renderData.depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1); +} void CreateImageViews() @@ -658,10 +977,10 @@ CreateCommandPool() "Failed to create command pool!"); } -void -CreateCommandBuffers(Application* app, uint32_t imageIndex) -{ - const auto& renderData = Data::renderData_.at(boundApplication_); +void +CreateCommandBuffers(Application* app, uint32_t imageIndex) +{ + const auto& renderData = Data::renderData_.at(boundApplication_); if (Data::commandBuffers.empty()) { @@ -694,12 +1013,46 @@ CreateCommandBuffers(Application* app, uint32_t imageIndex) renderPassInfo.pClearValues = clearValues.data(); renderPassInfo.framebuffer = renderData.swapChainFramebuffers[imageIndex]; - - vk_check_error(vkBeginCommandBuffer(Data::commandBuffers[Data::currentFrame_], &beginInfo), ""); - - vkCmdSetLineWidth(Data::commandBuffers[Data::currentFrame_], 2.0f); - vkCmdBeginRenderPass(Data::commandBuffers[Data::currentFrame_], &renderPassInfo, - VK_SUBPASS_CONTENTS_INLINE); + + vk_check_error(vkBeginCommandBuffer(Data::commandBuffers[Data::currentFrame_], &beginInfo), ""); + + vkCmdSetLineWidth(Data::commandBuffers[Data::currentFrame_], 2.0f); + + VkClearValue shadowClearValue = {}; + shadowClearValue.depthStencil = {1.0f, 0}; + + VkRenderPassBeginInfo shadowPassInfo = {}; + shadowPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + shadowPassInfo.renderPass = renderData.shadowRenderPass; + shadowPassInfo.framebuffer = renderData.shadowFramebuffers.at(Data::currentFrame_); + shadowPassInfo.renderArea.offset = {0, 0}; + shadowPassInfo.renderArea.extent = renderData.shadowMapExtent; + shadowPassInfo.clearValueCount = 1; + shadowPassInfo.pClearValues = &shadowClearValue; + + vkCmdBeginRenderPass(Data::commandBuffers[Data::currentFrame_], &shadowPassInfo, + VK_SUBPASS_CONTENTS_INLINE); + + VkViewport shadowViewport = {}; + shadowViewport.width = static_cast< float >(renderData.shadowMapExtent.width); + shadowViewport.height = static_cast< float >(renderData.shadowMapExtent.height); + shadowViewport.minDepth = 0.0f; + shadowViewport.maxDepth = 1.0f; + + VkRect2D shadowScissor = {}; + shadowScissor.extent = renderData.shadowMapExtent; + shadowScissor.offset = {0, 0}; + + vkCmdSetViewport(Data::commandBuffers[Data::currentFrame_], 0, 1, &shadowViewport); + vkCmdSetScissor(Data::commandBuffers[Data::currentFrame_], 0, 1, &shadowScissor); + vkCmdBindPipeline(Data::commandBuffers[Data::currentFrame_], VK_PIPELINE_BIND_POINT_GRAPHICS, + renderData.shadowPipeline); + DrawQuadMeshes(Data::commandBuffers[Data::currentFrame_], renderData.shadowPipelineLayout, + renderData.descriptorSets.at(Data::currentFrame_)); + vkCmdEndRenderPass(Data::commandBuffers[Data::currentFrame_]); + + vkCmdBeginRenderPass(Data::commandBuffers[Data::currentFrame_], &renderPassInfo, + VK_SUBPASS_CONTENTS_INLINE); VkViewport viewport = {}; viewport.width = static_cast< float >(renderData.swapChainExtent.width); @@ -718,10 +1071,50 @@ CreateCommandBuffers(Application* app, uint32_t imageIndex) vkCmdSetScissor(Data::commandBuffers[Data::currentFrame_], 0, 1, &scissor); app->Render(Data::commandBuffers[Data::currentFrame_]); - - vkCmdEndRenderPass(Data::commandBuffers[Data::currentFrame_]); - vk_check_error(vkEndCommandBuffer(Data::commandBuffers[Data::currentFrame_]), ""); -} + + vkCmdEndRenderPass(Data::commandBuffers[Data::currentFrame_]); + vk_check_error(vkEndCommandBuffer(Data::commandBuffers[Data::currentFrame_]), ""); +} + +void +DrawQuadMeshes(VkCommandBuffer cmdBuffer, VkPipelineLayout pipelineLayout, VkDescriptorSet descriptorSet, + int32_t renderLayerToDraw, bool alwaysRenderBaseLayer, const void* pushConstants, + uint32_t pushConstantSize, VkShaderStageFlags pushConstantStages) +{ + auto& renderData = Data::renderData_.at(boundApplication_); + + auto offsets = std::to_array< const VkDeviceSize >({0}); + vkCmdBindDescriptorSets(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, + &descriptorSet, 0, nullptr); + + if (pushConstants != nullptr && pushConstantSize > 0) + { + vkCmdPushConstants(cmdBuffer, pipelineLayout, pushConstantStages, 0, pushConstantSize, + pushConstants); + } + + const auto renderAllLayers = renderLayerToDraw == -1; + + for (int32_t layer = NUM_LAYERS - 1; layer >= 0; --layer) + { + const auto idx = static_cast< size_t >(layer); + const auto& numObjects = renderData.numMeshes.at(idx); + + const auto renderThisLayer = + renderAllLayers || (alwaysRenderBaseLayer && layer == 0) || renderLayerToDraw == layer; + + if (numObjects == 0 || !renderThisLayer) + { + continue; + } + + vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &renderData.vertexBuffer.at(idx).buffer_, + offsets.data()); + vkCmdBindIndexBuffer(cmdBuffer, renderData.indexBuffer.at(idx).buffer_, 0, + VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(cmdBuffer, numObjects * INDICES_PER_SPRITE, 1, 0, 0, 0); + } +} void @@ -876,15 +1269,26 @@ UpdateUniformBuffer() auto& renderData = Data::renderData_.at(boundApplication_); for (uint32_t frame = 0; frame < MAX_FRAMES_IN_FLIGHT; ++frame) - { - vkWaitForFences(Data::vk_device, 1, &inFlightFences_[frame], VK_TRUE, UINT64_MAX); - - UniformBufferObject tmpUBO = {}; - - tmpUBO.view = renderData.viewMat; - tmpUBO.proj = renderData.projMat; - - auto& ubo = renderData.uniformBuffers.at(frame); + { + vkWaitForFences(Data::vk_device, 1, &inFlightFences_[frame], VK_TRUE, UINT64_MAX); + + UniformBufferObject tmpUBO = {}; + const auto viewMat = renderData.viewMat[3][3] == 0.0f ? glm::mat4(1.0f) : renderData.viewMat; + const auto projMat = + (renderData.projMat[0][0] == 0.0f || renderData.projMat[1][1] == 0.0f) + ? glm::mat4(1.0f) + : renderData.projMat; + const auto inverseView = glm::inverse(viewMat); + + tmpUBO.view = viewMat; + tmpUBO.proj = projMat; + tmpUBO.cameraPos = glm::vec4(glm::vec3(inverseView[3]), 1.0f); + tmpUBO.lightViewProj = CalculateLightViewProj(renderData); + tmpUBO.lightDirection = renderData.lightDirection; + tmpUBO.lightColor = renderData.lightColor; + tmpUBO.shadowParams = renderData.shadowParams; + + auto& ubo = renderData.uniformBuffers.at(frame); void* data = nullptr; vmaMapMemory(Data::vk_hAllocator, ubo.allocation_, &data); @@ -924,17 +1328,26 @@ UpdatePerInstanceBuffer() } } -void -DestroyPipeline() -{ - vkDeviceWaitIdle(Data::vk_device); - - auto& renderData = Data::renderData_.at(boundApplication_); - - for (size_t i = 0; i < renderData.swapChainImages.size(); ++i) - { - vkDestroyFramebuffer(Data::vk_device, renderData.swapChainFramebuffers[i], nullptr); - vkDestroyImageView(Data::vk_device, renderData.swapChainImageViews[i], nullptr); +void +DestroyPipeline() +{ + vkDeviceWaitIdle(Data::vk_device); + + auto& renderData = Data::renderData_.at(boundApplication_); + + for (auto& framebuffer : renderData.shadowFramebuffers) + { + if (framebuffer != VK_NULL_HANDLE) + { + vkDestroyFramebuffer(Data::vk_device, framebuffer, nullptr); + framebuffer = VK_NULL_HANDLE; + } + } + + for (size_t i = 0; i < renderData.swapChainImages.size(); ++i) + { + vkDestroyFramebuffer(Data::vk_device, renderData.swapChainFramebuffers[i], nullptr); + vkDestroyImageView(Data::vk_device, renderData.swapChainImageViews[i], nullptr); } vkDestroySwapchainKHR(Data::vk_device, renderData.swapChain, nullptr); @@ -943,30 +1356,86 @@ DestroyPipeline() if (renderData.descriptorPool != VK_NULL_HANDLE) { vkDestroyDescriptorPool(Data::vk_device, renderData.descriptorPool, nullptr); - vkDestroyDescriptorSetLayout(Data::vk_device, renderData.descriptorSetLayout, nullptr); - - renderData.descriptorPool = VK_NULL_HANDLE; - } - - renderData.swapChainImages.clear(); - renderData.swapChainImageViews.clear(); - renderData.swapChainFramebuffers.clear(); - renderData.descriptorSets.clear(); - renderData.swapChainImageFormat = VK_FORMAT_UNDEFINED; - - vkDestroyImage(Data::vk_device, renderData.colorImage, nullptr); - vkDestroyImageView(Data::vk_device, renderData.colorImageView, nullptr); - vkFreeMemory(Data::vk_device, renderData.colorImageMemory, nullptr); - - vkDestroyImage(Data::vk_device, renderData.depthImage, nullptr); - vkDestroyImageView(Data::vk_device, renderData.depthImageView, nullptr); - vkFreeMemory(Data::vk_device, renderData.depthImageMemory, nullptr); - - vkDestroyPipeline(Data::vk_device, renderData.pipeline, nullptr); - vkDestroyPipelineLayout(Data::vk_device, renderData.pipelineLayout, nullptr); - vkDestroyPipelineCache(Data::vk_device, renderData.pipelineCache, nullptr); - vkDestroyRenderPass(Data::vk_device, renderData.renderPass, nullptr); -} + vkDestroyDescriptorSetLayout(Data::vk_device, renderData.descriptorSetLayout, nullptr); + + renderData.descriptorPool = VK_NULL_HANDLE; + renderData.descriptorSetLayout = VK_NULL_HANDLE; + } + + renderData.swapChainImages.clear(); + renderData.swapChainImageViews.clear(); + renderData.swapChainFramebuffers.clear(); + renderData.descriptorSets.clear(); + renderData.swapChainImageFormat = VK_FORMAT_UNDEFINED; + + if (renderData.colorImageView != VK_NULL_HANDLE) + { + vkDestroyImageView(Data::vk_device, renderData.colorImageView, nullptr); + renderData.colorImageView = VK_NULL_HANDLE; + } + + if (renderData.colorImage != VK_NULL_HANDLE) + { + vmaDestroyImage(Data::vk_hAllocator, renderData.colorImage, renderData.colorImageAllocation); + renderData.colorImage = VK_NULL_HANDLE; + renderData.colorImageMemory = VK_NULL_HANDLE; + renderData.colorImageAllocation = {}; + } + + if (renderData.depthImageView != VK_NULL_HANDLE) + { + vkDestroyImageView(Data::vk_device, renderData.depthImageView, nullptr); + renderData.depthImageView = VK_NULL_HANDLE; + } + + if (renderData.depthImage != VK_NULL_HANDLE) + { + vmaDestroyImage(Data::vk_hAllocator, renderData.depthImage, renderData.depthImageAllocation); + renderData.depthImage = VK_NULL_HANDLE; + renderData.depthImageMemory = VK_NULL_HANDLE; + renderData.depthImageAllocation = {}; + } + + for (uint32_t frame = 0; frame < MAX_FRAMES_IN_FLIGHT; ++frame) + { + if (renderData.shadowImageViews.at(frame) != VK_NULL_HANDLE) + { + vkDestroyImageView(Data::vk_device, renderData.shadowImageViews.at(frame), nullptr); + renderData.shadowImageViews.at(frame) = VK_NULL_HANDLE; + } + + if (renderData.shadowImages.at(frame) != VK_NULL_HANDLE) + { + vmaDestroyImage(Data::vk_hAllocator, renderData.shadowImages.at(frame), + renderData.shadowImageAllocations.at(frame)); + renderData.shadowImages.at(frame) = VK_NULL_HANDLE; + renderData.shadowImageMemories.at(frame) = VK_NULL_HANDLE; + renderData.shadowImageAllocations.at(frame) = {}; + } + } + + if (renderData.shadowSampler != VK_NULL_HANDLE) + { + vkDestroySampler(Data::vk_device, renderData.shadowSampler, nullptr); + renderData.shadowSampler = VK_NULL_HANDLE; + } + + vkDestroyPipeline(Data::vk_device, renderData.pipeline, nullptr); + vkDestroyPipelineLayout(Data::vk_device, renderData.pipelineLayout, nullptr); + vkDestroyPipelineCache(Data::vk_device, renderData.pipelineCache, nullptr); + vkDestroyRenderPass(Data::vk_device, renderData.renderPass, nullptr); + vkDestroyPipeline(Data::vk_device, renderData.shadowPipeline, nullptr); + vkDestroyPipelineLayout(Data::vk_device, renderData.shadowPipelineLayout, nullptr); + vkDestroyRenderPass(Data::vk_device, renderData.shadowRenderPass, nullptr); + + renderData.pipeline = VK_NULL_HANDLE; + renderData.pipelineLayout = VK_NULL_HANDLE; + renderData.pipelineCache = VK_NULL_HANDLE; + renderData.renderPass = VK_NULL_HANDLE; + renderData.shadowPipeline = VK_NULL_HANDLE; + renderData.shadowPipelineLayout = VK_NULL_HANDLE; + renderData.shadowRenderPass = VK_NULL_HANDLE; +} void UpdateData() @@ -1333,18 +1802,22 @@ CreateRenderPipeline() &renderData.surface), "failed to create window surface!"); - CreateSwapchain(); - CreateImageViews(); - CreateCommandPool(); - CreateRenderPass(); - QuadShader::CreateDescriptorSetLayout(); - CreatePipeline< QuadShader, Vertex >("vert.spv", "frag.spv", PrimitiveType::TRIANGLE); - CreateColorResources(); - CreateDepthResources(); - CreateFramebuffers(); - CreatePipelineCache(); - CreateSyncObjects(); -} + CreateSwapchain(); + CreateImageViews(); + CreateCommandPool(); + QuadShader::CreateDescriptorSetLayout(); + CreateRenderPass(); + CreateShadowRenderPass(); + CreatePipeline< QuadShader, Vertex >("vert.spv", "frag.spv", PrimitiveType::TRIANGLE); + CreateShadowPipeline(); + CreateColorResources(); + CreateDepthResources(); + CreateShadowResources(); + CreateFramebuffers(); + CreateShadowFramebuffers(); + CreatePipelineCache(); + CreateSyncObjects(); +} void Render(Application* app) diff --git a/engine/renderer/renderer.hpp b/engine/renderer/renderer.hpp index 98aee42c..d1c9792f 100644 --- a/engine/renderer/renderer.hpp +++ b/engine/renderer/renderer.hpp @@ -77,11 +77,17 @@ SetupLineData(); void UpdateLineData(uint32_t startingLine = 0); -void -CreateCommandBuffers(Application* app, uint32_t imageIndex); - -void -UpdateDescriptors(); +void +CreateCommandBuffers(Application* app, uint32_t imageIndex); + +void +DrawQuadMeshes(VkCommandBuffer cmdBuffer, VkPipelineLayout pipelineLayout, VkDescriptorSet descriptorSet, + int32_t renderLayerToDraw = -1, bool alwaysRenderBaseLayer = false, + const void* pushConstants = nullptr, uint32_t pushConstantSize = 0, + VkShaderStageFlags pushConstantStages = 0); + +void +UpdateDescriptors(); void UpdateData(); diff --git a/engine/renderer/shader.cpp b/engine/renderer/shader.cpp index 7caf9965..7ec2eee3 100644 --- a/engine/renderer/shader.cpp +++ b/engine/renderer/shader.cpp @@ -56,37 +56,39 @@ VulkanShader::CreateShader(VkDevice device, std::string_view vertex, std::string /////////////////////////////////////////////////////////////////// /////////////////////// QUAD SHADER /////////////////////// /////////////////////////////////////////////////////////////////// -void -QuadShader::CreateDescriptorPool() -{ - auto& renderData = Data::renderData_.at(GetCurrentlyBoundType()); - - std::array< VkDescriptorPoolSize, 2 > poolSizes{}; - poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSizes[0].descriptorCount = static_cast< uint32_t >(renderData.swapChainImages.size()); - poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - poolSizes[1].descriptorCount = static_cast< uint32_t >(renderData.swapChainImages.size()); - - VkDescriptorPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolInfo.poolSizeCount = static_cast< uint32_t >(poolSizes.size()); - poolInfo.pPoolSizes = poolSizes.data(); - poolInfo.maxSets = static_cast< uint32_t >(renderData.swapChainImages.size()); - - vk_check_error( - vkCreateDescriptorPool(Data::vk_device, &poolInfo, nullptr, &renderData.descriptorPool), - "Failed to create descriptor pool!"); +void +QuadShader::CreateDescriptorPool() +{ + auto& renderData = Data::renderData_.at(GetCurrentlyBoundType()); + + std::array< VkDescriptorPoolSize, 3 > poolSizes{}; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[0].descriptorCount = MAX_FRAMES_IN_FLIGHT; + poolSizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + poolSizes[1].descriptorCount = MAX_FRAMES_IN_FLIGHT; + poolSizes[2].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[2].descriptorCount = MAX_FRAMES_IN_FLIGHT * (MAX_NUM_TEXTURES + 1); + + VkDescriptorPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolInfo.poolSizeCount = static_cast< uint32_t >(poolSizes.size()); + poolInfo.pPoolSizes = poolSizes.data(); + poolInfo.maxSets = MAX_FRAMES_IN_FLIGHT; + + vk_check_error( + vkCreateDescriptorPool(Data::vk_device, &poolInfo, nullptr, &renderData.descriptorPool), + "Failed to create descriptor pool!"); } void QuadShader::CreateDescriptorSetLayout() { - VkDescriptorSetLayoutBinding uboLayoutBinding = {}; - uboLayoutBinding.binding = 0; - uboLayoutBinding.descriptorCount = 1; - uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uboLayoutBinding.pImmutableSamplers = nullptr; - uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + VkDescriptorSetLayoutBinding uboLayoutBinding = {}; + uboLayoutBinding.binding = 0; + uboLayoutBinding.descriptorCount = 1; + uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uboLayoutBinding.pImmutableSamplers = nullptr; + uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; VkDescriptorSetLayoutBinding perInstanceBinding = {}; perInstanceBinding.binding = 1; @@ -98,12 +100,19 @@ QuadShader::CreateDescriptorSetLayout() VkDescriptorSetLayoutBinding texturesLayoutBinding = {}; texturesLayoutBinding.binding = 2; texturesLayoutBinding.descriptorCount = MAX_NUM_TEXTURES; - texturesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - texturesLayoutBinding.pImmutableSamplers = nullptr; - texturesLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - - auto bindings = std::to_array< VkDescriptorSetLayoutBinding >( - {uboLayoutBinding, perInstanceBinding, texturesLayoutBinding}); + texturesLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + texturesLayoutBinding.pImmutableSamplers = nullptr; + texturesLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkDescriptorSetLayoutBinding shadowMapBinding = {}; + shadowMapBinding.binding = 3; + shadowMapBinding.descriptorCount = 1; + shadowMapBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + shadowMapBinding.pImmutableSamplers = nullptr; + shadowMapBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + auto bindings = std::to_array< VkDescriptorSetLayoutBinding >( + {uboLayoutBinding, perInstanceBinding, texturesLayoutBinding, shadowMapBinding}); VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; @@ -165,8 +174,8 @@ QuadShader::UpdateDescriptorSets() }); for (uint32_t frame = 0; frame < MAX_FRAMES_IN_FLIGHT; frame++) - { - WaitForFence(frame); + { + WaitForFence(frame); VkDescriptorBufferInfo bufferInfo{}; bufferInfo.buffer = renderData.uniformBuffers.at(frame).buffer_; @@ -176,10 +185,15 @@ QuadShader::UpdateDescriptorSets() VkDescriptorBufferInfo instanceBufferInfo = {}; instanceBufferInfo.buffer = renderData.ssbo.at(frame).buffer_; - instanceBufferInfo.offset = 0; - instanceBufferInfo.range = renderData.ssbo.at(frame).bufferSize_; - - std::array< VkWriteDescriptorSet, 3 > descriptorWrites = {}; + instanceBufferInfo.offset = 0; + instanceBufferInfo.range = renderData.ssbo.at(frame).bufferSize_; + + VkDescriptorImageInfo shadowImageInfo = {}; + shadowImageInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + shadowImageInfo.imageView = renderData.shadowImageViews.at(frame); + shadowImageInfo.sampler = renderData.shadowSampler; + + std::array< VkWriteDescriptorSet, 4 > descriptorWrites = {}; descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrites[0].dstSet = renderData.descriptorSets.at(frame); @@ -198,17 +212,25 @@ QuadShader::UpdateDescriptorSets() descriptorWrites[1].pBufferInfo = &instanceBufferInfo; descriptorWrites[2].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrites[2].dstSet = renderData.descriptorSets.at(frame); - descriptorWrites[2].dstBinding = 2; - descriptorWrites[2].dstArrayElement = 0; - descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorWrites[2].descriptorCount = static_cast< uint32_t >(viewAndSamplers.size()); - descriptorWrites[2].pImageInfo = descriptorImageInfos.data(); - - vkUpdateDescriptorSets(Data::vk_device, static_cast< uint32_t >(descriptorWrites.size()), - descriptorWrites.data(), 0, nullptr); - } -} + descriptorWrites[2].dstSet = renderData.descriptorSets.at(frame); + descriptorWrites[2].dstBinding = 2; + descriptorWrites[2].dstArrayElement = 0; + descriptorWrites[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[2].descriptorCount = MAX_NUM_TEXTURES; + descriptorWrites[2].pImageInfo = descriptorImageInfos.data(); + + descriptorWrites[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[3].dstSet = renderData.descriptorSets.at(frame); + descriptorWrites[3].dstBinding = 3; + descriptorWrites[3].dstArrayElement = 0; + descriptorWrites[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrites[3].descriptorCount = 1; + descriptorWrites[3].pImageInfo = &shadowImageInfo; + + vkUpdateDescriptorSets(Data::vk_device, static_cast< uint32_t >(descriptorWrites.size()), + descriptorWrites.data(), 0, nullptr); + } +} /////////////////////////////////////////////////////////////////// /////////////////////// LINE SHADER /////////////////////// diff --git a/engine/renderer/types.hpp b/engine/renderer/types.hpp index 4e84f2d0..bd5804de 100644 --- a/engine/renderer/types.hpp +++ b/engine/renderer/types.hpp @@ -70,12 +70,16 @@ using TextureMaps = std::array< std::string, 4 >; using TextureID = int32_t; using TextureIDs = std::array< TextureID, 4 >; -struct UniformBufferObject -{ - alignas(16) glm::mat4 proj = {}; - alignas(16) glm::mat4 view = {}; - glm::vec4 cameraPos = {}; -}; +struct UniformBufferObject +{ + alignas(16) glm::mat4 proj = {}; + alignas(16) glm::mat4 view = {}; + alignas(16) glm::vec4 cameraPos = {}; + alignas(16) glm::mat4 lightViewProj = {}; + alignas(16) glm::vec4 lightDirection = {}; + alignas(16) glm::vec4 lightColor = {}; + alignas(16) glm::vec4 shadowParams = {}; +}; struct PerInstanceBuffer { diff --git a/engine/renderer/vulkan_common.hpp b/engine/renderer/vulkan_common.hpp index 08f7d00b..3d4ddadc 100644 --- a/engine/renderer/vulkan_common.hpp +++ b/engine/renderer/vulkan_common.hpp @@ -208,23 +208,41 @@ struct RenderData VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; - VkRenderPass renderPass = VK_NULL_HANDLE; - VkPipeline pipeline = VK_NULL_HANDLE; - VkPipelineCache pipelineCache = VK_NULL_HANDLE; - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - - VkImage depthImage = VK_NULL_HANDLE; - VkDeviceMemory depthImageMemory = VK_NULL_HANDLE; - VkImageView depthImageView = VK_NULL_HANDLE; - - VkImage colorImage = VK_NULL_HANDLE; - VkDeviceMemory colorImageMemory = VK_NULL_HANDLE; - VkImageView colorImageView = VK_NULL_HANDLE; - - glm::mat4 viewMat = {}; - glm::mat4 projMat = {}; - glm::mat4 projNoZoomMat = {}; -}; + VkRenderPass renderPass = VK_NULL_HANDLE; + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineCache pipelineCache = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + + VkRenderPass shadowRenderPass = VK_NULL_HANDLE; + VkPipeline shadowPipeline = VK_NULL_HANDLE; + VkPipelineLayout shadowPipelineLayout = VK_NULL_HANDLE; + VkSampler shadowSampler = VK_NULL_HANDLE; + VkExtent2D shadowMapExtent = {2048, 2048}; + std::array< VkImage, MAX_FRAMES_IN_FLIGHT > shadowImages = {}; + std::array< VkDeviceMemory, MAX_FRAMES_IN_FLIGHT > shadowImageMemories = {}; + std::array< VmaAllocation, MAX_FRAMES_IN_FLIGHT > shadowImageAllocations = {}; + std::array< VkImageView, MAX_FRAMES_IN_FLIGHT > shadowImageViews = {}; + std::array< VkFramebuffer, MAX_FRAMES_IN_FLIGHT > shadowFramebuffers = {}; + + VkImage depthImage = VK_NULL_HANDLE; + VkDeviceMemory depthImageMemory = VK_NULL_HANDLE; + VmaAllocation depthImageAllocation = {}; + VkImageView depthImageView = VK_NULL_HANDLE; + + VkImage colorImage = VK_NULL_HANDLE; + VkDeviceMemory colorImageMemory = VK_NULL_HANDLE; + VmaAllocation colorImageAllocation = {}; + VkImageView colorImageView = VK_NULL_HANDLE; + + glm::mat4 viewMat = {}; + glm::mat4 projMat = {}; + glm::mat4 projNoZoomMat = {}; + + glm::mat4 lightViewProjMat = {}; + glm::vec4 lightDirection = glm::vec4(glm::normalize(glm::vec3(-0.55f, -0.35f, 1.0f)), 0.0f); + glm::vec4 lightColor = glm::vec4(1.0f, 0.96f, 0.88f, 1.0f); + glm::vec4 shadowParams = glm::vec4(0.35f, 0.75f, 0.0015f, 0.0f); +}; /* * This is storage for common Vulkan objects that are needed for numerous