重构完成到main

ink-soul 2024-04-08 15:45:52 +08:00
parent 83d35012e6
commit a74853688c
10 changed files with 1411 additions and 1545 deletions

View File

@ -0,0 +1,796 @@
#include "PBR.h"
void PBR::Material::generateCubemap()
{
enum Target { IRRADIANCE = 0, PREFILTEREDENV = 1 };
for (uint32_t target = 0; target < PREFILTEREDENV + 1; target++) {
vks::TextureCubeMap cubemap;
auto tStart = std::chrono::high_resolution_clock::now();
VkFormat format;
int32_t dim;
switch (target) {
case IRRADIANCE:
format = VK_FORMAT_R32G32B32A32_SFLOAT;
dim = 64;
break;
case PREFILTEREDENV:
format = VK_FORMAT_R16G16B16A16_SFLOAT;
dim = 512;
break;
};
const uint32_t numMips = static_cast<uint32_t>(floor(log2(dim))) + 1;
// Create target cubemap
{
// Image
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = format;
imageCI.extent.width = dim;
imageCI.extent.height = dim;
imageCI.extent.depth = 1;
imageCI.mipLevels = numMips;
imageCI.arrayLayers = 6;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
imageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
VK_CHECK_RESULT(vkCreateImage(VulkanBackend::VulkanFoundation::device, &imageCI, nullptr, &cubemap.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(VulkanBackend::VulkanFoundation::device, cubemap.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = VulkanBackend::VulkanFoundation::vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(VulkanBackend::VulkanFoundation::device, &memAllocInfo, nullptr, &cubemap.deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(VulkanBackend::VulkanFoundation::device, cubemap.image, cubemap.deviceMemory, 0));
// View
VkImageViewCreateInfo viewCI{};
viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
viewCI.format = format;
viewCI.subresourceRange = {};
viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCI.subresourceRange.levelCount = numMips;
viewCI.subresourceRange.layerCount = 6;
viewCI.image = cubemap.image;
VK_CHECK_RESULT(vkCreateImageView(VulkanBackend::VulkanFoundation::device, &viewCI, nullptr, &cubemap.view));
// Sampler
VkSamplerCreateInfo samplerCI{};
samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCI.magFilter = VK_FILTER_LINEAR;
samplerCI.minFilter = VK_FILTER_LINEAR;
samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.minLod = 0.0f;
samplerCI.maxLod = static_cast<float>(numMips);
samplerCI.maxAnisotropy = 1.0f;
samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(VulkanBackend::VulkanFoundation::device, &samplerCI, nullptr, &cubemap.sampler));
}
// FB, Att, RP, Pipe, etc.
VkAttachmentDescription attDesc{};
// Color attachment
attDesc.format = format;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpassDescription{};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
// Use subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> 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;
// Renderpass
VkRenderPassCreateInfo renderPassCI{};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCI.attachmentCount = 1;
renderPassCI.pAttachments = &attDesc;
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = 2;
renderPassCI.pDependencies = dependencies.data();
VkRenderPass renderpass;
VK_CHECK_RESULT(vkCreateRenderPass(VulkanBackend::VulkanFoundation::device, &renderPassCI, nullptr, &renderpass));
// Create offscreen framebuffer
{
// Image
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = format;
imageCI.extent.width = dim;
imageCI.extent.height = dim;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
VK_CHECK_RESULT(vkCreateImage(VulkanBackend::VulkanFoundation::device, &imageCI, nullptr, &offscreen.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(VulkanBackend::VulkanFoundation::device, offscreen.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = VulkanBackend::VulkanFoundation::vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(VulkanBackend::VulkanFoundation::device, &memAllocInfo, nullptr, &offscreen.memory));
VK_CHECK_RESULT(vkBindImageMemory(VulkanBackend::VulkanFoundation::device, offscreen.image, offscreen.memory, 0));
// View
VkImageViewCreateInfo viewCI{};
viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCI.format = format;
viewCI.flags = 0;
viewCI.subresourceRange = {};
viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCI.subresourceRange.baseMipLevel = 0;
viewCI.subresourceRange.levelCount = 1;
viewCI.subresourceRange.baseArrayLayer = 0;
viewCI.subresourceRange.layerCount = 1;
viewCI.image = offscreen.image;
VK_CHECK_RESULT(vkCreateImageView(VulkanBackend::VulkanFoundation::device, &viewCI, nullptr, &offscreen.view));
// Framebuffer
VkFramebufferCreateInfo framebufferCI{};
framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferCI.renderPass = renderpass;
framebufferCI.attachmentCount = 1;
framebufferCI.pAttachments = &offscreen.view;
framebufferCI.width = dim;
framebufferCI.height = dim;
framebufferCI.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(VulkanBackend::VulkanFoundation::device, &framebufferCI, nullptr, &offscreen.framebuffer));
VkCommandBuffer layoutCmd = VulkanBackend::VulkanFoundation::vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = offscreen.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(layoutCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
VulkanBackend::VulkanFoundation::vulkanDevice->flushCommandBuffer(layoutCmd, VulkanBackend::VulkanFoundation::graphicQueue, true);
}
// Descriptors
VkDescriptorSetLayout descriptorsetlayout;
VkDescriptorSetLayoutBinding setLayoutBinding = { 0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT, nullptr };
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCI.pBindings = &setLayoutBinding;
descriptorSetLayoutCI.bindingCount = 1;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(VulkanBackend::VulkanFoundation::device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout));
// Descriptor Pool
VkDescriptorPoolSize poolSize = { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1 };
VkDescriptorPoolCreateInfo descriptorPoolCI{};
descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolCI.poolSizeCount = 1;
descriptorPoolCI.pPoolSizes = &poolSize;
descriptorPoolCI.maxSets = 2;
VkDescriptorPool descriptorpool;
VK_CHECK_RESULT(vkCreateDescriptorPool(VulkanBackend::VulkanFoundation::device, &descriptorPoolCI, nullptr, &descriptorpool));
// Descriptor sets
VkDescriptorSet descriptorset;
VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocInfo.descriptorPool = descriptorpool;
descriptorSetAllocInfo.pSetLayouts = &descriptorsetlayout;
descriptorSetAllocInfo.descriptorSetCount = 1;
VK_CHECK_RESULT(vkAllocateDescriptorSets(VulkanBackend::VulkanFoundation::device, &descriptorSetAllocInfo, &descriptorset));
VkWriteDescriptorSet writeDescriptorSet{};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSet.descriptorCount = 1;
writeDescriptorSet.dstSet = descriptorset;
writeDescriptorSet.dstBinding = 0;
writeDescriptorSet.pImageInfo = &textures.environmentCube.descriptor;
vkUpdateDescriptorSets(VulkanBackend::VulkanFoundation::device, 1, &writeDescriptorSet, 0, nullptr);
// Pipeline layout
VkPipelineLayout pipelinelayout;
VkPushConstantRange pushConstantRange{};
pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
switch (target) {
case IRRADIANCE:
pushConstantRange.size = sizeof(IrradiancePushBlock);
break;
case PREFILTEREDENV:
pushConstantRange.size = sizeof(PrefilterPushBlock);
break;
};
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &descriptorsetlayout;
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(VulkanBackend::VulkanFoundation::device, &pipelineLayoutCI, nullptr, &pipelinelayout));
// Pipeline
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &blendAttachmentState;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilStateCI.depthTestEnable = VK_FALSE;
depthStencilStateCI.depthWriteEnable = VK_FALSE;
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencilStateCI.front = depthStencilStateCI.back;
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
VkPipelineViewportStateCreateInfo viewportStateCI{};
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCI.viewportCount = 1;
viewportStateCI.scissorCount = 1;
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
// Vertex input state
VkVertexInputBindingDescription vertexInputBinding = { 0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX };
VkVertexInputAttributeDescription vertexInputAttribute = { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0 };
VkPipelineVertexInputStateCreateInfo vertexInputStateCI{};
vertexInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputStateCI.vertexBindingDescriptionCount = 1;
vertexInputStateCI.pVertexBindingDescriptions = &vertexInputBinding;
vertexInputStateCI.vertexAttributeDescriptionCount = 1;
vertexInputStateCI.pVertexAttributeDescriptions = &vertexInputAttribute;
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCI{};
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCI.layout = pipelinelayout;
pipelineCI.renderPass = renderpass;
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCI.pVertexInputState = &vertexInputStateCI;
pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pViewportState = &viewportStateCI;
pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCI.stageCount = 2;
pipelineCI.pStages = shaderStages.data();
pipelineCI.renderPass = renderpass;
shaderStages[0] = loadShader(VulkanBackend::VulkanFoundation::device, PlumageRender::Setter::filePath.filterVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT);
switch (target) {
case IRRADIANCE:
shaderStages[1] = loadShader(VulkanBackend::VulkanFoundation::device, PlumageRender::Setter::filePath.irradianceFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT);
break;
case PREFILTEREDENV:
shaderStages[1] = loadShader(VulkanBackend::VulkanFoundation::device, PlumageRender::Setter::filePath.prefilterEnvmapFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT);
break;
};
VkPipeline pipeline;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(VulkanBackend::VulkanFoundation::device, VulkanBackend::VulkanFoundation::pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
for (auto shaderStage : shaderStages) {
vkDestroyShaderModule(VulkanBackend::VulkanFoundation::device, shaderStage.module, nullptr);
}
// Render cubemap
VkClearValue clearValues[1];
clearValues[0].color = { { 0.0f, 0.0f, 0.2f, 0.0f } };
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderpass;
renderPassBeginInfo.framebuffer = offscreen.framebuffer;
renderPassBeginInfo.renderArea.extent.width = dim;
renderPassBeginInfo.renderArea.extent.height = dim;
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = clearValues;
std::vector<glm::mat4> matrices = {
glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(0.0f, 1.0f, 0.0f)), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(-90.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(1.0f, 0.0f, 0.0f)),
glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0.0f, 0.0f, 1.0f)),
};
VkCommandBuffer cmdBuf = VulkanBackend::VulkanFoundation::vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false);
VkViewport viewport{};
viewport.width = (float)dim;
viewport.height = (float)dim;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.extent.width = dim;
scissor.extent.height = dim;
VkImageSubresourceRange subresourceRange{};
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = numMips;
subresourceRange.layerCount = 6;
// Change image layout for all cubemap faces to transfer destination
{
VulkanBackend::VulkanFoundation::vulkanDevice->beginCommandBuffer(cmdBuf);
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = cubemap.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.subresourceRange = subresourceRange;
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
VulkanBackend::VulkanFoundation::vulkanDevice->flushCommandBuffer(cmdBuf, VulkanBackend::VulkanFoundation::graphicQueue, false);
}
for (uint32_t m = 0; m < numMips; m++) {
for (uint32_t f = 0; f < 6; f++) {
VulkanBackend::VulkanFoundation::vulkanDevice->beginCommandBuffer(cmdBuf);
viewport.width = static_cast<float>(dim * std::pow(0.5f, m));
viewport.height = static_cast<float>(dim * std::pow(0.5f, m));
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
// Render scene from cube face's point of view
vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
// Pass parameters for current pass using a push constant block
switch (target) {
case IRRADIANCE:
irradiancePushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f];
vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(IrradiancePushBlock), &irradiancePushBlock);
break;
case PREFILTEREDENV:
prefilterPushBlock.mvp = glm::perspective((float)(M_PI / 2.0), 1.0f, 0.1f, 512.0f) * matrices[f];
prefilterPushBlock.roughness = (float)m / (float)(numMips - 1);
vkCmdPushConstants(cmdBuf, pipelinelayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PrefilterPushBlock), &prefilterPushBlock);
break;
};
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelinelayout, 0, 1, &descriptorset, 0, NULL);
VkDeviceSize offsets[1] = { 0 };
PlumageRender::renderMain::models.skybox.draw(cmdBuf);
vkCmdEndRenderPass(cmdBuf);
VkImageSubresourceRange subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subresourceRange.baseMipLevel = 0;
subresourceRange.levelCount = numMips;
subresourceRange.layerCount = 6;
{
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = offscreen.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
// Copy region for transfer from framebuffer to cube face
VkImageCopy copyRegion{};
copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.mipLevel = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcOffset = { 0, 0, 0 };
copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.dstSubresource.baseArrayLayer = f;
copyRegion.dstSubresource.mipLevel = m;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstOffset = { 0, 0, 0 };
copyRegion.extent.width = static_cast<uint32_t>(viewport.width);
copyRegion.extent.height = static_cast<uint32_t>(viewport.height);
copyRegion.extent.depth = 1;
vkCmdCopyImage(
cmdBuf,
offscreen.image,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
cubemap.image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&copyRegion);
{
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = offscreen.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
}
VulkanBackend::VulkanFoundation::vulkanDevice->flushCommandBuffer(cmdBuf, VulkanBackend::VulkanFoundation::graphicQueue, false);
}
}
{
VulkanBackend::VulkanFoundation::vulkanDevice->beginCommandBuffer(cmdBuf);
VkImageMemoryBarrier imageMemoryBarrier{};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.image = cubemap.image;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.subresourceRange = subresourceRange;
vkCmdPipelineBarrier(cmdBuf, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
VulkanBackend::VulkanFoundation::vulkanDevice->flushCommandBuffer(cmdBuf, VulkanBackend::VulkanFoundation::graphicQueue, false);
}
vkDestroyRenderPass(VulkanBackend::VulkanFoundation::device, renderpass, nullptr);
vkDestroyFramebuffer(VulkanBackend::VulkanFoundation::device, offscreen.framebuffer, nullptr);
vkFreeMemory(VulkanBackend::VulkanFoundation::device, offscreen.memory, nullptr);
vkDestroyImageView(VulkanBackend::VulkanFoundation::device, offscreen.view, nullptr);
vkDestroyImage(VulkanBackend::VulkanFoundation::device, offscreen.image, nullptr);
vkDestroyDescriptorPool(VulkanBackend::VulkanFoundation::device, descriptorpool, nullptr);
vkDestroyDescriptorSetLayout(VulkanBackend::VulkanFoundation::device, descriptorsetlayout, nullptr);
vkDestroyPipeline(VulkanBackend::VulkanFoundation::device, pipeline, nullptr);
vkDestroyPipelineLayout(VulkanBackend::VulkanFoundation::device, pipelinelayout, nullptr);
cubemap.descriptor.imageView = cubemap.view;
cubemap.descriptor.sampler = cubemap.sampler;
cubemap.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
cubemap.device = VulkanBackend::VulkanFoundation::vulkanDevice;
switch (target) {
case IRRADIANCE:
textures.irradianceCube = cubemap;
break;
case PREFILTEREDENV:
textures.prefilteredCube = cubemap;
shaderData.prefilteredCubeMipLevels = static_cast<float>(numMips);
break;
};
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
std::cout << "Generating cube map with " << numMips << " mip levels took " << tDiff << " ms" << std::endl;
}
}
void PBR::Material::generateBRDFLUT()
{
auto tStart = std::chrono::high_resolution_clock::now();
const VkFormat format = VK_FORMAT_R16G16_SFLOAT;
const int32_t dim = 512;
// Image
VkImageCreateInfo imageCI{};
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = format;
imageCI.extent.width = dim;
imageCI.extent.height = dim;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
VK_CHECK_RESULT(vkCreateImage(VulkanBackend::VulkanFoundation::device, &imageCI, nullptr, &textures.lutBrdf.image));
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(VulkanBackend::VulkanFoundation::device, textures.lutBrdf.image, &memReqs);
VkMemoryAllocateInfo memAllocInfo{};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.allocationSize = memReqs.size;
memAllocInfo.memoryTypeIndex = VulkanBackend::VulkanFoundation::vulkanDevice->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
VK_CHECK_RESULT(vkAllocateMemory(VulkanBackend::VulkanFoundation::device, &memAllocInfo, nullptr, &textures.lutBrdf.deviceMemory));
VK_CHECK_RESULT(vkBindImageMemory(VulkanBackend::VulkanFoundation::device, textures.lutBrdf.image, textures.lutBrdf.deviceMemory, 0));
// View
VkImageViewCreateInfo viewCI{};
viewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
viewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewCI.format = format;
viewCI.subresourceRange = {};
viewCI.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
viewCI.subresourceRange.levelCount = 1;
viewCI.subresourceRange.layerCount = 1;
viewCI.image = textures.lutBrdf.image;
VK_CHECK_RESULT(vkCreateImageView(VulkanBackend::VulkanFoundation::device, &viewCI, nullptr, &textures.lutBrdf.view));
// Sampler
VkSamplerCreateInfo samplerCI{};
samplerCI.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCI.magFilter = VK_FILTER_LINEAR;
samplerCI.minFilter = VK_FILTER_LINEAR;
samplerCI.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCI.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
samplerCI.minLod = 0.0f;
samplerCI.maxLod = 1.0f;
samplerCI.maxAnisotropy = 1.0f;
samplerCI.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
VK_CHECK_RESULT(vkCreateSampler(VulkanBackend::VulkanFoundation::device, &samplerCI, nullptr, &textures.lutBrdf.sampler));
// FB, Att, RP, Pipe, etc.
VkAttachmentDescription attDesc{};
// Color attachment
attDesc.format = format;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attDesc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
attDesc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attDesc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
attDesc.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
VkAttachmentReference colorReference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
VkSubpassDescription subpassDescription{};
subpassDescription.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpassDescription.colorAttachmentCount = 1;
subpassDescription.pColorAttachments = &colorReference;
// Use subpass dependencies for layout transitions
std::array<VkSubpassDependency, 2> 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;
// Create the actual renderpass
VkRenderPassCreateInfo renderPassCI{};
renderPassCI.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassCI.attachmentCount = 1;
renderPassCI.pAttachments = &attDesc;
renderPassCI.subpassCount = 1;
renderPassCI.pSubpasses = &subpassDescription;
renderPassCI.dependencyCount = 2;
renderPassCI.pDependencies = dependencies.data();
VkRenderPass renderpass;
VK_CHECK_RESULT(vkCreateRenderPass(VulkanBackend::VulkanFoundation::device, &renderPassCI, nullptr, &renderpass));
VkFramebufferCreateInfo framebufferCI{};
framebufferCI.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferCI.renderPass = renderpass;
framebufferCI.attachmentCount = 1;
framebufferCI.pAttachments = &textures.lutBrdf.view;
framebufferCI.width = dim;
framebufferCI.height = dim;
framebufferCI.layers = 1;
VkFramebuffer framebuffer;
VK_CHECK_RESULT(vkCreateFramebuffer(VulkanBackend::VulkanFoundation::device, &framebufferCI, nullptr, &framebuffer));
// Desriptors
VkDescriptorSetLayout descriptorsetlayout;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI{};
descriptorSetLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(VulkanBackend::VulkanFoundation::device, &descriptorSetLayoutCI, nullptr, &descriptorsetlayout));
// Pipeline layout
VkPipelineLayout pipelinelayout;
VkPipelineLayoutCreateInfo pipelineLayoutCI{};
pipelineLayoutCI.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCI.setLayoutCount = 1;
pipelineLayoutCI.pSetLayouts = &descriptorsetlayout;
VK_CHECK_RESULT(vkCreatePipelineLayout(VulkanBackend::VulkanFoundation::device, &pipelineLayoutCI, nullptr, &pipelinelayout));
// Pipeline
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI{};
inputAssemblyStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
inputAssemblyStateCI.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI{};
rasterizationStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizationStateCI.polygonMode = VK_POLYGON_MODE_FILL;
rasterizationStateCI.cullMode = VK_CULL_MODE_NONE;
rasterizationStateCI.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
rasterizationStateCI.lineWidth = 1.0f;
VkPipelineColorBlendAttachmentState blendAttachmentState{};
blendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
blendAttachmentState.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI{};
colorBlendStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
colorBlendStateCI.attachmentCount = 1;
colorBlendStateCI.pAttachments = &blendAttachmentState;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI{};
depthStencilStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
depthStencilStateCI.depthTestEnable = VK_FALSE;
depthStencilStateCI.depthWriteEnable = VK_FALSE;
depthStencilStateCI.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
depthStencilStateCI.front = depthStencilStateCI.back;
depthStencilStateCI.back.compareOp = VK_COMPARE_OP_ALWAYS;
VkPipelineViewportStateCreateInfo viewportStateCI{};
viewportStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewportStateCI.viewportCount = 1;
viewportStateCI.scissorCount = 1;
VkPipelineMultisampleStateCreateInfo multisampleStateCI{};
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampleStateCI.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
std::vector<VkDynamicState> dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
VkPipelineDynamicStateCreateInfo dynamicStateCI{};
dynamicStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamicStateCI.pDynamicStates = dynamicStateEnables.data();
dynamicStateCI.dynamicStateCount = static_cast<uint32_t>(dynamicStateEnables.size());
VkPipelineVertexInputStateCreateInfo emptyInputStateCI{};
emptyInputStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
std::array<VkPipelineShaderStageCreateInfo, 2> shaderStages;
VkGraphicsPipelineCreateInfo pipelineCI{};
pipelineCI.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCI.layout = pipelinelayout;
pipelineCI.renderPass = renderpass;
pipelineCI.pInputAssemblyState = &inputAssemblyStateCI;
pipelineCI.pVertexInputState = &emptyInputStateCI;
pipelineCI.pRasterizationState = &rasterizationStateCI;
pipelineCI.pColorBlendState = &colorBlendStateCI;
pipelineCI.pMultisampleState = &multisampleStateCI;
pipelineCI.pViewportState = &viewportStateCI;
pipelineCI.pDepthStencilState = &depthStencilStateCI;
pipelineCI.pDynamicState = &dynamicStateCI;
pipelineCI.stageCount = 2;
pipelineCI.pStages = shaderStages.data();
// Look-up-table (from BRDF) pipeline
shaderStages = {
loadShader(VulkanBackend::VulkanFoundation::device,PlumageRender::Setter::filePath.brdfVertShaderPath, VK_SHADER_STAGE_VERTEX_BIT),
loadShader(VulkanBackend::VulkanFoundation::device,PlumageRender::Setter::filePath.brdfFragShaderPath, VK_SHADER_STAGE_FRAGMENT_BIT)
};
VkPipeline pipeline;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(VulkanBackend::VulkanFoundation::device, VulkanBackend::VulkanFoundation::pipelineCache, 1, &pipelineCI, nullptr, &pipeline));
for (auto shaderStage : shaderStages) {
vkDestroyShaderModule(VulkanBackend::VulkanFoundation::device, shaderStage.module, nullptr);
}
// Render
VkClearValue clearValues[1];
clearValues[0].color = { { 0.0f, 0.0f, 0.0f, 1.0f } };
VkRenderPassBeginInfo renderPassBeginInfo{};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.renderPass = renderpass;
renderPassBeginInfo.renderArea.extent.width = dim;
renderPassBeginInfo.renderArea.extent.height = dim;
renderPassBeginInfo.clearValueCount = 1;
renderPassBeginInfo.pClearValues = clearValues;
renderPassBeginInfo.framebuffer = framebuffer;
VkCommandBuffer cmdBuf = VulkanBackend::VulkanFoundation::vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
vkCmdBeginRenderPass(cmdBuf, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
VkViewport viewport{};
viewport.width = (float)dim;
viewport.height = (float)dim;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.extent.width = dim;
scissor.extent.height = dim;
vkCmdSetViewport(cmdBuf, 0, 1, &viewport);
vkCmdSetScissor(cmdBuf, 0, 1, &scissor);
vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
vkCmdDraw(cmdBuf, 3, 1, 0, 0);
vkCmdEndRenderPass(cmdBuf);
VulkanBackend::VulkanFoundation::vulkanDevice->flushCommandBuffer(cmdBuf, VulkanBackend::VulkanFoundation::graphicQueue);
vkQueueWaitIdle(VulkanBackend::VulkanFoundation::graphicQueue);
vkDestroyPipeline(VulkanBackend::VulkanFoundation::device, pipeline, nullptr);
vkDestroyPipelineLayout(VulkanBackend::VulkanFoundation::device, pipelinelayout, nullptr);
vkDestroyRenderPass(VulkanBackend::VulkanFoundation::device, renderpass, nullptr);
vkDestroyFramebuffer(VulkanBackend::VulkanFoundation::device, framebuffer, nullptr);
vkDestroyDescriptorSetLayout(VulkanBackend::VulkanFoundation::device, descriptorsetlayout, nullptr);
textures.lutBrdf.descriptor.imageView = textures.lutBrdf.view;
textures.lutBrdf.descriptor.sampler = textures.lutBrdf.sampler;
textures.lutBrdf.descriptor.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
textures.lutBrdf.device = VulkanBackend::VulkanFoundation::vulkanDevice;
auto tEnd = std::chrono::high_resolution_clock::now();
auto tDiff = std::chrono::duration<double, std::milli>(tEnd - tStart).count();
std::cout << "Generating BRDF LUT took " << tDiff << " ms" << std::endl;
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "glm/glm.hpp"
#include <VulkanTexture.hpp>
#include "vulkanFoundation.h"
namespace PBR
@ -10,7 +10,14 @@ namespace PBR
{
public:
Material();
~Material();
~Material()
{
textures.environmentCube.destroy();
textures.irradianceCube.destroy();
textures.prefilteredCube.destroy();
textures.lutBrdf.destroy();
textures.empty.destroy();
}
struct PushConstBlockMaterial {
glm::vec4 baseColorFactor;
@ -27,21 +34,64 @@ namespace PBR
float roughnessFactor;
float alphaMask;
float alphaMaskCutoff;
} pushConstBlockMaterial;
} ;
static PushConstBlockMaterial pushConstBlockMaterial;
struct Textures {
vks::TextureCubeMap environmentCube;
vks::Texture2D empty;
vks::Texture2D lutBrdf;
vks::TextureCubeMap irradianceCube;
vks::TextureCubeMap prefilteredCube;
} textures;
} ;
static Textures textures;
enum PBRWorkflows { PBR_WORKFLOW_METALLIC_ROUGHNESS = 0, PBR_WORKFLOW_SPECULAR_GLOSINESS = 1 };
struct ShaderData {
glm::vec4 lightDir;
float exposure = 4.5f;
float gamma = 2.2f;
float prefilteredCubeMipLevels;
float scaleIBLAmbient = 1.0f;
float debugViewInputs = 0;
float debugViewEquation = 0;
};
static ShaderData shaderData;
// generate two cube maps
// irradiance cube map
// prefileter environment cube map
void generateCubemap();
// generate BRDF integration map for roughness/NdotV
void generateBRDFLUT();
private:
//cube map generation
struct OffScreen
{
VkImage image;
VkImageView view;
VkDeviceMemory memory;
VkFramebuffer framebuffer;
} offscreen;
struct IrradiancePushBlock
{
glm::mat4 mvp;
// Sampling deltas
float deltaPhi = (2.0f * float(M_PI)) / 180.0f;
float deltaTheta = (0.5f * float(M_PI)) / 64.0f;
} irradiancePushBlock;
struct PrefilterPushBlock {
glm::mat4 mvp;
float roughness;
uint32_t numSamples = 32u;
} prefilterPushBlock;

File diff suppressed because it is too large Load Diff

View File

@ -30,23 +30,19 @@
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#include "vulkanFoundation.h"
#define ENABLE_VALIDATION false
namespace PlumageRender
{
class renderMain : public VulkanExampleBase
class renderMain
{
public:
GLFWwindow* window;
static VulkanBackend::VulkanFoundation vkFoundation;
static PlumageRender::Setter::Settings settings;
static PlumageRender::Setter::FilePath filePath;
static PBR::Material pbrmaterial;
static PlumageRender::RenderInput renderInput;
static PlumageRender::RenderOutput renderOutput;
static Camera camera;
struct Models
@ -65,120 +61,40 @@ namespace PlumageRender
glm::vec3 modelrot = glm::vec3(0.0f);
glm::vec3 modelPos = glm::vec3(0.0f);
uint32_t frameIndex = 0;
//VkImage swapChainImage;
static uint32_t currentBuffer;
struct LightSource {
glm::vec3 color = glm::vec3(1.0f);
glm::vec3 rotation = glm::vec3(75.0f, 40.0f, 0.0f);
} lightSource;
//cube map generation
struct OffScreen
{
VkImage image;
VkImageView view;
VkDeviceMemory memory;
VkFramebuffer framebuffer;
} offscreen;
struct IrradiancePushBlock
{
glm::mat4 mvp;
// Sampling deltas
float deltaPhi = (2.0f * float(M_PI)) / 180.0f;
float deltaTheta = (0.5f * float(M_PI)) / 64.0f;
} irradiancePushBlock;
struct PrefilterPushBlock {
glm::mat4 mvp;
float roughness;
uint32_t numSamples = 32u;
} prefilterPushBlock;
UI* gui;
uint64_t savedFrameCounter = settings.startFrameCount;
uint64_t savedFrameCounter = PlumageRender::Setter::settings.startFrameCount;
bool framebufferResized = false;
renderMain();
~renderMain()
{
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline(device, pipelines.skybox, nullptr);
vkDestroyPipeline(device, pipelines.pbr, nullptr);
vkDestroyPipeline(device, pipelines.pbrAlphaBlend, nullptr);
models.scene.destroy(VulkanBackend::VulkanFoundation::device);
models.skybox.destroy(VulkanBackend::VulkanFoundation::device);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.node, nullptr);
models.scene.destroy(device);
models.skybox.destroy(device);
for (auto buffer : uniformBuffers) {
buffer.params.destroy();
buffer.scene.destroy();
buffer.skybox.destroy();
}
for (auto fence : waitFences) {
vkDestroyFence(device, fence, nullptr);
}
for (auto semaphore : renderCompleteSemaphores) {
vkDestroySemaphore(device, semaphore, nullptr);
}
for (auto semaphore : presentCompleteSemaphores) {
vkDestroySemaphore(device, semaphore, nullptr);
}
textures.environmentCube.destroy();
textures.irradianceCube.destroy();
textures.prefilteredCube.destroy();
textures.lutBrdf.destroy();
textures.empty.destroy();
delete gui;
}
void initWindow(int width, int height);
static void framebufferResizeCallback(GLFWwindow* window, int width, int height);
void renderNode(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode);
void loadScene(std::string filename);
void loadEnvironment(std::string filename);
void buildCommandBuffers();
void loadAssets();
void setupNodeDescriptorSet(glTFModel::Node* node);
void setupDescriptors();
void preparePipelines();
// void tonemappingPipelin();
void generateCubemaps();
void generateBRDFLUT();
void prepareUniformBuffers();
void updateUniformBuffers();
void updateShaderData();
void windowResized();
void prepare();
void setupCamera();
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue);
void writeImageToFile(std::string filePath);
void outputImageSequence();
void imageSequenceToVideo();
void removeImageSequence();
//void outputScreenShot();
//uint32_t getMemoryTypeIndex(uint32_t typeBits, VkMemoryPropertyFlags properties);
virtual void render();
virtual void updateUIOverlay();
virtual void fileDropped(std::string filename);
private:
};
}

View File

@ -1,14 +1,14 @@
#include "renderIO.h"
void PlumageRender::RenderInput::loadScene()
void PlumageRender::RenderInput::loadScene(std::string fileName)
{
std::string filename = PlumageRender::renderMain::filePath.glTFModelFilePath;
std::cout << "Loading scene from " << filename << std::endl;
PlumageRender::renderMain::models.scene.destroy(PlumageRender::renderMain::vkFoundation.device);
std::cout << "Loading scene from " << fileName << std::endl;
PlumageRender::renderMain::models.scene.destroy(VulkanBackend::VulkanFoundation::device);
animationIndex = 0;
animationTimer = 0.0f;
auto tStart = std::chrono::high_resolution_clock::now();
PlumageRender::renderMain::models.scene.loadFromFile(filename, PlumageRender::renderMain::vkFoundation.vulkanDevice, PlumageRender::renderMain::vkFoundation.graphicQueue);
PlumageRender::renderMain::models.scene.loadFromFile(fileName, VulkanBackend::VulkanFoundation::vulkanDevice, VulkanBackend::VulkanFoundation::graphicQueue);
auto tFileLoad = std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - tStart).count();
std::cout << "Loading took " << tFileLoad << " ms" << std::endl;
PlumageRender::renderMain::camera.setPosition({ 0.0f, 0.0f, -1.0f });
@ -17,5 +17,391 @@ void PlumageRender::RenderInput::loadScene()
void PlumageRender::RenderInput::loadEnvironment(std::string fileName)
{
std::cout << "Loading environment from " << fileName << std::endl;
if (PBR::Material::textures.environmentCube.image) {
PBR::Material::textures.environmentCube.destroy();
PBR::Material::textures.irradianceCube.destroy();
PBR::Material::textures.prefilteredCube.destroy();
}
PBR::Material::textures.environmentCube.loadFromFile(fileName, VK_FORMAT_R16G16B16A16_SFLOAT, VulkanBackend::VulkanFoundation::vulkanDevice, VulkanBackend::VulkanFoundation::graphicQueue);
PBR::Material material;
material.generateCubemap();
}
void PlumageRender::RenderInput::loadAssets()
{
const std::string assetpath = getAssetPath();
if (std::filesystem::exists(assetpath.c_str())) {
std::string msg = "asset path get " + assetpath;
std::cout << msg << std::endl;
}
else
{
std::string msg = "Could not locate asset path in \"" + assetpath + "\".\nMake sure binary is running from correct relative directory!";
std::cerr << msg << std::endl;
system("pause");
//exit(-1);
}
readDirectory(assetpath + "environments", "*.ktx", environments, false);
PBR::Material::textures.empty.loadFromFile(PlumageRender::Setter::filePath.emptyEnvmapFilePath, VK_FORMAT_R8G8B8A8_UNORM, VulkanBackend::VulkanFoundation::vulkanDevice, VulkanBackend::VulkanFoundation::graphicQueue);
std::string sceneFile = PlumageRender::Setter::filePath.glTFModelFilePath;
std::string envMapFile = PlumageRender::Setter::filePath.envMapFilePath;
loadScene(sceneFile.c_str());
PlumageRender::renderMain::models.skybox.loadFromFile(PlumageRender::Setter::filePath.skyboxModleFilePath, VulkanBackend::VulkanFoundation::vulkanDevice, VulkanBackend::VulkanFoundation::graphicQueue);
loadEnvironment(envMapFile.c_str());
}
// todo :根据physicalDeviceIndex确定子文件夹路径frameIndex确定fileName
// 移动到fileSystem里
void PlumageRender::RenderOutput::writeImageToFile(std::string filePath)
{
bool screenshotSaved = false;
bool supportsBlit = true;
// Check blit support for source and destination
VkFormatProperties formatProps;
// Check if the device supports blitting from optimal images (the swapchain images are in optimal format)
vkGetPhysicalDeviceFormatProperties(VulkanBackend::VulkanFoundation::physicalDevice, VulkanBackend::VulkanFoundation::swapChainImageFormat, &formatProps);
if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
std::cerr << "Device does not support blitting from optimal tiled images, using copy instead of blit!" << std::endl;
supportsBlit = false;
}
// Check if the device supports blitting to linear images
vkGetPhysicalDeviceFormatProperties(VulkanBackend::VulkanFoundation::physicalDevice, VK_FORMAT_R8G8B8A8_UNORM, &formatProps);
if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) {
std::cerr << "Device does not support blitting to linear tiled images, using copy instead of blit!" << std::endl;
supportsBlit = false;
}
// Source for the copy is the last rendered swapchain image
VkImage srcImage = VulkanBackend::VulkanFoundation::swapChainImages[PlumageRender::renderMain::currentBuffer];
// Create the linear tiled destination image to copy to and to read the memory from
VkImageCreateInfo imageCreateCI(vks::initializers::imageCreateInfo());
imageCreateCI.imageType = VK_IMAGE_TYPE_2D;
// Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ
imageCreateCI.format = VK_FORMAT_R8G8B8A8_UNORM;
imageCreateCI.extent.width = PlumageRender::Setter::settings.width;
imageCreateCI.extent.height = PlumageRender::Setter::settings.height;
imageCreateCI.extent.depth = 1;
imageCreateCI.arrayLayers = 1;
imageCreateCI.mipLevels = 1;
imageCreateCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageCreateCI.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateCI.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
// Create the image
VkImage dstImage;
VK_CHECK_RESULT(vkCreateImage(VulkanBackend::VulkanFoundation::device, &imageCreateCI, nullptr, &dstImage));
// Create memory to back up the image
VkMemoryRequirements memRequirements;
VkMemoryAllocateInfo memAllocInfo(vks::initializers::memoryAllocateInfo());
VkDeviceMemory dstImageMemory;
vkGetImageMemoryRequirements(VulkanBackend::VulkanFoundation::device, dstImage, &memRequirements);
memAllocInfo.allocationSize = memRequirements.size;
// Memory must be host visible to copy from
memAllocInfo.memoryTypeIndex = VulkanBackend::VulkanFoundation::vulkanDevice->getMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
VK_CHECK_RESULT(vkAllocateMemory(VulkanBackend::VulkanFoundation::device, &memAllocInfo, nullptr, &dstImageMemory));
VK_CHECK_RESULT(vkBindImageMemory(VulkanBackend::VulkanFoundation::device, dstImage, dstImageMemory, 0));
// Do the actual blit from the swapchain image to our host visible destination image
VkCommandBuffer copyCmd = VulkanBackend::VulkanFoundation::vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
// Transition destination image to transfer destination layout
vks::tools::insertImageMemoryBarrier(
copyCmd,
dstImage,
0,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
// Transition swapchain image from present to transfer source layout
vks::tools::insertImageMemoryBarrier(
copyCmd,
srcImage,
VK_ACCESS_MEMORY_READ_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
//VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
// If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB)
if (supportsBlit)
{
// Define the region to blit (we will blit the whole swapchain image)
VkOffset3D blitSize;
blitSize.x = PlumageRender::Setter::settings.width;
blitSize.y = PlumageRender::Setter::settings.height;
blitSize.z = 1;
VkImageBlit imageBlitRegion{};
imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.srcSubresource.layerCount = 1;
imageBlitRegion.srcOffsets[1] = blitSize;
imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageBlitRegion.dstSubresource.layerCount = 1;
imageBlitRegion.dstOffsets[1] = blitSize;
// Issue the blit command
vkCmdBlitImage(
copyCmd,
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageBlitRegion,
VK_FILTER_NEAREST);
}
else
{
// Otherwise use image copy (requires us to manually flip components)
VkImageCopy imageCopyRegion{};
imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.srcSubresource.layerCount = 1;
imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageCopyRegion.dstSubresource.layerCount = 1;
imageCopyRegion.extent.width = PlumageRender::Setter::settings.width;
imageCopyRegion.extent.height = PlumageRender::Setter::settings.height;
imageCopyRegion.extent.depth = 1;
// Issue the copy command
vkCmdCopyImage(
copyCmd,
srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1,
&imageCopyRegion);
}
// Transition destination image to general layout, which is the required layout for mapping the image memory later on
vks::tools::insertImageMemoryBarrier(
copyCmd,
dstImage,
VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_MEMORY_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_GENERAL,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
if (!PlumageRender::Setter::settings.headless)
{
// Transition back the swap chain image after the blit is done
vks::tools::insertImageMemoryBarrier(
copyCmd,
srcImage,
VK_ACCESS_TRANSFER_READ_BIT,
VK_ACCESS_MEMORY_READ_BIT,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
}
VulkanBackend::VulkanFoundation::vulkanDevice->flushCommandBuffer(copyCmd, VulkanBackend::VulkanFoundation::graphicQueue);
// Get layout of the image (including row pitch)
VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
VkSubresourceLayout subResourceLayout;
vkGetImageSubresourceLayout(VulkanBackend::VulkanFoundation::device, dstImage, &subResource, &subResourceLayout);
// Map image memory so we can start copying from it
const char* data;
vkMapMemory(VulkanBackend::VulkanFoundation::device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data);
data += subResourceLayout.offset;
// If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components
bool colorSwizzle = false;
// Check if source is BGR
// Note: Not complete, only contains most common and basic BGR surface formats for demonstration purposes
if (!supportsBlit)
{
std::vector<VkFormat> formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM };
colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), VulkanBackend::VulkanFoundation::swapChainImageFormat) != formatsBGR.end());
}
if (PlumageRender::Setter::settings.outputPNGimage)
{
if (colorSwizzle)
{
// 暂时不改此处需要将BGR通道改成RGB格式
stbi_write_png(filePath.c_str(), PlumageRender::Setter::settings.width, PlumageRender::Setter::settings.height, 4, data, static_cast<int>(subResourceLayout.rowPitch));
}
else
{
stbi_write_png(filePath.c_str(), PlumageRender::Setter::settings.width, PlumageRender::Setter::settings.height, 4, data, static_cast<int>(subResourceLayout.rowPitch));
}
}
else
{
std::ofstream file(filePath, std::ios::out | std::ios::binary);
// ppm header
file << "P6\n" << PlumageRender::Setter::settings.width << "\n" << PlumageRender::Setter::settings.height << "\n" << 255 << "\n";
// ppm binary pixel data
for (uint32_t y = 0; y < PlumageRender::Setter::settings.height; y++)
{
unsigned int* row = (unsigned int*)data;
for (uint32_t x = 0; x < PlumageRender::Setter::settings.width; x++)
{
if (colorSwizzle)
{
file.write((char*)row + 2, 1);
file.write((char*)row + 1, 1);
file.write((char*)row, 1);
}
else
{
file.write((char*)row, 3);
}
row++;
}
data += subResourceLayout.rowPitch;
}
file.close();
}
std::cout << "Screenshot saved to " << filePath << std::endl;
// Clean up resources
vkUnmapMemory(VulkanBackend::VulkanFoundation::device, dstImageMemory);
vkFreeMemory(VulkanBackend::VulkanFoundation::device, dstImageMemory, nullptr);
vkDestroyImage(VulkanBackend::VulkanFoundation::device, dstImage, nullptr);
screenshotSaved = true;
}
void PlumageRender::RenderOutput::outputImageSequence()
{
// 比较已保存的帧数和设置里的开始帧数,在生成前清理上一次生成的图片序列
if (savedFrameCounter == PlumageRender::Setter::settings.startFrameCount)
{
std::cout << "clean up directory for image sequence generation" << std::endl;
removeImageSequence();
}
// 根据显卡编号设置输出路径todo提前到配置里
PlumageRender::Setter::filePath.deviceSpecFilePath = PlumageRender::Setter::filePath.imageOutputPath + "/device" + std::to_string(PlumageRender::Setter::settings.selectedPhysicalDeviceIndex);
// 非第一次生成,生成结束的边界条件
if (savedFrameCounter > PlumageRender::Setter::settings.endFrameIndex)
{
// 避免重复改变为true带来的无效性能开销
if (PlumageRender::RenderOutput::signal.imageSequenceOutputComplete)
{
return;
}
// 生成结束的信号标志置为true
PlumageRender::RenderOutput::signal.imageSequenceOutputComplete = true;
// 构造ffmpeg脚本需要的路径变量(提前到配置)
std::string fileName = "/%dresult.ppm";
PlumageRender::Setter::filePath.totalImageOutputPath = PlumageRender::Setter::filePath.deviceSpecFilePath + fileName;
return;
}
// 路径存在性检查,不存在则创建
if (!std::filesystem::exists(PlumageRender::Setter::filePath.deviceSpecFilePath.c_str()))
{
std::filesystem::create_directories(PlumageRender::Setter::filePath.deviceSpecFilePath.c_str());
}
// 拼接图片序列编号到路径里
std::string fileName = "/" + std::to_string(savedFrameCounter) + "result.ppm";
PlumageRender::Setter::filePath.totalImageOutputPath = PlumageRender::Setter::filePath.deviceSpecFilePath + fileName;
//std::cout << outputPath << std::endl;
// 写入文件
writeImageToFile(PlumageRender::Setter::filePath.totalImageOutputPath.c_str());
// 写入一帧后已保存帧数+1
savedFrameCounter++;
}
void PlumageRender::RenderOutput::imageSequenceToVideo()
{
// 边界条件,图片序列输出未完成
if (!PlumageRender::RenderOutput::signal.imageSequenceOutputComplete)
{
return;
}
// 边界条件,图片序列到视频的输出已完成
if (PlumageRender::RenderOutput::signal.imageSequenceToVideoComplete)
{
return;
}
// 拼接视频保存的设备编号路径(提前到配置文件进行)
std::string deviceFilePath = PlumageRender::Setter::filePath.videoOutputPath + "/device" + std::to_string(PlumageRender::Setter::settings.selectedPhysicalDeviceIndex);
// 判断路径是否存在,不存在则创建
if (std::filesystem::exists(deviceFilePath.c_str()))
{
std::filesystem::create_directories(deviceFilePath.c_str());
}
// 构造结果视频路径
std::string resultVideoPath = deviceFilePath + "/result.mp4";
// 构造脚本需要参数,图片序列路径和设定的帧率
std::string commandLineImageSequencePath = PlumageRender::Setter::filePath.totalImageOutputPath;
//std::string commandLineCodecAndResultPath = resultVideoPath;
std::string commandLineFrameRate = std::to_string(PlumageRender::Setter::settings.videoFrameRate);
// 根据不同系统使用不同脚本
#if defined(_WIN32)
std::string commandLine = PlumageRender::Setter::filePath.image2videoBatFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath;
#else
std::string commandLine = filePath.image2videoShFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath;
#endif
std::cout << commandLine << std::endl;
std::system(commandLine.c_str());
// 视频输出完成置标志为true
PlumageRender::RenderOutput::signal.imageSequenceToVideoComplete = true;
std::cout << "vidoe codec complete,saved in:" << resultVideoPath << std::endl;
std::cout << "star to clean up image sequence" << std::endl;
removeImageSequence();
}
void PlumageRender::RenderOutput::removeImageSequence()
{
// 函数非第一次运行的边界条件
if (savedFrameCounter != PlumageRender::Setter::settings.startFrameCount)
{
// 检查视频输出完成的标志位
if (!PlumageRender::RenderOutput::signal.imageSequenceToVideoComplete)
{
return;
}
}
// 遍历删除图片序列文件和空文件夹
if (std::filesystem::exists(PlumageRender::Setter::filePath.deviceSpecFilePath))
{
for (const auto& entry : std::filesystem::directory_iterator(PlumageRender::Setter::filePath.deviceSpecFilePath))
{
if (std::filesystem::is_directory(entry.path()))
{
std::filesystem::remove_all(entry.path());
}
else
{
std::filesystem::remove(entry.path());
}
}
std::filesystem::remove(PlumageRender::Setter::filePath.deviceSpecFilePath);
std::cout << "clean up complete" << std::endl;
}
return;
}

View File

@ -13,26 +13,24 @@ namespace PlumageRender
RenderInput();
~RenderInput();
struct Signal
{
bool imageSequenceOutputComplete = false;
bool imageSequenceToVideoComplete = false;
};
static Signal signal;
std::map<std::string, std::string> environments;
std::string selectedEnvironment = "papermill";
std::map<std::string, std::string> scenes;
std::string selectedScene = "DamagedHelmet";
void loadScene();
void loadScene(std::string fileName);
void loadEnvironment(std::string fileName);
static void loadAssets();
static int32_t animationIndex;
private:
int32_t animationIndex = 0;
float animationTimer = 0.0f;
@ -54,6 +52,23 @@ namespace PlumageRender
RenderOutput();
~RenderOutput();
struct Signal
{
bool imageSequenceOutputComplete = false;
bool imageSequenceToVideoComplete = false;
};
static Signal signal;
static uint64_t savedFrameCounter;
static void writeImageToFile(std::string filePath);
static void outputImageSequence();
static void imageSequenceToVideo();
static void removeImageSequence();
private:
};

View File

@ -41,8 +41,8 @@ namespace PlumageRender
uint32_t selectedPhysicalDeviceIndex = 0;
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
}settings;
};
static Settings settings;
struct FilePath
{
@ -100,8 +100,8 @@ namespace PlumageRender
std::string image2videoBatFilePath = getAssetPath() + "script/image2video.bat";
std::string image2videoShFilePath = getAssetPath() + "script/image2video.sh";
}filePath;
};
static FilePath filePath;
private:

View File

@ -7,7 +7,7 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
ImGuiIO& io = ImGui::GetIO();
ImVec2 lastDisplaySize = io.DisplaySize;
io.DisplaySize = ImVec2((float)PlumageRender::renderMain::settings.width, (float)PlumageRender::renderMain::settings.height);
io.DisplaySize = ImVec2((float)PlumageRender::Setter::settings.width, (float)PlumageRender::Setter::settings.height);
io.DeltaTime = frameTimer;
io.MousePos = ImVec2(mousePos.x, mousePos.y);
@ -57,12 +57,12 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
std::string stringFilename = converter.to_bytes(filename);
loadScene(stringFilename);
PlumageRender::RenderInput::loadScene(stringFilename);
PlumageRender::renderMain::vkFoundation.createDescriptorSets();
updateCBs = true;
PlumageRender::RenderInput::signal.imageSequenceOutputComplete = false;
PlumageRender::RenderInput::signal.imageSequenceToVideoComplete = false;
savedFrameCounter = 1;
PlumageRender::renderMain::renderOutput.signal.imageSequenceOutputComplete = false;
PlumageRender::renderMain::renderOutput.signal.imageSequenceToVideoComplete = false;
PlumageRender::renderMain::renderOutput.savedFrameCounter = 1;
}
}
gui->endMenu();
@ -71,22 +71,24 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
{
if (gui->beginMenu(chineseUI.menuEnvironmentConfig))
{
if (gui->combo(chineseUI.environmentMap, PlumageRender::RenderInput::selectedEnvironment, PlumageRender::RenderInput::environments)) {
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
loadEnvironment(environments[selectedEnvironment]);
setupDescriptors();
auto& selectedEnvironment = PlumageRender::renderMain::renderInput.selectedEnvironment;
auto& environments = PlumageRender::renderMain::renderInput.environments;
if (gui->combo(chineseUI.environmentMap, selectedEnvironment, environments)) {
vkDeviceWaitIdle(PlumageRender::renderMain::vkFoundation.device);
PlumageRender::renderMain::renderInput.loadEnvironment(environments[selectedEnvironment]);
PlumageRender::renderMain::vkFoundation.createDescriptorSets();
updateCBs = true;
}
if (gui->checkbox(chineseUI.environmentBackGround, &PlumageRender::Setter::settings.displayBackground)) {
updateShaderParams = true;
}
if (gui->slider("Exposure", &VulkanBackend::VulkanFoundation::shaderData.exposure, 0.1f, 10.0f)) {
if (gui->slider("Exposure", &PlumageRender::renderMain::vkFoundation.shaderData.exposure, 0.1f, 10.0f)) {
updateShaderParams = true;
}
if (gui->slider("Gamma", &VulkanBackend::VulkanFoundation::shaderData.gamma, 0.1f, 4.0f)) {
if (gui->slider("Gamma", &PlumageRender::renderMain::vkFoundation.shaderData.gamma, 0.1f, 4.0f)) {
updateShaderParams = true;
}
if (gui->slider("IBL", &VulkanBackend::VulkanFoundation::shaderData.scaleIBLAmbient, 0.0f, 1.0f)) {
if (gui->slider("IBL", &PlumageRender::renderMain::vkFoundation.shaderData.scaleIBLAmbient, 0.0f, 1.0f)) {
updateShaderParams = true;
}
gui->endMenu();
@ -101,7 +103,7 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
"none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"
};
if (gui->combo(chineseUI.debugInput, &debugView.debugViewInputs, debugNamesInputs)) {
VulkanBackend::VulkanFoundation::shaderData.debugViewInputs = static_cast<float>(debugView.debugViewInputs);
PlumageRender::renderMain::vkFoundation.shaderData.debugViewInputs = static_cast<float>(debugView.debugViewInputs);
updateShaderParams = true;
}
gui->endMenu();
@ -112,7 +114,7 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
"none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular"
};
if (gui->combo(chineseUI.debugPBREquation, &debugView.debugViewEquation, debugNamesEquation)) {
VulkanBackend::VulkanFoundation::shaderData.debugViewEquation = static_cast<float>(debugView.debugViewEquation);
PlumageRender::renderMain::vkFoundation.shaderData.debugViewEquation = static_cast<float>(debugView.debugViewEquation);
updateShaderParams = true;
}
gui->endMenu();
@ -127,20 +129,20 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
}
if (gui->beginMenu(chineseUI.menuAnimation))
{
if (models.scene.animations.size() > 0)
if (PlumageRender::renderMain::models.scene.animations.size() > 0)
{
if (gui->beginMenu(chineseUI.menuAnimationActivation))
{
gui->checkbox(chineseUI.pauseAnimation, &animate);
gui->checkbox(chineseUI.pauseAnimation, &PlumageRender::Setter::settings.animate);
gui->endMenu();
}
if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence))
{
std::vector<std::string> animationNames;
for (auto animation : models.scene.animations) {
for (auto animation : PlumageRender::renderMain::models.scene.animations) {
animationNames.push_back(animation.name);
}
gui->combo(chineseUI.animationSeq, &animationIndex, animationNames);
gui->combo(chineseUI.animationSeq, &PlumageRender::RenderInput::animationIndex, animationNames);
gui->endMenu();
}
}
@ -169,16 +171,16 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
bool updateBuffers = (gui->vertexBuffer.buffer == VK_NULL_HANDLE) || (gui->vertexBuffer.count != imDrawData->TotalVtxCount) || (gui->indexBuffer.buffer == VK_NULL_HANDLE) || (gui->indexBuffer.count != imDrawData->TotalIdxCount);
if (updateBuffers) {
vkDeviceWaitIdle(device);
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
if (gui->vertexBuffer.buffer) {
gui->vertexBuffer.destroy();
}
gui->vertexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize);
gui->vertexBuffer.create(PlumageRender::renderMain::vkFoundation.vulkanDevice, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertexBufferSize);
gui->vertexBuffer.count = imDrawData->TotalVtxCount;
if (gui->indexBuffer.buffer) {
gui->indexBuffer.destroy();
}
gui->indexBuffer.create(vulkanDevice, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize);
gui->indexBuffer.create(PlumageRender::renderMain::vkFoundation.vulkanDevice, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, indexBufferSize);
gui->indexBuffer.count = imDrawData->TotalIdxCount;
}
@ -204,12 +206,12 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
}
if (updateCBs) {
vkDeviceWaitIdle(device);
buildCommandBuffers();
vkDeviceWaitIdle(device);
vkDeviceWaitIdle(PlumageRender::renderMain::vkFoundation.device);
PlumageRender::renderMain::vkFoundation.createCommandBuffer();
vkDeviceWaitIdle(PlumageRender::renderMain::vkFoundation.device);
}
if (updateShaderParams) {
updateShaderData();
PlumageRender::renderMain::vkFoundation.createCommandBuffer();
}
}

View File

@ -616,14 +616,14 @@ void VulkanBackend::VulkanFoundation::createImageView()
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = colorAttachmentFormat;
imageCI.extent.width = PlumageRender::renderMain::settings.width;
imageCI.extent.height =PlumageRender::renderMain::settings.height;
imageCI.extent.width = PlumageRender::Setter::settings.width;
imageCI.extent.height =PlumageRender::Setter::settings.height;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.samples =PlumageRender::renderMain::settings.sampleCount;
imageCI.samples =PlumageRender::Setter::settings.sampleCount;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
@ -660,14 +660,14 @@ void VulkanBackend::VulkanFoundation::createImageView()
// Depth target
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = depthFormat;
imageCI.extent.width =PlumageRender::renderMain::settings.width;
imageCI.extent.height =PlumageRender::renderMain::settings.height;
imageCI.extent.width =PlumageRender::Setter::settings.width;
imageCI.extent.height =PlumageRender::Setter::settings.height;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCI.samples =PlumageRender::renderMain::settings.sampleCount;
imageCI.samples =PlumageRender::Setter::settings.sampleCount;
imageCI.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &multisampleTarget.depthAttachment.image));
@ -700,8 +700,8 @@ void VulkanBackend::VulkanFoundation::createImageView()
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCI.imageType = VK_IMAGE_TYPE_2D;
imageCI.format = colorAttachmentFormat;
imageCI.extent.width =PlumageRender::renderMain::settings.width;
imageCI.extent.height =PlumageRender::renderMain::settings.height;
imageCI.extent.width =PlumageRender::Setter::settings.width;
imageCI.extent.height =PlumageRender::Setter::settings.height;
imageCI.extent.depth = 1;
imageCI.mipLevels = 1;
imageCI.arrayLayers = 1;
@ -749,8 +749,8 @@ void VulkanBackend::VulkanFoundation::createImageView()
image.pNext = NULL;
image.imageType = VK_IMAGE_TYPE_2D;
image.format = depthFormat;
image.extent.width =PlumageRender::renderMain::settings.width;
image.extent.height =PlumageRender::renderMain::settings.height;
image.extent.width =PlumageRender::Setter::settings.width;
image.extent.height =PlumageRender::Setter::settings.height;
image.extent.depth = 1;
image.mipLevels = 1;
image.arrayLayers = 1;
@ -852,7 +852,7 @@ void VulkanBackend::VulkanFoundation::createRenderPass()
// Multisampled attachment that we render to
attachments[0].format = colorAttachmentFormat;
attachments[0].samples =PlumageRender::renderMain::settings.sampleCount;
attachments[0].samples =PlumageRender::Setter::settings.sampleCount;
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@ -873,7 +873,7 @@ void VulkanBackend::VulkanFoundation::createRenderPass()
// Multisampled depth attachment we render to
attachments[2].format = depthAttachmentFormat;
attachments[2].samples =PlumageRender::renderMain::settings.sampleCount;
attachments[2].samples =PlumageRender::Setter::settings.sampleCount;
attachments[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[2].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
attachments[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
@ -1137,7 +1137,7 @@ void VulkanBackend::VulkanFoundation::createGraphicPipeline()
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
if (PlumageRender::Setter::settings.multiSampling) {
multisampleStateCI.rasterizationSamples =PlumageRender::renderMain::settings.sampleCount;
multisampleStateCI.rasterizationSamples =PlumageRender::Setter::settings.sampleCount;
}
std::vector<VkDynamicState> dynamicStateEnables = {
@ -1158,7 +1158,7 @@ void VulkanBackend::VulkanFoundation::createGraphicPipeline()
pipelineLayoutCI.setLayoutCount = static_cast<uint32_t>(setLayouts.size());
pipelineLayoutCI.pSetLayouts = setLayouts.data();
VkPushConstantRange pushConstantRange{};
pushConstantRange.size = sizeof(PlumageRender::renderMain::pbrmaterial.pushConstBlockMaterial);
pushConstantRange.size = sizeof(PBR::Material::pushConstBlockMaterial);
pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
pipelineLayoutCI.pushConstantRangeCount = 1;
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
@ -1201,7 +1201,7 @@ void VulkanBackend::VulkanFoundation::createGraphicPipeline()
pipelineCI.pStages = shaderStages.data();
if (PlumageRender::Setter::settings.multiSampling) {
multisampleStateCI.rasterizationSamples =PlumageRender::renderMain::settings.sampleCount;
multisampleStateCI.rasterizationSamples =PlumageRender::Setter::settings.sampleCount;
}
// Skybox pipeline (background cube)
@ -1264,8 +1264,8 @@ void VulkanBackend::VulkanFoundation::createFramebuffer()
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = 4;
framebufferCreateInfo.pAttachments = attachments;
framebufferCreateInfo.width =PlumageRender::renderMain::settings.width;
framebufferCreateInfo.height =PlumageRender::renderMain::settings.height;
framebufferCreateInfo.width =PlumageRender::Setter::settings.width;
framebufferCreateInfo.height =PlumageRender::Setter::settings.height;
framebufferCreateInfo.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
@ -1284,8 +1284,8 @@ void VulkanBackend::VulkanFoundation::createFramebuffer()
framebufferCreateInfo.renderPass = renderPass;
framebufferCreateInfo.attachmentCount = 2;
framebufferCreateInfo.pAttachments = attachments;
framebufferCreateInfo.width =PlumageRender::renderMain::settings.width;
framebufferCreateInfo.height =PlumageRender::renderMain::settings.height;
framebufferCreateInfo.width =PlumageRender::Setter::settings.width;
framebufferCreateInfo.height =PlumageRender::Setter::settings.height;
framebufferCreateInfo.layers = 1;
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
@ -1323,8 +1323,8 @@ void VulkanBackend::VulkanFoundation::createSwapChainFramebuffer()
frameBufferCI.renderPass = renderPass;
frameBufferCI.attachmentCount = attachmentCount;
frameBufferCI.pAttachments = attachments;
frameBufferCI.width =PlumageRender::renderMain::settings.width;
frameBufferCI.height =PlumageRender::renderMain::settings.height;
frameBufferCI.width =PlumageRender::Setter::settings.width;
frameBufferCI.height =PlumageRender::Setter::settings.height;
frameBufferCI.layers = 1;
@ -1377,7 +1377,7 @@ void VulkanBackend::VulkanFoundation::createUniformBuffer()
for (auto& uniformBuffer : uniformBuffers) {
uniformBuffer.scene.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataScene));
uniformBuffer.skybox.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderDataSkybox));
uniformBuffer.params.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(shaderData));
uniformBuffer.params.create(vulkanDevice, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, sizeof(PBR::Material::shaderData));
}
updateUniformBuffers();
}
@ -1500,21 +1500,21 @@ void VulkanBackend::VulkanFoundation::createSceneDescriptorSets()
writeDescriptorSets[2].descriptorCount = 1;
writeDescriptorSets[2].dstSet = descriptorSets[i].scene;
writeDescriptorSets[2].dstBinding = 2;
writeDescriptorSets[2].pImageInfo = &PlumageRender::renderMain::pbrmaterial.textures.irradianceCube.descriptor;
writeDescriptorSets[2].pImageInfo = &PBR::Material::textures.irradianceCube.descriptor;
writeDescriptorSets[3].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[3].descriptorCount = 1;
writeDescriptorSets[3].dstSet = descriptorSets[i].scene;
writeDescriptorSets[3].dstBinding = 3;
writeDescriptorSets[3].pImageInfo = &PlumageRender::renderMain::pbrmaterial.textures.prefilteredCube.descriptor;
writeDescriptorSets[3].pImageInfo = &PBR::Material::textures.prefilteredCube.descriptor;
writeDescriptorSets[4].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
writeDescriptorSets[4].descriptorCount = 1;
writeDescriptorSets[4].dstSet = descriptorSets[i].scene;
writeDescriptorSets[4].dstBinding = 4;
writeDescriptorSets[4].pImageInfo = &PlumageRender::renderMain::pbrmaterial.textures.lutBrdf.descriptor;
writeDescriptorSets[4].pImageInfo = &PBR::Material::textures.lutBrdf.descriptor;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
@ -1536,11 +1536,11 @@ void VulkanBackend::VulkanFoundation::createMaterialDescriptorSets()
std::vector<VkDescriptorImageInfo> imageDescriptors =
{
PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
material.normalTexture ? material.normalTexture->descriptor : PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
material.occlusionTexture ? material.occlusionTexture->descriptor : PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
material.emissiveTexture ? material.emissiveTexture->descriptor : PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor
PBR::Material::textures.empty.descriptor,
PBR::Material::textures.empty.descriptor,
material.normalTexture ? material.normalTexture->descriptor : PBR::Material::textures.empty.descriptor,
material.occlusionTexture ? material.occlusionTexture->descriptor : PBR::Material::textures.empty.descriptor,
material.emissiveTexture ? material.emissiveTexture->descriptor : PBR::Material::textures.empty.descriptor
};
if (material.pbrWorkflows.metallicRoughness)
@ -1651,7 +1651,7 @@ void VulkanBackend::VulkanFoundation::createSkyboxDescriptorSets()
writeDescriptorSets[2].descriptorCount = 1;
writeDescriptorSets[2].dstSet = descriptorSets[i].skybox;
writeDescriptorSets[2].dstBinding = 2;
writeDescriptorSets[2].pImageInfo = &PlumageRender::renderMain::pbrmaterial.textures.prefilteredCube.descriptor;
writeDescriptorSets[2].pImageInfo = &PBR::Material::textures.prefilteredCube.descriptor;
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
}
@ -1701,9 +1701,9 @@ void VulkanBackend::VulkanFoundation::createCommandBuffer()
renderPassBeginInfo.renderPass = renderPass;
renderPassBeginInfo.renderArea.offset.x = 0;
renderPassBeginInfo.renderArea.offset.y = 0;
renderPassBeginInfo.renderArea.extent.width =PlumageRender::renderMain::settings.width;
renderPassBeginInfo.renderArea.extent.height =PlumageRender::renderMain::settings.height;
renderPassBeginInfo.clearValueCount =PlumageRender::renderMain::settings.multiSampling ? 3 : 2;
renderPassBeginInfo.renderArea.extent.width =PlumageRender::Setter::settings.width;
renderPassBeginInfo.renderArea.extent.height =PlumageRender::Setter::settings.height;
renderPassBeginInfo.clearValueCount =PlumageRender::Setter::settings.multiSampling ? 3 : 2;
renderPassBeginInfo.pClearValues = clearValues;
for (uint32_t i = 0; i < commandbuffers.size(); ++i)
@ -1723,7 +1723,7 @@ void VulkanBackend::VulkanFoundation::createCommandBuffer()
vkCmdSetViewport(currentCB, 0, 1, &viewport);
VkRect2D scissor{};
scissor.extent = {PlumageRender::renderMain::settings.width,PlumageRender::renderMain::settings.height };
scissor.extent = {PlumageRender::Setter::settings.width,PlumageRender::Setter::settings.height };
vkCmdSetScissor(currentCB, 0, 1, &scissor);
VkDeviceSize offsets[1] = { 0 };
@ -1874,6 +1874,15 @@ void VulkanBackend::VulkanFoundation::createFenceAndSemaphore()
}
}
void VulkanBackend::VulkanFoundation::updateShaderData()
{
PBR::Material::shaderData.lightDir = glm::vec4(
sin(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)),
sin(glm::radians(lightSource.rotation.y)),
cos(glm::radians(lightSource.rotation.x)) * cos(glm::radians(lightSource.rotation.y)),
0.0f);
}

View File

@ -22,7 +22,37 @@ namespace VulkanBackend
{
public:
VulkanFoundation();
~VulkanFoundation();
~VulkanFoundation()
{
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline(device, pipelines.skybox, nullptr);
vkDestroyPipeline(device, pipelines.pbr, nullptr);
vkDestroyPipeline(device, pipelines.pbrAlphaBlend, nullptr);
vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.scene, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.node, nullptr);
models.scene.destroy(device);
models.skybox.destroy(device);
for (auto buffer : uniformBuffers) {
buffer.params.destroy();
buffer.scene.destroy();
buffer.skybox.destroy();
}
for (auto fence : waitFences) {
vkDestroyFence(device, fence, nullptr);
}
for (auto semaphore : renderCompleteSemaphores) {
vkDestroySemaphore(device, semaphore, nullptr);
}
for (auto semaphore : presentCompleteSemaphores) {
vkDestroySemaphore(device, semaphore, nullptr);
}
}
const std::vector<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
@ -36,36 +66,31 @@ namespace VulkanBackend
const int MAX_FRAME_IN_FLIGHT = 2;
const int frameRange =PlumageRender::renderMain::settings.endFrameIndex -PlumageRender::renderMain::settings.startFrameCount;
const int frameRange =PlumageRender::Setter::settings.endFrameIndex - PlumageRender::Setter::settings.startFrameCount;
static VkDevice device;
static vks::VulkanDevice* vulkanDevice;
static VkQueue graphicQueue;
struct ShaderData {
glm::vec4 lightDir;
float exposure = 4.5f;
float gamma = 2.2f;
float prefilteredCubeMipLevels;
float scaleIBLAmbient = 1.0f;
float debugViewInputs = 0;
float debugViewEquation = 0;
};
static ShaderData shaderData;
static VkPipelineCache pipelineCache;
static VkPhysicalDevice physicalDevice;
static std::vector<VkImage> swapChainImages;
static VkFormat swapChainImageFormat;
void initVulkan();
// 创建描述符集合
void createDescriptorSets();
void createCommandBuffer();
private:
VkInstance instance;
VkDebugUtilsMessengerEXT debugMessenger;
@ -92,7 +117,7 @@ namespace VulkanBackend
std::vector<VkPresentModeKHR> presentModes;
};
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
GLFWwindow* window;
@ -104,8 +129,7 @@ namespace VulkanBackend
VkSwapchainKHR swapChain;
std::vector<VkImage> swapChainImages;
VkFormat swapChainImageFormat;
VkExtent2D swapChainExtent;
std::vector<VkImageView> swapChainImageViews;
@ -176,7 +200,7 @@ namespace VulkanBackend
VkPipelineLayout pipelineLayout;
VkPipelineCache pipelineCache;
struct UniformBufferSet {
Buffer scene;
@ -191,7 +215,10 @@ namespace VulkanBackend
glm::vec3 camPos;
} shaderDataScene, shaderDataSkybox;
struct LightSource {
glm::vec3 color = glm::vec3(1.0f);
glm::vec3 rotation = glm::vec3(75.0f, 40.0f, 0.0f);
} lightSource;
std::vector<UniformBufferSet> uniformBuffers;
@ -277,12 +304,14 @@ namespace VulkanBackend
// 创建命令缓存区
void allocateCommandBuffers();
void createCommandBuffer();
void createglTFNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode);
// 创建栅栏和信号量,用于多帧并行的同步
void createFenceAndSemaphore();
void updateShaderData();
};
VulkanFoundation::VulkanFoundation()