#include "worldpass.h" #include #include #include "renderer.h" #include "world.h" #include "mesh.h" #include "light.h" #include "camera.h" #include "material.h" WorldPass::WorldPass(Renderer& renderer) : renderer_(renderer) { createRenderPass(); createDescriptorSetLayout(); createPipeline(); createUniformBuffer(); createDescriptorSet(); } WorldPass::~WorldPass() { vkDestroyRenderPass(renderer_.getDevice(), renderPass_, nullptr); vkDestroyDescriptorSetLayout(renderer_.getDevice(), setLayout_, nullptr); vkDestroyPipeline(renderer_.getDevice(), pipeline_, nullptr); vkDestroyPipelineLayout(renderer_.getDevice(), pipelineLayout_, nullptr); vkFreeMemory(renderer_.getDevice(), lightMemory_, nullptr); vkDestroyBuffer(renderer_.getDevice(), lightBuffer_, nullptr); } void WorldPass::render(VkCommandBuffer commandBuffer, World& world, Camera& camera, RenderTarget* target) { struct ShaderLight { glm::vec4 position; glm::vec3 color; }; ShaderLight* data; vkMapMemory(renderer_.getDevice(), lightMemory_, 0, sizeof(float) * (4 + 3) * 32, 0, reinterpret_cast(&data)); for(const auto& light : world.lights) { glm::vec3 position; if(light->type == LightType::Point) position = light->position; else position = glm::normalize(glm::vec3(0) - light->position); data->position = glm::vec4(position, ((int)light->type) + 1); data->color = light->color; data++; } vkUnmapMemory(renderer_.getDevice(), lightMemory_); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &descriptorSet_, 0, nullptr); for(const auto& mesh : world.meshes) { vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 1, 1, &mesh->material->set, 0, nullptr); 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), &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); vkCmdBindIndexBuffer(commandBuffer, mesh->indexBuffer, 0, VK_INDEX_TYPE_UINT32); vkCmdDrawIndexed(commandBuffer, mesh->indices.size(), 1, 0, 0, 0); } } void WorldPass::createRenderPass() { VkAttachmentDescription colorAttachment = {}; colorAttachment.format = VK_FORMAT_R32G32B32A32_SFLOAT; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 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 colorAttachmentRef = {}; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkAttachmentReference depthAttachmentRef = {}; depthAttachmentRef.attachment = 1; depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; subpass.pDepthStencilAttachment = &depthAttachmentRef; const std::array attachments = { colorAttachment, depthAttachment }; std::array dependencies; dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; dependencies[0].dstSubpass = 0; dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_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_COLOR_ATTACHMENT_OUTPUT_BIT; dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.attachmentCount = attachments.size(); renderPassInfo.pAttachments = attachments.data(); renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; renderPassInfo.dependencyCount = dependencies.size(); renderPassInfo.pDependencies = dependencies.data(); vkCreateRenderPass(renderer_.getDevice(), &renderPassInfo, nullptr, &renderPass_); } void WorldPass::createDescriptorSetLayout() { VkDescriptorSetLayoutBinding lightBufferBinding = {}; lightBufferBinding.descriptorCount = 1; 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 = bindings.size(); createInfo.pBindings = bindings.data(); vkCreateDescriptorSetLayout(renderer_.getDevice(), &createInfo, nullptr, &setLayout_); } void WorldPass::createPipeline() { VkShaderModule vertShaderModule = renderer_.createShader("shaders/mesh.vert.spv"); VkShaderModule fragShaderModule = renderer_.createShader("shaders/mesh.frag.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"; VkSpecializationMapEntry mapEntry = {}; mapEntry.size = sizeof(int); VkSpecializationInfo specializationInfo = {}; specializationInfo.mapEntryCount = 1; specializationInfo.pMapEntries = &mapEntry; specializationInfo.dataSize = sizeof(int); int shadowFilterPCF = renderer_.getConfig().filterPCF; specializationInfo.pData = &shadowFilterPCF; VkPipelineShaderStageCreateInfo fragShaderStageInfo = {}; fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; fragShaderStageInfo.module = fragShaderModule; fragShaderStageInfo.pName = "main"; fragShaderStageInfo.pSpecializationInfo = &specializationInfo; const std::array shaderStages = {vertShaderStageInfo, fragShaderStageInfo}; VkVertexInputBindingDescription vertexBindingDescription = {}; vertexBindingDescription.stride = sizeof(Vertex); VkVertexInputAttributeDescription positionAttributeDescription = {}; positionAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; VkVertexInputAttributeDescription normalAttributeDescription = {}; normalAttributeDescription.location = 1; normalAttributeDescription.offset = offsetof(Vertex, normal); normalAttributeDescription.format = VK_FORMAT_R32G32B32_SFLOAT; VkVertexInputAttributeDescription uvAttributeDescription = {}; uvAttributeDescription.location = 2; uvAttributeDescription.offset = offsetof(Vertex, uv); uvAttributeDescription .format = VK_FORMAT_R32G32_SFLOAT; const std::array attributes = { positionAttributeDescription, normalAttributeDescription, uvAttributeDescription }; VkPipelineVertexInputStateCreateInfo vertexInputInfo = {}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; vertexInputInfo.vertexBindingDescriptionCount = 1; vertexInputInfo.pVertexBindingDescriptions = &vertexBindingDescription; vertexInputInfo.vertexAttributeDescriptionCount = attributes.size(); vertexInputInfo.pVertexAttributeDescriptions = attributes.data(); 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_BACK_BIT; rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; VkPipelineMultisampleStateCreateInfo multisampling = {}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; colorBlendAttachment.blendEnable = VK_FALSE; VkPipelineColorBlendStateCreateInfo colorBlending = {}; colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; colorBlending.attachmentCount = 1; colorBlending.pAttachments = &colorBlendAttachment; 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; 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 mvpPushConstant = {}; mvpPushConstant.size = sizeof(glm::mat4) * 2; mvpPushConstant.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; const std::array setLayouts = { setLayout_, renderer_.getMaterialSetLayout() }; VkPipelineLayoutCreateInfo pipelineLayoutInfo = {}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = setLayouts.size(); pipelineLayoutInfo.pSetLayouts = setLayouts.data(); pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &mvpPushConstant; vkCreatePipelineLayout(renderer_.getDevice(), &pipelineLayoutInfo, nullptr, &pipelineLayout_); VkGraphicsPipelineCreateInfo pipelineInfo = {}; pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; pipelineInfo.stageCount = shaderStages.size(); pipelineInfo.pStages = shaderStages.data(); pipelineInfo.pVertexInputState = &vertexInputInfo; pipelineInfo.pInputAssemblyState = &inputAssembly; pipelineInfo.pViewportState = &viewportState; pipelineInfo.pRasterizationState = &rasterizer; pipelineInfo.pMultisampleState = &multisampling; pipelineInfo.pDepthStencilState = &depthState; pipelineInfo.pColorBlendState = &colorBlending; pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.layout = pipelineLayout_; pipelineInfo.renderPass = renderPass_; vkCreateGraphicsPipelines(renderer_.getDevice(), nullptr, 1, &pipelineInfo, nullptr, &pipeline_); vkDestroyShaderModule(renderer_.getDevice(), fragShaderModule, nullptr); vkDestroyShaderModule(renderer_.getDevice(), vertShaderModule, nullptr); } void WorldPass::createUniformBuffer() { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = sizeof(float) * (4 + 3) * 32; bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkCreateBuffer(renderer_.getDevice(), &bufferInfo, nullptr, &lightBuffer_); VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(renderer_.getDevice(), lightBuffer_, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); vkAllocateMemory(renderer_.getDevice(), &allocInfo, nullptr, &lightMemory_); vkBindBufferMemory(renderer_.getDevice(), lightBuffer_, lightMemory_, 0); } void WorldPass::createDescriptorSet() { VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; allocInfo.descriptorPool = renderer_.getDescriptorPool(); allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &setLayout_; vkAllocateDescriptorSets(renderer_.getDevice(), &allocInfo, &descriptorSet_); VkDescriptorBufferInfo bufferInfo = {}; bufferInfo.buffer = lightBuffer_; bufferInfo.range = sizeof(float) * (4 + 3) * 32; VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; imageInfo.imageView = renderer_.getShadowPass().getImageView(); imageInfo.sampler = renderer_.getShadowPass().getSampler(); 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 + 3) * 32, 0, reinterpret_cast(&data)); for(uint32_t i = 0; i < (4 + 3) * 32; i++) data[i] = 0.0f; vkUnmapMemory(renderer_.getDevice(), lightMemory_); }