267 lines
11 KiB
C++
267 lines
11 KiB
C++
|
#include "shadowpass.h"
|
||
|
|
||
|
#include <glm/glm.hpp>
|
||
|
#include <glm/gtc/matrix_transform.hpp>
|
||
|
|
||
|
#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<VkDynamicState, 2> 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);
|
||
|
}
|