diff --git a/CMakeLists.txt b/CMakeLists.txt index 62ecd72..5726b27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,8 @@ add_executable(Graph src/postpass.cpp src/dofpass.cpp src/imguipass.cpp - src/skypass.cpp) + src/skypass.cpp + src/shadowpass.cpp) target_compile_options(Graph PUBLIC -fno-exceptions @@ -81,7 +82,8 @@ add_shaders(Graph shaders/imgui.vert shaders/imgui.frag shaders/sky.vert - shaders/sky.frag) + shaders/sky.frag + shaders/shadow.vert) add_data(Graph data/suzanne.obj diff --git a/include/light.h b/include/light.h index bb1482c..1da39c0 100644 --- a/include/light.h +++ b/include/light.h @@ -10,6 +10,8 @@ enum class LightType { class Light { public: LightType type = LightType::Point; - glm::vec3 position = glm::vec3(0), direction = glm::vec3(0); + glm::vec3 position = glm::vec3(0); glm::vec3 color = glm::vec3(1); + + glm::mat4 matrix = glm::mat4(1.0f); }; diff --git a/include/renderer.h b/include/renderer.h index 9e5ddbb..6e65933 100644 --- a/include/renderer.h +++ b/include/renderer.h @@ -7,6 +7,7 @@ #include "dofpass.h" #include "imguipass.h" #include "skypass.h" +#include "shadowpass.h" constexpr int numFrameResources = 2; @@ -128,6 +129,10 @@ public: return *worldPass_; } + ShadowPass& getShadowPass() const { + return *shadowPass_; + } + private: void createInstance(); #ifdef DEBUG @@ -174,4 +179,5 @@ private: DoFPass* dofPass_ = nullptr; ImGuiPass* imguiPass_ = nullptr; SkyPass* skyPass_ = nullptr; + ShadowPass* shadowPass_ = nullptr; }; diff --git a/include/shadowpass.h b/include/shadowpass.h new file mode 100644 index 0000000..870bbb9 --- /dev/null +++ b/include/shadowpass.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +class Renderer; +class World; + +class ShadowPass { +public: + ShadowPass(Renderer& renderer); + ~ShadowPass(); + + void render(VkCommandBuffer commandBuffer, World& world); + + VkImageView getImageView() const { + return shadowImageView_; + } + + VkSampler getSampler() const { + return shadowSampler_; + } + +private: + void createRenderPass(); + void createFramebuffer(); + void createPipeline(); + + VkRenderPass renderPass_ = nullptr; + + VkImage shadowImage_ = nullptr; + VkDeviceMemory shadowMemory_ = nullptr; + VkImageView shadowImageView_ = nullptr; + VkFramebuffer shadowFramebuffer_ = nullptr; + VkSampler shadowSampler_ = nullptr; + + VkPipeline pipeline_ = nullptr; + VkPipelineLayout pipelineLayout_ = nullptr; + + Renderer& renderer_; +}; diff --git a/shaders/mesh.frag b/shaders/mesh.frag index 2487aba..2adc1f7 100644 --- a/shaders/mesh.frag +++ b/shaders/mesh.frag @@ -1,8 +1,9 @@ #version 460 core layout(location = 0) in vec3 inFragPos; -layout(location = 1) in vec3 inNormal; -layout(location = 2) in vec2 inUV; +layout(location = 1) in vec4 inShadowPos; +layout(location = 2) in vec3 inNormal; +layout(location = 3) in vec2 inUV; layout(location = 0) out vec4 outColor; @@ -15,8 +16,41 @@ layout(set = 0, binding = 0) uniform Lights { Light lights[32]; }; +layout(set = 0, binding = 1) uniform sampler2D shadowSampler; layout(set = 1, binding = 0) uniform sampler2D albedoSampler; +float textureProj(vec4 P, vec2 off) { + const vec4 shadowCoord = P / P.w; // perspective divide + + float shadow = 1.0; + if(shadowCoord.z > -1.0 && shadowCoord.z < 1.0) { + const float dist = texture(shadowSampler, shadowCoord.st + off).r; + if(shadowCoord.w > 0.0 && dist < shadowCoord.z) + shadow = 0.1; + } + + return shadow; +} + +float filterPCF(vec4 sc) { + const ivec2 texDim = textureSize(shadowSampler, 0); + const float scale = 1.5; + const float dx = scale * 1.0 / float(texDim.x); + const float dy = scale * 1.0 / float(texDim.y); + const int range = 2; + + float shadowFactor = 0.0; + int count = 0; + for(int x = -range; x <= range; x++) { + for(int y = -range; y <= range; y++) { + shadowFactor += textureProj(sc, vec2(dx * x, dy * y)); + count++; + } + } + + return shadowFactor / count; +} + void main() { vec3 diffuse = vec3(0); for(int i = 0; i < 32; i++) { @@ -29,7 +63,7 @@ void main() { lightDir = normalize(-lights[i].direction.xyz); const float diff = max(dot(norm, lightDir), 0.0); - diffuse += vec3(diff) * lights[i].color; + diffuse += vec3(diff) * lights[i].color * filterPCF(inShadowPos / inShadowPos.w); } outColor = vec4(vec3(0.1) + diffuse * texture(albedoSampler, inUV).rgb, 1.0); diff --git a/shaders/mesh.vert b/shaders/mesh.vert index c23cc32..62da307 100644 --- a/shaders/mesh.vert +++ b/shaders/mesh.vert @@ -5,16 +5,24 @@ layout(location = 1) in vec3 inNormal; layout(location = 2) in vec2 inUV; layout(location = 0) out vec3 outFragPos; -layout(location = 1) out vec3 outNormal; -layout(location = 2) out vec2 outUV; +layout(location = 1) out vec4 outShadowPos; +layout(location = 2) out vec3 outNormal; +layout(location = 3) out vec2 outUV; layout(push_constant) uniform PushConstants { - mat4 mvp; + mat4 vp, lightSpace; } pushConstants; +const mat4 biasMat = mat4( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.5, 0.5, 0.0, 1.0); + void main() { - gl_Position = pushConstants.mvp * vec4(inPosition, 1.0); + gl_Position = pushConstants.vp * vec4(inPosition, 1.0); outFragPos = inPosition; + outShadowPos = (biasMat * pushConstants.lightSpace) * vec4(inPosition, 1.0); outNormal = inNormal; outUV = inUV; } diff --git a/shaders/post.frag b/shaders/post.frag index f12a152..82d9134 100644 --- a/shaders/post.frag +++ b/shaders/post.frag @@ -9,24 +9,24 @@ layout(binding = 1) uniform sampler2D depthSampler; layout(binding = 2) uniform sampler2D nearFieldSampler; layout(binding = 3) uniform sampler2D farFieldSampler; -void main() { - vec3 sceneColor = texture(sceneSampler, inUV).rgb; +void main() { + vec3 sceneColor = texture(sceneSampler, inUV).rgb; // alpha divide reconstruction vec3 farColor = texture(farFieldSampler, inUV).rgb / max(texture(farFieldSampler, inUV).a, 0.0001) * 0.02; vec3 nearColor = texture(nearFieldSampler, inUV).rgb / max(texture(nearFieldSampler, inUV).a, 0.0001) * 0.02; - + // read coc stored in the alpha channel float coc = texture(farFieldSampler, inUV).a; - + // transistion between out of focus and regular scene vec3 farColorBlurred = mix(sceneColor, farColor, clamp(coc, 0.0, 1.0)); - + // smoother transistion between the normal scene and the "out of focus" portions farColorBlurred = mix(sceneColor, farColorBlurred, clamp(0.5 * coc + 1.0, 0.0, 1.0)); - + //float coc2 = texture(nearFieldSampler, inUV).a; //vec3 finalColor = mix(farColorBlurred, nearColor, clamp(clamp(-coc2 - 1.0, 0.0, 1.0) + texture(nearFieldSampler, inUV).a * 8.0, 0.0, 1.0)); - + outColor = vec4(farColorBlurred, 1.0); } diff --git a/shaders/shadow.vert b/shaders/shadow.vert new file mode 100644 index 0000000..ff6a7db --- /dev/null +++ b/shaders/shadow.vert @@ -0,0 +1,11 @@ +#version 460 core + +layout(location = 0) in vec3 inPosition; + +layout(push_constant) uniform PushConstants { + mat4 mvp; +} pushConstants; + +void main() { + gl_Position = pushConstants.mvp * vec4(inPosition, 1.0); +} diff --git a/src/main.cpp b/src/main.cpp index dea51c2..1f2bbe6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -239,7 +239,7 @@ int main(int argc, char* argv[]) { auto light = new Light(); light->type = LightType::Directional; - light->direction = glm::vec3(-0.2, -0.8, 0); + light->position = glm::vec3(66, 56, 25); world.lights.push_back(light); @@ -362,7 +362,8 @@ int main(int argc, char* argv[]) { if(SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) io.MousePos = ImVec2(static_cast(mouseX), static_cast(mouseY)); - ImGui::DragFloat3("Position", &camera.position[0], 0.1f); + ImGui::DragFloat3("Light Position", &world.lights[0]->position[0]); + ImGui::DragFloat3("Camera Position", &camera.position[0], 0.1f); ImGui::DragFloat3("Target", &camera.target[0], 0.1f); ImGui::DragFloat("Aperture", &camera.aperture, 0.01f, 0.0f, 1.0f); ImGui::DragFloat("Focus Distance", &camera.focusDistance); diff --git a/src/renderer.cpp b/src/renderer.cpp index 5000328..45a9de4 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -26,6 +26,7 @@ Renderer::Renderer() { createDescriptorPool(); createMaterialSetLayout(); + shadowPass_ = new ShadowPass(*this); worldPass_ = new WorldPass(*this); postPass_ = new PostPass(*this); dofPass_ = new DoFPass(*this); @@ -41,6 +42,7 @@ Renderer::~Renderer() { delete dofPass_; delete postPass_; delete worldPass_; + delete shadowPass_; vkDestroyDescriptorSetLayout(device_, materialSetLayout_, nullptr); @@ -74,6 +76,8 @@ void Renderer::render(World& world, Camera& camera, RenderTarget* target) { vkBeginCommandBuffer(commandBuffer, &beginInfo); + shadowPass_->render(commandBuffer, world); + VkViewport viewport = {}; viewport.width = target->extent.width; viewport.height = target->extent.height; diff --git a/src/shadowpass.cpp b/src/shadowpass.cpp new file mode 100644 index 0000000..0060ba5 --- /dev/null +++ b/src/shadowpass.cpp @@ -0,0 +1,266 @@ +#include "shadowpass.h" + +#include +#include + +#include "renderer.h" +#include "world.h" +#include "mesh.h" +#include "light.h" + +ShadowPass::ShadowPass(Renderer& renderer) : renderer_(renderer) { + createRenderPass(); + createFramebuffer(); + createPipeline(); +} + +ShadowPass::~ShadowPass() { + vkDestroyPipeline(renderer_.getDevice(), pipeline_, nullptr); + vkDestroyPipelineLayout(renderer_.getDevice(), pipelineLayout_, nullptr); + + vkDestroySampler(renderer_.getDevice(), shadowSampler_, nullptr); + vkDestroyFramebuffer(renderer_.getDevice(), shadowFramebuffer_, nullptr); + vkDestroyImageView(renderer_.getDevice(), shadowImageView_, nullptr); + vkFreeMemory(renderer_.getDevice(), shadowMemory_, nullptr); + vkDestroyImage(renderer_.getDevice(), shadowImage_, nullptr); + + vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr); +} + +void ShadowPass::render(VkCommandBuffer commandBuffer, World& world) { + VkViewport viewport = {}; + viewport.width = 512; + viewport.height = 512; + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(commandBuffer, 0, 1, &viewport); + + VkRect2D scissor = {}; + scissor.extent.width = 512; + scissor.extent.height = 512; + + vkCmdSetScissor(commandBuffer, 0, 1, &scissor); + + VkClearValue clearColor = {}; + clearColor.depthStencil.depth = 1.0f; + + VkRenderPassBeginInfo renderPassBeginInfo = {}; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.framebuffer = shadowFramebuffer_; + renderPassBeginInfo.renderPass = renderPass_; + renderPassBeginInfo.renderArea.extent.width = 512; + renderPassBeginInfo.renderArea.extent.height = 512; + renderPassBeginInfo.clearValueCount = 1; + renderPassBeginInfo.pClearValues = &clearColor; + + vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); + + glm::mat4 lightSpace = glm::mat4(1.0f); + //lightSpace = glm::perspective(glm::radians(75.0f), 1.0f, 0.1f, 100.0f); + lightSpace = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 0.1f, 100.0f); + lightSpace *= glm::lookAt(world.lights[0]->position, glm::vec3(0), glm::vec3(0, -1, 0)); + + world.lights[0]->matrix = lightSpace; + + for(const auto& mesh : world.meshes) { + glm::mat4 mvp = world.lights[0]->matrix; + mvp = glm::translate(mvp, mesh->position); + + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp); + + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); + + vkCmdDrawIndexed(commandBuffer, mesh->indices.size(), 1, 0, 0, 0); + } + + vkCmdEndRenderPass(commandBuffer); +} + +void ShadowPass::createRenderPass() { + VkAttachmentDescription depthAttachment = {}; + depthAttachment.format = VK_FORMAT_D32_SFLOAT; + 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_SHADER_READ_ONLY_OPTIMAL; + + VkAttachmentReference depthAttachmentRef = {}; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = 1; + renderPassInfo.pAttachments = &depthAttachment; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + + vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_); +} + +void ShadowPass::createFramebuffer() { + VkImageCreateInfo imageCreateInfo = {}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = VK_FORMAT_D32_SFLOAT; + imageCreateInfo.extent.width = 512; + imageCreateInfo.extent.height = 512; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + + vkCreateImage(renderer_.getDevice(), &imageCreateInfo, nullptr, &shadowImage_); + + VkMemoryRequirements memoryRequirements = {}; + vkGetImageMemoryRequirements(renderer_.getDevice(), shadowImage_, &memoryRequirements); + + VkMemoryAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memoryRequirements.size; + allocateInfo.memoryTypeIndex = renderer_.findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(renderer_.getDevice(), &allocateInfo, nullptr, &shadowMemory_); + vkBindImageMemory(renderer_.getDevice(), shadowImage_, shadowMemory_, 0); + + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = shadowImage_; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = VK_FORMAT_D32_SFLOAT; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(renderer_.getDevice(), &createInfo, nullptr, &shadowImageView_); + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = renderPass_; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &shadowImageView_; + framebufferInfo.width = 512; + framebufferInfo.height = 512; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(renderer_.getDevice(), &framebufferInfo, nullptr, &shadowFramebuffer_); + + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + 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.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + + vkCreateSampler(renderer_.getDevice(), &samplerInfo, nullptr, &shadowSampler_); +} + +void ShadowPass::createPipeline() { + VkShaderModule vertShaderModule = renderer_.createShader("shaders/shadow.vert.spv"); + + VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertShaderModule; + vertShaderStageInfo.pName = "main"; + + VkVertexInputBindingDescription vertexBindingDescription = {}; + vertexBindingDescription.stride = sizeof(Vertex); + + VkVertexInputAttributeDescription positionAttributeDescription = {}; + positionAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; + + VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 1; + vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription; + vertexInputInfo.vertexAttributeDescriptionCount = 1; + vertexInputInfo.pVertexAttributeDescriptions = &positionAttributeDescription; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT; + rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rasterizer.depthBiasEnable = VK_TRUE; + rasterizer.depthBiasConstantFactor = 1.25f; + rasterizer.depthBiasSlopeFactor = 1.75f; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + + VkPipelineDepthStencilStateCreateInfo depthState = {}; + depthState.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthState.depthTestEnable = VK_TRUE; + depthState.depthWriteEnable = VK_TRUE; + depthState.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; + + const std::array dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = dynamicStates.size(); + dynamicState.pDynamicStates = dynamicStates.data(); + + VkPushConstantRange pushConstant = {}; + pushConstant.size = sizeof(glm::mat4); + pushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstant; + + vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); + + VkGraphicsPipelineCreateInfo pipelineInfo = {}; + pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipelineInfo.stageCount = 1; + pipelineInfo.pStages = &vertShaderStageInfo; + pipelineInfo.pVertexInputState = &vertexInputInfo; + pipelineInfo.pInputAssemblyState = &inputAssembly; + pipelineInfo.pViewportState = &viewportState; + pipelineInfo.pRasterizationState = &rasterizer; + pipelineInfo.pMultisampleState = &multisampling; + pipelineInfo.pColorBlendState = &colorBlending; + pipelineInfo.pDepthStencilState = &depthState; + pipelineInfo.pDynamicState = &dynamicState; + pipelineInfo.layout = pipelineLayout_; + pipelineInfo.renderPass = renderPass_; + + vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_); + + vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); +} diff --git a/src/worldpass.cpp b/src/worldpass.cpp index 3fcb55d..41c60bd 100644 --- a/src/worldpass.cpp +++ b/src/worldpass.cpp @@ -41,7 +41,7 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& came for(const auto& light : world.lights) { data->position = glm::vec4(light->position, (int)light->type); - data->direction = glm::vec4(light->direction, 0.0); + data->direction = glm::vec4(glm::normalize(glm::vec3(0) - light->position), 0.0); data->color = light->color; data++; @@ -55,12 +55,13 @@ void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& came for(const auto& mesh : world.meshes) { vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 1, 1, &mesh->material->set, 0, nullptr); - glm::mat4 mvp; - mvp = glm::perspective(glm::radians(75.0f), (float)target->extent.width / target->extent.height, camera.near, camera.far); - mvp *= glm::lookAt(camera.position, camera.target, glm::vec3(0, -1, 0)); - mvp = glm::translate(mvp, mesh->position); + glm::mat4 vp; + vp = glm::perspective(glm::radians(75.0f), (float)target->extent.width / target->extent.height, camera.near, camera.far); + vp *= glm::lookAt(camera.position, camera.target, glm::vec3(0, -1, 0)); - vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &mvp); + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &vp); + + vkCmdPushConstants(commandBuffer, pipelineLayout_, VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), sizeof(glm::mat4), &world.lights[0]->matrix); VkDeviceSize offsets[] = {0}; vkCmdBindVertexBuffers(commandBuffer, 0, 1, &mesh->vertexBuffer, offsets); @@ -144,10 +145,21 @@ void WorldPass::createDescriptorSetLayout() { lightBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; lightBufferBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + VkDescriptorSetLayoutBinding shadowBinding = {}; + shadowBinding.descriptorCount = 1; + shadowBinding.binding = 1; + shadowBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + shadowBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + const std::array bindings = { + lightBufferBinding, + shadowBinding + }; + VkDescriptorSetLayoutCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - createInfo.bindingCount = 1; - createInfo.pBindings = &lightBufferBinding; + createInfo.bindingCount = bindings.size(); + createInfo.pBindings = bindings.data(); vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_); } @@ -245,7 +257,7 @@ void WorldPass::createPipeline() { dynamicState.pDynamicStates = dynamicStates.data(); VkPushConstantRange mvpPushConstant = {}; - mvpPushConstant.size = sizeof(glm::mat4); + mvpPushConstant.size = sizeof(glm::mat4) * 2; mvpPushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; const std::array setLayouts = { @@ -317,14 +329,32 @@ void WorldPass::createDescriptorSet() { bufferInfo.buffer = lightBuffer_; bufferInfo.range = sizeof(float) * (4 + 4 + 3) * 32; - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.descriptorCount = 1; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - descriptorWrite.dstSet = descriptorSet_; - descriptorWrite.pBufferInfo = &bufferInfo; + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = renderer_.getShadowPass().getImageView(); + imageInfo.sampler = renderer_.getShadowPass().getSampler(); - vkUpdateDescriptorSets(renderer_.getDevice(), 1, &descriptorWrite, 0, nullptr); + VkWriteDescriptorSet bufferDescriptorWrite = {}; + bufferDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + bufferDescriptorWrite.descriptorCount = 1; + bufferDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + bufferDescriptorWrite.dstSet = descriptorSet_; + bufferDescriptorWrite.pBufferInfo = &bufferInfo; + + VkWriteDescriptorSet shadowDescriptorWrite = {}; + shadowDescriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + shadowDescriptorWrite.descriptorCount = 1; + shadowDescriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + shadowDescriptorWrite.dstBinding = 1; + shadowDescriptorWrite.dstSet = descriptorSet_; + shadowDescriptorWrite.pImageInfo = &imageInfo; + + const std::array descriptorWrites = { + bufferDescriptorWrite, + shadowDescriptorWrite + }; + + vkUpdateDescriptorSets(renderer_.getDevice(), descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); float* data; vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 4 + 3) * 32, 0, reinterpret_cast(&data));