重构完成到main
parent
83d35012e6
commit
a74853688c
|
@ -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,
|
||||
©Region);
|
||||
|
||||
{
|
||||
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;
|
||||
}
|
|
@ -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
|
@ -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:
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
};
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue