重构完成到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
|
#pragma once
|
||||||
#include "glm/glm.hpp"
|
#include "glm/glm.hpp"
|
||||||
#include <VulkanTexture.hpp>
|
#include <VulkanTexture.hpp>
|
||||||
|
#include "vulkanFoundation.h"
|
||||||
|
|
||||||
|
|
||||||
namespace PBR
|
namespace PBR
|
||||||
|
@ -10,7 +10,14 @@ namespace PBR
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Material();
|
Material();
|
||||||
~Material();
|
~Material()
|
||||||
|
{
|
||||||
|
textures.environmentCube.destroy();
|
||||||
|
textures.irradianceCube.destroy();
|
||||||
|
textures.prefilteredCube.destroy();
|
||||||
|
textures.lutBrdf.destroy();
|
||||||
|
textures.empty.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
struct PushConstBlockMaterial {
|
struct PushConstBlockMaterial {
|
||||||
glm::vec4 baseColorFactor;
|
glm::vec4 baseColorFactor;
|
||||||
|
@ -27,21 +34,64 @@ namespace PBR
|
||||||
float roughnessFactor;
|
float roughnessFactor;
|
||||||
float alphaMask;
|
float alphaMask;
|
||||||
float alphaMaskCutoff;
|
float alphaMaskCutoff;
|
||||||
} pushConstBlockMaterial;
|
} ;
|
||||||
|
static PushConstBlockMaterial pushConstBlockMaterial;
|
||||||
struct Textures {
|
struct Textures {
|
||||||
vks::TextureCubeMap environmentCube;
|
vks::TextureCubeMap environmentCube;
|
||||||
vks::Texture2D empty;
|
vks::Texture2D empty;
|
||||||
vks::Texture2D lutBrdf;
|
vks::Texture2D lutBrdf;
|
||||||
vks::TextureCubeMap irradianceCube;
|
vks::TextureCubeMap irradianceCube;
|
||||||
vks::TextureCubeMap prefilteredCube;
|
vks::TextureCubeMap prefilteredCube;
|
||||||
} textures;
|
} ;
|
||||||
|
static Textures textures;
|
||||||
|
|
||||||
enum PBRWorkflows { PBR_WORKFLOW_METALLIC_ROUGHNESS = 0, PBR_WORKFLOW_SPECULAR_GLOSINESS = 1 };
|
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:
|
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
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
#include "stb_image_write.h"
|
#include "stb_image_write.h"
|
||||||
|
#include "vulkanFoundation.h"
|
||||||
|
|
||||||
#define ENABLE_VALIDATION false
|
#define ENABLE_VALIDATION false
|
||||||
|
|
||||||
namespace PlumageRender
|
namespace PlumageRender
|
||||||
{
|
{
|
||||||
class renderMain : public VulkanExampleBase
|
class renderMain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GLFWwindow* window;
|
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;
|
static Camera camera;
|
||||||
|
|
||||||
struct Models
|
struct Models
|
||||||
|
@ -65,120 +61,40 @@ namespace PlumageRender
|
||||||
glm::vec3 modelrot = glm::vec3(0.0f);
|
glm::vec3 modelrot = glm::vec3(0.0f);
|
||||||
glm::vec3 modelPos = glm::vec3(0.0f);
|
glm::vec3 modelPos = glm::vec3(0.0f);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t frameIndex = 0;
|
uint32_t frameIndex = 0;
|
||||||
|
|
||||||
//VkImage swapChainImage;
|
//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;
|
UI* gui;
|
||||||
|
|
||||||
uint64_t savedFrameCounter = settings.startFrameCount;
|
uint64_t savedFrameCounter = PlumageRender::Setter::settings.startFrameCount;
|
||||||
|
|
||||||
bool framebufferResized = false;
|
bool framebufferResized = false;
|
||||||
|
|
||||||
renderMain();
|
renderMain();
|
||||||
~renderMain()
|
~renderMain()
|
||||||
{
|
{
|
||||||
// Clean up used Vulkan resources
|
models.scene.destroy(VulkanBackend::VulkanFoundation::device);
|
||||||
// Note : Inherited destructor cleans up resources stored in base class
|
models.skybox.destroy(VulkanBackend::VulkanFoundation::device);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
textures.environmentCube.destroy();
|
|
||||||
textures.irradianceCube.destroy();
|
|
||||||
textures.prefilteredCube.destroy();
|
|
||||||
textures.lutBrdf.destroy();
|
|
||||||
textures.empty.destroy();
|
|
||||||
delete gui;
|
delete gui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void initWindow(int width, int height);
|
void initWindow(int width, int height);
|
||||||
|
|
||||||
static void framebufferResizeCallback(GLFWwindow* window, 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 windowResized();
|
||||||
void prepare();
|
void prepare();
|
||||||
void setupCamera();
|
void setupCamera();
|
||||||
void submitWork(VkCommandBuffer cmdBuffer, VkQueue queue);
|
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 render();
|
||||||
virtual void updateUIOverlay();
|
|
||||||
virtual void fileDropped(std::string filename);
|
virtual void fileDropped(std::string filename);
|
||||||
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#include "renderIO.h"
|
#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;
|
std::cout << "Loading scene from " << fileName << std::endl;
|
||||||
PlumageRender::renderMain::models.scene.destroy(PlumageRender::renderMain::vkFoundation.device);
|
PlumageRender::renderMain::models.scene.destroy(VulkanBackend::VulkanFoundation::device);
|
||||||
animationIndex = 0;
|
animationIndex = 0;
|
||||||
animationTimer = 0.0f;
|
animationTimer = 0.0f;
|
||||||
auto tStart = std::chrono::high_resolution_clock::now();
|
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();
|
auto tFileLoad = std::chrono::duration<double, std::milli>(std::chrono::high_resolution_clock::now() - tStart).count();
|
||||||
std::cout << "Loading took " << tFileLoad << " ms" << std::endl;
|
std::cout << "Loading took " << tFileLoad << " ms" << std::endl;
|
||||||
PlumageRender::renderMain::camera.setPosition({ 0.0f, 0.0f, -1.0f });
|
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)
|
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();
|
||||||
~RenderInput();
|
~RenderInput();
|
||||||
|
|
||||||
struct Signal
|
|
||||||
{
|
|
||||||
bool imageSequenceOutputComplete = false;
|
|
||||||
bool imageSequenceToVideoComplete = false;
|
|
||||||
};
|
|
||||||
static Signal signal;
|
|
||||||
|
|
||||||
std::map<std::string, std::string> environments;
|
std::map<std::string, std::string> environments;
|
||||||
std::string selectedEnvironment = "papermill";
|
std::string selectedEnvironment = "papermill";
|
||||||
std::map<std::string, std::string> scenes;
|
std::map<std::string, std::string> scenes;
|
||||||
std::string selectedScene = "DamagedHelmet";
|
std::string selectedScene = "DamagedHelmet";
|
||||||
|
|
||||||
void loadScene();
|
void loadScene(std::string fileName);
|
||||||
|
|
||||||
void loadEnvironment(std::string fileName);
|
void loadEnvironment(std::string fileName);
|
||||||
|
|
||||||
|
static void loadAssets();
|
||||||
|
|
||||||
|
static int32_t animationIndex;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int32_t animationIndex = 0;
|
|
||||||
float animationTimer = 0.0f;
|
float animationTimer = 0.0f;
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +52,23 @@ namespace PlumageRender
|
||||||
RenderOutput();
|
RenderOutput();
|
||||||
~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:
|
private:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,8 +41,8 @@ namespace PlumageRender
|
||||||
uint32_t selectedPhysicalDeviceIndex = 0;
|
uint32_t selectedPhysicalDeviceIndex = 0;
|
||||||
|
|
||||||
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
|
VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_4_BIT; // 多重采样倍率
|
||||||
}settings;
|
};
|
||||||
|
static Settings settings;
|
||||||
|
|
||||||
struct FilePath
|
struct FilePath
|
||||||
{
|
{
|
||||||
|
@ -100,8 +100,8 @@ namespace PlumageRender
|
||||||
std::string image2videoBatFilePath = getAssetPath() + "script/image2video.bat";
|
std::string image2videoBatFilePath = getAssetPath() + "script/image2video.bat";
|
||||||
std::string image2videoShFilePath = getAssetPath() + "script/image2video.sh";
|
std::string image2videoShFilePath = getAssetPath() + "script/image2video.sh";
|
||||||
|
|
||||||
}filePath;
|
};
|
||||||
|
static FilePath filePath;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
ImVec2 lastDisplaySize = io.DisplaySize;
|
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.DeltaTime = frameTimer;
|
||||||
|
|
||||||
io.MousePos = ImVec2(mousePos.x, mousePos.y);
|
io.MousePos = ImVec2(mousePos.x, mousePos.y);
|
||||||
|
@ -57,12 +57,12 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
|
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
|
||||||
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
|
||||||
std::string stringFilename = converter.to_bytes(filename);
|
std::string stringFilename = converter.to_bytes(filename);
|
||||||
loadScene(stringFilename);
|
PlumageRender::RenderInput::loadScene(stringFilename);
|
||||||
PlumageRender::renderMain::vkFoundation.createDescriptorSets();
|
PlumageRender::renderMain::vkFoundation.createDescriptorSets();
|
||||||
updateCBs = true;
|
updateCBs = true;
|
||||||
PlumageRender::RenderInput::signal.imageSequenceOutputComplete = false;
|
PlumageRender::renderMain::renderOutput.signal.imageSequenceOutputComplete = false;
|
||||||
PlumageRender::RenderInput::signal.imageSequenceToVideoComplete = false;
|
PlumageRender::renderMain::renderOutput.signal.imageSequenceToVideoComplete = false;
|
||||||
savedFrameCounter = 1;
|
PlumageRender::renderMain::renderOutput.savedFrameCounter = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gui->endMenu();
|
gui->endMenu();
|
||||||
|
@ -71,22 +71,24 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
{
|
{
|
||||||
if (gui->beginMenu(chineseUI.menuEnvironmentConfig))
|
if (gui->beginMenu(chineseUI.menuEnvironmentConfig))
|
||||||
{
|
{
|
||||||
if (gui->combo(chineseUI.environmentMap, PlumageRender::RenderInput::selectedEnvironment, PlumageRender::RenderInput::environments)) {
|
auto& selectedEnvironment = PlumageRender::renderMain::renderInput.selectedEnvironment;
|
||||||
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
|
auto& environments = PlumageRender::renderMain::renderInput.environments;
|
||||||
loadEnvironment(environments[selectedEnvironment]);
|
if (gui->combo(chineseUI.environmentMap, selectedEnvironment, environments)) {
|
||||||
setupDescriptors();
|
vkDeviceWaitIdle(PlumageRender::renderMain::vkFoundation.device);
|
||||||
|
PlumageRender::renderMain::renderInput.loadEnvironment(environments[selectedEnvironment]);
|
||||||
|
PlumageRender::renderMain::vkFoundation.createDescriptorSets();
|
||||||
updateCBs = true;
|
updateCBs = true;
|
||||||
}
|
}
|
||||||
if (gui->checkbox(chineseUI.environmentBackGround, &PlumageRender::Setter::settings.displayBackground)) {
|
if (gui->checkbox(chineseUI.environmentBackGround, &PlumageRender::Setter::settings.displayBackground)) {
|
||||||
updateShaderParams = true;
|
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;
|
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;
|
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;
|
updateShaderParams = true;
|
||||||
}
|
}
|
||||||
gui->endMenu();
|
gui->endMenu();
|
||||||
|
@ -101,7 +103,7 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
"none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"
|
"none", "Base color", "Normal", "Occlusion", "Emissive", "Metallic", "Roughness"
|
||||||
};
|
};
|
||||||
if (gui->combo(chineseUI.debugInput, &debugView.debugViewInputs, debugNamesInputs)) {
|
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;
|
updateShaderParams = true;
|
||||||
}
|
}
|
||||||
gui->endMenu();
|
gui->endMenu();
|
||||||
|
@ -112,7 +114,7 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
"none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular"
|
"none", "Diff (l,n)", "F (l,h)", "G (l,v,h)", "D (h)", "Specular"
|
||||||
};
|
};
|
||||||
if (gui->combo(chineseUI.debugPBREquation, &debugView.debugViewEquation, debugNamesEquation)) {
|
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;
|
updateShaderParams = true;
|
||||||
}
|
}
|
||||||
gui->endMenu();
|
gui->endMenu();
|
||||||
|
@ -127,20 +129,20 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
}
|
}
|
||||||
if (gui->beginMenu(chineseUI.menuAnimation))
|
if (gui->beginMenu(chineseUI.menuAnimation))
|
||||||
{
|
{
|
||||||
if (models.scene.animations.size() > 0)
|
if (PlumageRender::renderMain::models.scene.animations.size() > 0)
|
||||||
{
|
{
|
||||||
if (gui->beginMenu(chineseUI.menuAnimationActivation))
|
if (gui->beginMenu(chineseUI.menuAnimationActivation))
|
||||||
{
|
{
|
||||||
gui->checkbox(chineseUI.pauseAnimation, &animate);
|
gui->checkbox(chineseUI.pauseAnimation, &PlumageRender::Setter::settings.animate);
|
||||||
gui->endMenu();
|
gui->endMenu();
|
||||||
}
|
}
|
||||||
if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence))
|
if (gui->beginMenu(chineseUI.menuAnimationAnimationSequence))
|
||||||
{
|
{
|
||||||
std::vector<std::string> animationNames;
|
std::vector<std::string> animationNames;
|
||||||
for (auto animation : models.scene.animations) {
|
for (auto animation : PlumageRender::renderMain::models.scene.animations) {
|
||||||
animationNames.push_back(animation.name);
|
animationNames.push_back(animation.name);
|
||||||
}
|
}
|
||||||
gui->combo(chineseUI.animationSeq, &animationIndex, animationNames);
|
gui->combo(chineseUI.animationSeq, &PlumageRender::RenderInput::animationIndex, animationNames);
|
||||||
gui->endMenu();
|
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);
|
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) {
|
if (updateBuffers) {
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(VulkanBackend::VulkanFoundation::device);
|
||||||
if (gui->vertexBuffer.buffer) {
|
if (gui->vertexBuffer.buffer) {
|
||||||
gui->vertexBuffer.destroy();
|
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;
|
gui->vertexBuffer.count = imDrawData->TotalVtxCount;
|
||||||
if (gui->indexBuffer.buffer) {
|
if (gui->indexBuffer.buffer) {
|
||||||
gui->indexBuffer.destroy();
|
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;
|
gui->indexBuffer.count = imDrawData->TotalIdxCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,12 +206,12 @@ void PlumageRender::PlumageGUI::updateUIOverlay()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateCBs) {
|
if (updateCBs) {
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(PlumageRender::renderMain::vkFoundation.device);
|
||||||
buildCommandBuffers();
|
PlumageRender::renderMain::vkFoundation.createCommandBuffer();
|
||||||
vkDeviceWaitIdle(device);
|
vkDeviceWaitIdle(PlumageRender::renderMain::vkFoundation.device);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (updateShaderParams) {
|
if (updateShaderParams) {
|
||||||
updateShaderData();
|
PlumageRender::renderMain::vkFoundation.createCommandBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -616,14 +616,14 @@ void VulkanBackend::VulkanFoundation::createImageView()
|
||||||
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
imageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
||||||
imageCI.format = colorAttachmentFormat;
|
imageCI.format = colorAttachmentFormat;
|
||||||
imageCI.extent.width = PlumageRender::renderMain::settings.width;
|
imageCI.extent.width = PlumageRender::Setter::settings.width;
|
||||||
imageCI.extent.height =PlumageRender::renderMain::settings.height;
|
imageCI.extent.height =PlumageRender::Setter::settings.height;
|
||||||
imageCI.extent.depth = 1;
|
imageCI.extent.depth = 1;
|
||||||
imageCI.mipLevels = 1;
|
imageCI.mipLevels = 1;
|
||||||
imageCI.arrayLayers = 1;
|
imageCI.arrayLayers = 1;
|
||||||
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
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.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
|
@ -660,14 +660,14 @@ void VulkanBackend::VulkanFoundation::createImageView()
|
||||||
// Depth target
|
// Depth target
|
||||||
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
||||||
imageCI.format = depthFormat;
|
imageCI.format = depthFormat;
|
||||||
imageCI.extent.width =PlumageRender::renderMain::settings.width;
|
imageCI.extent.width =PlumageRender::Setter::settings.width;
|
||||||
imageCI.extent.height =PlumageRender::renderMain::settings.height;
|
imageCI.extent.height =PlumageRender::Setter::settings.height;
|
||||||
imageCI.extent.depth = 1;
|
imageCI.extent.depth = 1;
|
||||||
imageCI.mipLevels = 1;
|
imageCI.mipLevels = 1;
|
||||||
imageCI.arrayLayers = 1;
|
imageCI.arrayLayers = 1;
|
||||||
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
imageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
imageCI.tiling = VK_IMAGE_TILING_OPTIMAL;
|
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.usage = VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||||
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
imageCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
VK_CHECK_RESULT(vkCreateImage(device, &imageCI, nullptr, &multisampleTarget.depthAttachment.image));
|
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.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
imageCI.imageType = VK_IMAGE_TYPE_2D;
|
||||||
imageCI.format = colorAttachmentFormat;
|
imageCI.format = colorAttachmentFormat;
|
||||||
imageCI.extent.width =PlumageRender::renderMain::settings.width;
|
imageCI.extent.width =PlumageRender::Setter::settings.width;
|
||||||
imageCI.extent.height =PlumageRender::renderMain::settings.height;
|
imageCI.extent.height =PlumageRender::Setter::settings.height;
|
||||||
imageCI.extent.depth = 1;
|
imageCI.extent.depth = 1;
|
||||||
imageCI.mipLevels = 1;
|
imageCI.mipLevels = 1;
|
||||||
imageCI.arrayLayers = 1;
|
imageCI.arrayLayers = 1;
|
||||||
|
@ -749,8 +749,8 @@ void VulkanBackend::VulkanFoundation::createImageView()
|
||||||
image.pNext = NULL;
|
image.pNext = NULL;
|
||||||
image.imageType = VK_IMAGE_TYPE_2D;
|
image.imageType = VK_IMAGE_TYPE_2D;
|
||||||
image.format = depthFormat;
|
image.format = depthFormat;
|
||||||
image.extent.width =PlumageRender::renderMain::settings.width;
|
image.extent.width =PlumageRender::Setter::settings.width;
|
||||||
image.extent.height =PlumageRender::renderMain::settings.height;
|
image.extent.height =PlumageRender::Setter::settings.height;
|
||||||
image.extent.depth = 1;
|
image.extent.depth = 1;
|
||||||
image.mipLevels = 1;
|
image.mipLevels = 1;
|
||||||
image.arrayLayers = 1;
|
image.arrayLayers = 1;
|
||||||
|
@ -852,7 +852,7 @@ void VulkanBackend::VulkanFoundation::createRenderPass()
|
||||||
|
|
||||||
// Multisampled attachment that we render to
|
// Multisampled attachment that we render to
|
||||||
attachments[0].format = colorAttachmentFormat;
|
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].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||||
|
@ -873,7 +873,7 @@ void VulkanBackend::VulkanFoundation::createRenderPass()
|
||||||
|
|
||||||
// Multisampled depth attachment we render to
|
// Multisampled depth attachment we render to
|
||||||
attachments[2].format = depthAttachmentFormat;
|
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].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||||
attachments[2].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
attachments[2].storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||||
attachments[2].stencilLoadOp = VK_ATTACHMENT_LOAD_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;
|
multisampleStateCI.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||||
|
|
||||||
if (PlumageRender::Setter::settings.multiSampling) {
|
if (PlumageRender::Setter::settings.multiSampling) {
|
||||||
multisampleStateCI.rasterizationSamples =PlumageRender::renderMain::settings.sampleCount;
|
multisampleStateCI.rasterizationSamples =PlumageRender::Setter::settings.sampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VkDynamicState> dynamicStateEnables = {
|
std::vector<VkDynamicState> dynamicStateEnables = {
|
||||||
|
@ -1158,7 +1158,7 @@ void VulkanBackend::VulkanFoundation::createGraphicPipeline()
|
||||||
pipelineLayoutCI.setLayoutCount = static_cast<uint32_t>(setLayouts.size());
|
pipelineLayoutCI.setLayoutCount = static_cast<uint32_t>(setLayouts.size());
|
||||||
pipelineLayoutCI.pSetLayouts = setLayouts.data();
|
pipelineLayoutCI.pSetLayouts = setLayouts.data();
|
||||||
VkPushConstantRange pushConstantRange{};
|
VkPushConstantRange pushConstantRange{};
|
||||||
pushConstantRange.size = sizeof(PlumageRender::renderMain::pbrmaterial.pushConstBlockMaterial);
|
pushConstantRange.size = sizeof(PBR::Material::pushConstBlockMaterial);
|
||||||
pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
pushConstantRange.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||||
pipelineLayoutCI.pushConstantRangeCount = 1;
|
pipelineLayoutCI.pushConstantRangeCount = 1;
|
||||||
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
|
pipelineLayoutCI.pPushConstantRanges = &pushConstantRange;
|
||||||
|
@ -1201,7 +1201,7 @@ void VulkanBackend::VulkanFoundation::createGraphicPipeline()
|
||||||
pipelineCI.pStages = shaderStages.data();
|
pipelineCI.pStages = shaderStages.data();
|
||||||
|
|
||||||
if (PlumageRender::Setter::settings.multiSampling) {
|
if (PlumageRender::Setter::settings.multiSampling) {
|
||||||
multisampleStateCI.rasterizationSamples =PlumageRender::renderMain::settings.sampleCount;
|
multisampleStateCI.rasterizationSamples =PlumageRender::Setter::settings.sampleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skybox pipeline (background cube)
|
// Skybox pipeline (background cube)
|
||||||
|
@ -1264,8 +1264,8 @@ void VulkanBackend::VulkanFoundation::createFramebuffer()
|
||||||
framebufferCreateInfo.renderPass = renderPass;
|
framebufferCreateInfo.renderPass = renderPass;
|
||||||
framebufferCreateInfo.attachmentCount = 4;
|
framebufferCreateInfo.attachmentCount = 4;
|
||||||
framebufferCreateInfo.pAttachments = attachments;
|
framebufferCreateInfo.pAttachments = attachments;
|
||||||
framebufferCreateInfo.width =PlumageRender::renderMain::settings.width;
|
framebufferCreateInfo.width =PlumageRender::Setter::settings.width;
|
||||||
framebufferCreateInfo.height =PlumageRender::renderMain::settings.height;
|
framebufferCreateInfo.height =PlumageRender::Setter::settings.height;
|
||||||
framebufferCreateInfo.layers = 1;
|
framebufferCreateInfo.layers = 1;
|
||||||
|
|
||||||
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
|
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
|
||||||
|
@ -1284,8 +1284,8 @@ void VulkanBackend::VulkanFoundation::createFramebuffer()
|
||||||
framebufferCreateInfo.renderPass = renderPass;
|
framebufferCreateInfo.renderPass = renderPass;
|
||||||
framebufferCreateInfo.attachmentCount = 2;
|
framebufferCreateInfo.attachmentCount = 2;
|
||||||
framebufferCreateInfo.pAttachments = attachments;
|
framebufferCreateInfo.pAttachments = attachments;
|
||||||
framebufferCreateInfo.width =PlumageRender::renderMain::settings.width;
|
framebufferCreateInfo.width =PlumageRender::Setter::settings.width;
|
||||||
framebufferCreateInfo.height =PlumageRender::renderMain::settings.height;
|
framebufferCreateInfo.height =PlumageRender::Setter::settings.height;
|
||||||
framebufferCreateInfo.layers = 1;
|
framebufferCreateInfo.layers = 1;
|
||||||
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
|
VK_CHECK_RESULT(vkCreateFramebuffer(device, &framebufferCreateInfo, nullptr, &framebuffers[i]));
|
||||||
|
|
||||||
|
@ -1323,8 +1323,8 @@ void VulkanBackend::VulkanFoundation::createSwapChainFramebuffer()
|
||||||
frameBufferCI.renderPass = renderPass;
|
frameBufferCI.renderPass = renderPass;
|
||||||
frameBufferCI.attachmentCount = attachmentCount;
|
frameBufferCI.attachmentCount = attachmentCount;
|
||||||
frameBufferCI.pAttachments = attachments;
|
frameBufferCI.pAttachments = attachments;
|
||||||
frameBufferCI.width =PlumageRender::renderMain::settings.width;
|
frameBufferCI.width =PlumageRender::Setter::settings.width;
|
||||||
frameBufferCI.height =PlumageRender::renderMain::settings.height;
|
frameBufferCI.height =PlumageRender::Setter::settings.height;
|
||||||
frameBufferCI.layers = 1;
|
frameBufferCI.layers = 1;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1377,7 +1377,7 @@ void VulkanBackend::VulkanFoundation::createUniformBuffer()
|
||||||
for (auto& uniformBuffer : uniformBuffers) {
|
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.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.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();
|
updateUniformBuffers();
|
||||||
}
|
}
|
||||||
|
@ -1500,21 +1500,21 @@ void VulkanBackend::VulkanFoundation::createSceneDescriptorSets()
|
||||||
writeDescriptorSets[2].descriptorCount = 1;
|
writeDescriptorSets[2].descriptorCount = 1;
|
||||||
writeDescriptorSets[2].dstSet = descriptorSets[i].scene;
|
writeDescriptorSets[2].dstSet = descriptorSets[i].scene;
|
||||||
writeDescriptorSets[2].dstBinding = 2;
|
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].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
writeDescriptorSets[3].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
writeDescriptorSets[3].descriptorCount = 1;
|
writeDescriptorSets[3].descriptorCount = 1;
|
||||||
writeDescriptorSets[3].dstSet = descriptorSets[i].scene;
|
writeDescriptorSets[3].dstSet = descriptorSets[i].scene;
|
||||||
writeDescriptorSets[3].dstBinding = 3;
|
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].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||||
writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
writeDescriptorSets[4].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||||
writeDescriptorSets[4].descriptorCount = 1;
|
writeDescriptorSets[4].descriptorCount = 1;
|
||||||
writeDescriptorSets[4].dstSet = descriptorSets[i].scene;
|
writeDescriptorSets[4].dstSet = descriptorSets[i].scene;
|
||||||
writeDescriptorSets[4].dstBinding = 4;
|
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);
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
|
||||||
|
|
||||||
|
@ -1536,11 +1536,11 @@ void VulkanBackend::VulkanFoundation::createMaterialDescriptorSets()
|
||||||
|
|
||||||
std::vector<VkDescriptorImageInfo> imageDescriptors =
|
std::vector<VkDescriptorImageInfo> imageDescriptors =
|
||||||
{
|
{
|
||||||
PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
|
PBR::Material::textures.empty.descriptor,
|
||||||
PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
|
PBR::Material::textures.empty.descriptor,
|
||||||
material.normalTexture ? material.normalTexture->descriptor : PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
|
material.normalTexture ? material.normalTexture->descriptor : PBR::Material::textures.empty.descriptor,
|
||||||
material.occlusionTexture ? material.occlusionTexture->descriptor : PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor,
|
material.occlusionTexture ? material.occlusionTexture->descriptor : PBR::Material::textures.empty.descriptor,
|
||||||
material.emissiveTexture ? material.emissiveTexture->descriptor : PlumageRender::renderMain::pbrmaterial.textures.empty.descriptor
|
material.emissiveTexture ? material.emissiveTexture->descriptor : PBR::Material::textures.empty.descriptor
|
||||||
};
|
};
|
||||||
|
|
||||||
if (material.pbrWorkflows.metallicRoughness)
|
if (material.pbrWorkflows.metallicRoughness)
|
||||||
|
@ -1651,7 +1651,7 @@ void VulkanBackend::VulkanFoundation::createSkyboxDescriptorSets()
|
||||||
writeDescriptorSets[2].descriptorCount = 1;
|
writeDescriptorSets[2].descriptorCount = 1;
|
||||||
writeDescriptorSets[2].dstSet = descriptorSets[i].skybox;
|
writeDescriptorSets[2].dstSet = descriptorSets[i].skybox;
|
||||||
writeDescriptorSets[2].dstBinding = 2;
|
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);
|
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, nullptr);
|
||||||
}
|
}
|
||||||
|
@ -1701,9 +1701,9 @@ void VulkanBackend::VulkanFoundation::createCommandBuffer()
|
||||||
renderPassBeginInfo.renderPass = renderPass;
|
renderPassBeginInfo.renderPass = renderPass;
|
||||||
renderPassBeginInfo.renderArea.offset.x = 0;
|
renderPassBeginInfo.renderArea.offset.x = 0;
|
||||||
renderPassBeginInfo.renderArea.offset.y = 0;
|
renderPassBeginInfo.renderArea.offset.y = 0;
|
||||||
renderPassBeginInfo.renderArea.extent.width =PlumageRender::renderMain::settings.width;
|
renderPassBeginInfo.renderArea.extent.width =PlumageRender::Setter::settings.width;
|
||||||
renderPassBeginInfo.renderArea.extent.height =PlumageRender::renderMain::settings.height;
|
renderPassBeginInfo.renderArea.extent.height =PlumageRender::Setter::settings.height;
|
||||||
renderPassBeginInfo.clearValueCount =PlumageRender::renderMain::settings.multiSampling ? 3 : 2;
|
renderPassBeginInfo.clearValueCount =PlumageRender::Setter::settings.multiSampling ? 3 : 2;
|
||||||
renderPassBeginInfo.pClearValues = clearValues;
|
renderPassBeginInfo.pClearValues = clearValues;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < commandbuffers.size(); ++i)
|
for (uint32_t i = 0; i < commandbuffers.size(); ++i)
|
||||||
|
@ -1723,7 +1723,7 @@ void VulkanBackend::VulkanFoundation::createCommandBuffer()
|
||||||
vkCmdSetViewport(currentCB, 0, 1, &viewport);
|
vkCmdSetViewport(currentCB, 0, 1, &viewport);
|
||||||
|
|
||||||
VkRect2D scissor{};
|
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);
|
vkCmdSetScissor(currentCB, 0, 1, &scissor);
|
||||||
|
|
||||||
VkDeviceSize offsets[1] = { 0 };
|
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:
|
public:
|
||||||
VulkanFoundation();
|
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 = {
|
const std::vector<const char*> validationLayers = {
|
||||||
"VK_LAYER_KHRONOS_validation"
|
"VK_LAYER_KHRONOS_validation"
|
||||||
|
@ -36,36 +66,31 @@ namespace VulkanBackend
|
||||||
|
|
||||||
const int MAX_FRAME_IN_FLIGHT = 2;
|
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 VkDevice device;
|
||||||
static vks::VulkanDevice* vulkanDevice;
|
static vks::VulkanDevice* vulkanDevice;
|
||||||
|
|
||||||
static VkQueue graphicQueue;
|
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 initVulkan();
|
||||||
|
|
||||||
// 创建描述符集合
|
// 创建描述符集合
|
||||||
void createDescriptorSets();
|
void createDescriptorSets();
|
||||||
|
|
||||||
|
void createCommandBuffer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
VkInstance instance;
|
VkInstance instance;
|
||||||
|
|
||||||
VkDebugUtilsMessengerEXT debugMessenger;
|
VkDebugUtilsMessengerEXT debugMessenger;
|
||||||
|
@ -92,7 +117,7 @@ namespace VulkanBackend
|
||||||
std::vector<VkPresentModeKHR> presentModes;
|
std::vector<VkPresentModeKHR> presentModes;
|
||||||
};
|
};
|
||||||
|
|
||||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
|
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
|
@ -104,8 +129,7 @@ namespace VulkanBackend
|
||||||
|
|
||||||
|
|
||||||
VkSwapchainKHR swapChain;
|
VkSwapchainKHR swapChain;
|
||||||
std::vector<VkImage> swapChainImages;
|
|
||||||
VkFormat swapChainImageFormat;
|
|
||||||
VkExtent2D swapChainExtent;
|
VkExtent2D swapChainExtent;
|
||||||
std::vector<VkImageView> swapChainImageViews;
|
std::vector<VkImageView> swapChainImageViews;
|
||||||
|
|
||||||
|
@ -176,7 +200,7 @@ namespace VulkanBackend
|
||||||
|
|
||||||
VkPipelineLayout pipelineLayout;
|
VkPipelineLayout pipelineLayout;
|
||||||
|
|
||||||
VkPipelineCache pipelineCache;
|
|
||||||
|
|
||||||
struct UniformBufferSet {
|
struct UniformBufferSet {
|
||||||
Buffer scene;
|
Buffer scene;
|
||||||
|
@ -191,7 +215,10 @@ namespace VulkanBackend
|
||||||
glm::vec3 camPos;
|
glm::vec3 camPos;
|
||||||
} shaderDataScene, shaderDataSkybox;
|
} 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;
|
std::vector<UniformBufferSet> uniformBuffers;
|
||||||
|
|
||||||
|
@ -277,12 +304,14 @@ namespace VulkanBackend
|
||||||
|
|
||||||
// 创建命令缓存区
|
// 创建命令缓存区
|
||||||
void allocateCommandBuffers();
|
void allocateCommandBuffers();
|
||||||
void createCommandBuffer();
|
|
||||||
void createglTFNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode);
|
void createglTFNodeCommandBuffer(glTFModel::Node* node, uint32_t cbIndex, glTFModel::Material::AlphaMode alphaMode);
|
||||||
|
|
||||||
// 创建栅栏和信号量,用于多帧并行的同步
|
// 创建栅栏和信号量,用于多帧并行的同步
|
||||||
void createFenceAndSemaphore();
|
void createFenceAndSemaphore();
|
||||||
|
|
||||||
|
void updateShaderData();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
VulkanFoundation::VulkanFoundation()
|
VulkanFoundation::VulkanFoundation()
|
||||||
|
|
Loading…
Reference in New Issue