2023-06-12 11:05:10 +08:00
2023-06-07 00:45:10 +08:00
2023-05-26 14:12:02 +08:00
2023-05-26 16:19:12 +08:00
# ifndef TINYGLTF_IMPLEMENTATION
# define TINYGLTF_IMPLEMENTATION
# endif
# ifndef STB_IMAGE_IMPLEMENTATION
# define STB_IMAGE_IMPLEMENTATION
# endif
2023-05-26 14:12:02 +08:00
2023-05-26 16:19:12 +08:00
# ifndef TINYGLTF_NO_STB_IMAGE_WRITE
# define TINYGLTF_NO_STB_IMAGE_WRITE
# endif
2023-05-26 14:12:02 +08:00
2023-05-26 16:19:12 +08:00
# include "render.h"
2023-06-07 10:52:04 +08:00
//#include "VulkanUtils.hpp"
2023-06-07 00:45:10 +08:00
//#include "assetLoader.h"
2023-05-17 14:53:31 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : initWindow ( int Width , int Height )
2024-04-01 13:45:00 +08:00
{
glfwInit ( ) ;
glfwWindowHint ( GLFW_CLIENT_API , GLFW_NO_API ) ;
2024-04-07 17:29:35 +08:00
2024-04-01 13:45:00 +08:00
window = glfwCreateWindow ( Width , Height , " vulkan " , nullptr , nullptr ) ;
glfwSetWindowUserPointer ( window , this ) ;
glfwSetFramebufferSizeCallback ( window , framebufferResizeCallback ) ;
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : framebufferResizeCallback ( GLFWwindow * window , int width , int height )
2024-04-01 13:45:00 +08:00
{
2024-04-07 17:29:35 +08:00
auto app = reinterpret_cast < renderMain * > ( glfwGetWindowUserPointer ( window ) ) ;
2024-04-01 13:45:00 +08:00
app - > framebufferResized = true ;
}
2024-04-01 18:05:17 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : buildCommandBuffers ( )
2023-05-17 14:49:05 +08:00
{
2023-06-05 22:37:31 +08:00
VkCommandBufferBeginInfo cmdBufferBeginInfo { } ;
cmdBufferBeginInfo . sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO ;
2023-05-17 14:49:05 +08:00
2023-06-05 22:37:31 +08:00
VkClearValue clearValues [ 3 ] ;
2024-04-08 11:10:30 +08:00
if ( PlumageRender : : Setter : : settings . multiSampling ) {
2023-06-05 22:37:31 +08:00
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.0f , 1.0f } } ;
clearValues [ 1 ] . color = { { 0.0f , 0.0f , 0.0f , 1.0f } } ;
clearValues [ 2 ] . depthStencil = { 1.0f , 0 } ;
}
else {
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.0f , 1.0f } } ;
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
}
2023-05-17 14:49:05 +08:00
2023-06-05 22:37:31 +08:00
VkRenderPassBeginInfo renderPassBeginInfo { } ;
renderPassBeginInfo . sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO ;
renderPassBeginInfo . renderPass = renderPass ;
2023-05-17 14:49:05 +08:00
renderPassBeginInfo . renderArea . offset . x = 0 ;
renderPassBeginInfo . renderArea . offset . y = 0 ;
2024-04-08 11:10:30 +08:00
renderPassBeginInfo . renderArea . extent . width = PlumageRender : : renderMain : : settings . width ;
renderPassBeginInfo . renderArea . extent . height = PlumageRender : : renderMain : : settings . height ;
renderPassBeginInfo . clearValueCount = PlumageRender : : renderMain : : settings . multiSampling ? 3 : 2 ;
2023-05-17 14:49:05 +08:00
renderPassBeginInfo . pClearValues = clearValues ;
2024-03-25 11:51:10 +08:00
2023-06-05 22:37:31 +08:00
for ( uint32_t i = 0 ; i < commandBuffers . size ( ) ; + + i ) {
renderPassBeginInfo . framebuffer = frameBuffers [ i ] ;
2023-05-17 14:49:05 +08:00
2023-06-05 22:37:31 +08:00
VkCommandBuffer currentCB = commandBuffers [ i ] ;
VK_CHECK_RESULT ( vkBeginCommandBuffer ( currentCB , & cmdBufferBeginInfo ) ) ;
vkCmdBeginRenderPass ( currentCB , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
VkViewport viewport { } ;
2024-04-08 11:10:30 +08:00
viewport . width = ( float ) PlumageRender : : Setter : : settings . width ;
viewport . height = ( float ) PlumageRender : : Setter : : settings . height ;
2023-06-05 22:37:31 +08:00
viewport . minDepth = 0.0f ;
viewport . maxDepth = 1.0f ;
vkCmdSetViewport ( currentCB , 0 , 1 , & viewport ) ;
VkRect2D scissor { } ;
2024-04-08 11:10:30 +08:00
scissor . extent = { PlumageRender : : renderMain : : settings . width , PlumageRender : : renderMain : : settings . height } ;
2023-06-05 22:37:31 +08:00
vkCmdSetScissor ( currentCB , 0 , 1 , & scissor ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
2024-04-07 17:29:35 +08:00
2023-06-05 22:37:31 +08:00
if ( displayBackground ) {
vkCmdBindDescriptorSets ( currentCB , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSets [ i ] . skybox , 0 , nullptr ) ;
vkCmdBindPipeline ( currentCB , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . skybox ) ;
models . skybox . draw ( currentCB ) ;
2023-05-25 00:29:04 +08:00
}
2023-06-05 22:37:31 +08:00
glTFModel : : Model & model = models . scene ;
vkCmdBindVertexBuffers ( currentCB , 0 , 1 , & model . vertices . buffer , offsets ) ;
if ( model . indices . buffer ! = VK_NULL_HANDLE ) {
vkCmdBindIndexBuffer ( currentCB , model . indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
}
boundPipeline = VK_NULL_HANDLE ;
// Opaque primitives first
for ( auto node : model . nodes ) {
renderNode ( node , i , glTFModel : : Material : : ALPHAMODE_OPAQUE ) ;
}
// Alpha masked primitives
for ( auto node : model . nodes ) {
renderNode ( node , i , glTFModel : : Material : : ALPHAMODE_MASK ) ;
}
// Transparent primitives
// TODO: Correct depth sorting
for ( auto node : model . nodes ) {
renderNode ( node , i , glTFModel : : Material : : ALPHAMODE_BLEND ) ;
}
// User interface
2024-04-08 11:10:30 +08:00
if ( ! PlumageRender : : Setter : : settings . headless )
2024-03-29 18:11:09 +08:00
{
gui - > draw ( currentCB ) ;
}
2023-06-05 22:37:31 +08:00
vkCmdEndRenderPass ( currentCB ) ;
VK_CHECK_RESULT ( vkEndCommandBuffer ( currentCB ) ) ;
2024-03-25 11:51:10 +08:00
2023-05-17 14:49:05 +08:00
}
}
2023-06-07 16:16:53 +08:00
2023-05-17 14:49:05 +08:00
2024-04-08 11:10:30 +08:00
2023-06-05 22:37:31 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : loadEnvironment ( std : : string filename )
2023-06-05 22:37:31 +08:00
{
std : : cout < < " Loading environment from " < < filename < < std : : endl ;
2024-04-08 11:10:30 +08:00
if ( PlumageRender : : renderMain : : pbrmaterial . textures . environmentCube . image ) {
2023-06-05 22:37:31 +08:00
textures . environmentCube . destroy ( ) ;
textures . irradianceCube . destroy ( ) ;
textures . prefilteredCube . destroy ( ) ;
}
textures . environmentCube . loadFromFile ( filename , VK_FORMAT_R16G16B16A16_SFLOAT , vulkanDevice , queue ) ;
generateCubemaps ( ) ;
}
2023-06-06 11:40:59 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : loadAssets ( )
2023-05-17 14:49:05 +08:00
{
2023-06-06 11:40:59 +08:00
const std : : string assetpath = getAssetPath ( ) ;
2024-03-28 15:23:40 +08:00
if ( std : : filesystem : : exists ( assetpath . c_str ( ) ) ) {
std : : string msg = " asset path get " + assetpath ;
std : : cout < < msg < < std : : endl ;
}
else
{
2024-03-02 21:59:07 +08:00
std : : string msg = " Could not locate asset path in \" " + assetpath + " \" . \n Make sure binary is running from correct relative directory! " ;
2023-06-05 22:37:31 +08:00
std : : cerr < < msg < < std : : endl ;
2023-06-12 11:05:10 +08:00
system ( " pause " ) ;
//exit(-1);
}
2023-06-05 22:37:31 +08:00
2023-06-07 00:45:10 +08:00
readDirectory ( assetpath + " environments " , " *.ktx " , environments , false ) ;
2023-06-05 22:37:31 +08:00
2024-04-08 11:10:30 +08:00
textures . empty . loadFromFile ( PlumageRender : : Setter : : filePath . emptyEnvmapFilePath , VK_FORMAT_R8G8B8A8_UNORM , vulkanDevice , queue ) ;
2023-06-05 22:37:31 +08:00
2024-04-08 11:10:30 +08:00
std : : string sceneFile = PlumageRender : : renderMain : : filePath . glTFModelFilePath ;
std : : string envMapFile = PlumageRender : : renderMain : : filePath . envMapFilePath ;
2024-04-01 13:45:00 +08:00
2023-06-05 22:37:31 +08:00
loadScene ( sceneFile . c_str ( ) ) ;
2024-04-08 11:10:30 +08:00
models . skybox . loadFromFile ( PlumageRender : : Setter : : filePath . skyboxModleFilePath , vulkanDevice , queue ) ;
2023-06-05 22:37:31 +08:00
loadEnvironment ( envMapFile . c_str ( ) ) ;
2023-05-17 14:49:05 +08:00
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : setupNodeDescriptorSet ( glTFModel : : Node * node )
2023-05-17 14:49:05 +08:00
{
/*
This sample uses separate descriptor sets ( and layouts ) for the matrices and materials ( textures )
*/
2024-04-07 17:29:35 +08:00
2023-06-06 11:40:59 +08:00
}
2023-05-17 14:49:05 +08:00
2024-04-01 18:05:17 +08:00
// generate two cube maps
// irradiance cube map
// prefileter environment cube map
// 重构到PBR中
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : generateCubemaps ( )
2023-05-17 14:49:05 +08:00
{
2023-06-06 11:40:59 +08:00
enum Target { IRRADIANCE = 0 , PREFILTEREDENV = 1 } ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
for ( uint32_t target = 0 ; target < PREFILTEREDENV + 1 ; target + + ) {
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vks : : TextureCubeMap cubemap ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkFormat format ;
int32_t dim ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
switch ( target ) {
case IRRADIANCE :
format = VK_FORMAT_R32G32B32A32_SFLOAT ;
dim = 64 ;
break ;
case PREFILTEREDENV :
format = VK_FORMAT_R16G16B16A16_SFLOAT ;
dim = 512 ;
break ;
} ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
const uint32_t numMips = static_cast < uint32_t > ( floor ( log2 ( dim ) ) ) + 1 ;
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// 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 ( device , & imageCI , nullptr , & cubemap . image ) ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , cubemap . image , & memReqs ) ;
VkMemoryAllocateInfo memAllocInfo { } ;
memAllocInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memAllocInfo . allocationSize = memReqs . size ;
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & cubemap . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( 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 ( 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 ( device , & samplerCI , nullptr , & cubemap . sampler ) ) ;
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// 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 ( device , & renderPassCI , nullptr , & renderpass ) ) ;
// Create offscreen framebuffer
2023-05-25 16:13:37 +08:00
{
2023-06-06 11:40:59 +08:00
// 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 ( device , & imageCI , nullptr , & offscreen . image ) ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , offscreen . image , & memReqs ) ;
VkMemoryAllocateInfo memAllocInfo { } ;
memAllocInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memAllocInfo . allocationSize = memReqs . size ;
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & offscreen . memory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( 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 ( 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 ( device , & framebufferCI , nullptr , & offscreen . framebuffer ) ) ;
VkCommandBuffer layoutCmd = 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 ) ;
vulkanDevice - > flushCommandBuffer ( layoutCmd , queue , true ) ;
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// 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 ( 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 ( 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 ( 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 ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// 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 ;
} ;
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
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 ( 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 ;
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
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 ;
2024-04-08 11:10:30 +08:00
shaderStages [ 0 ] = loadShader ( device , PlumageRender : : renderMain : : filePath . filterVertShaderPath , VK_SHADER_STAGE_VERTEX_BIT ) ;
2023-06-06 11:40:59 +08:00
switch ( target ) {
case IRRADIANCE :
2024-04-08 11:10:30 +08:00
shaderStages [ 1 ] = loadShader ( device , PlumageRender : : renderMain : : filePath . irradianceFragShaderPath , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2023-06-06 11:40:59 +08:00
break ;
case PREFILTEREDENV :
2024-04-08 11:10:30 +08:00
shaderStages [ 1 ] = loadShader ( device , PlumageRender : : renderMain : : filePath . prefilterEnvmapFragShaderPath , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2023-06-06 11:40:59 +08:00
break ;
2023-05-25 16:13:37 +08:00
} ;
2023-06-06 11:40:59 +08:00
VkPipeline pipeline ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
for ( auto shaderStage : shaderStages ) {
vkDestroyShaderModule ( device , shaderStage . module , nullptr ) ;
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// 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 ) ) ,
} ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkCommandBuffer cmdBuf = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , false ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkViewport viewport { } ;
viewport . width = ( float ) dim ;
viewport . height = ( float ) dim ;
viewport . minDepth = 0.0f ;
viewport . maxDepth = 1.0f ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkRect2D scissor { } ;
scissor . extent . width = dim ;
scissor . extent . height = dim ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkImageSubresourceRange subresourceRange { } ;
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
subresourceRange . baseMipLevel = 0 ;
subresourceRange . levelCount = numMips ;
subresourceRange . layerCount = 6 ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Change image layout for all cubemap faces to transfer destination
2023-05-24 16:10:36 +08:00
{
2023-06-06 11:40:59 +08:00
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 ) ;
vulkanDevice - > flushCommandBuffer ( cmdBuf , queue , false ) ;
2023-05-24 16:10:36 +08:00
}
2023-06-06 11:40:59 +08:00
for ( uint32_t m = 0 ; m < numMips ; m + + ) {
for ( uint32_t f = 0 ; f < 6 ; f + + ) {
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vulkanDevice - > beginCommandBuffer ( cmdBuf ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
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 ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Render scene from cube face's point of view
vkCmdBeginRenderPass ( cmdBuf , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// 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 ] ;
2023-06-06 15:52:39 +08:00
vkCmdPushConstants ( cmdBuf , pipelinelayout , VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , 0 , sizeof ( IrradiancePushBlock ) , & irradiancePushBlock ) ;
2023-06-06 11:40:59 +08:00
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 ) ;
2023-06-06 15:52:39 +08:00
vkCmdPushConstants ( cmdBuf , pipelinelayout , VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , 0 , sizeof ( PrefilterPushBlock ) , & prefilterPushBlock ) ;
2023-06-06 11:40:59 +08:00
break ;
} ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vkCmdBindPipeline ( cmdBuf , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
vkCmdBindDescriptorSets ( cmdBuf , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelinelayout , 0 , 1 , & descriptorset , 0 , NULL ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
VkDeviceSize offsets [ 1 ] = { 0 } ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
models . skybox . draw ( cmdBuf ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vkCmdEndRenderPass ( cmdBuf ) ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
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 ;
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
{
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 ) ;
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
// Copy region for transfer from framebuffer to cube face
VkImageCopy copyRegion { } ;
copyRegion . srcSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
copyRegion . srcSubresource . baseArrayLayer = 0 ;
copyRegion . srcSubresource . mipLevel = 0 ;
copyRegion . srcSubresource . layerCount = 1 ;
copyRegion . srcOffset = { 0 , 0 , 0 } ;
copyRegion . dstSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
copyRegion . dstSubresource . baseArrayLayer = f ;
copyRegion . dstSubresource . mipLevel = m ;
copyRegion . dstSubresource . layerCount = 1 ;
copyRegion . dstOffset = { 0 , 0 , 0 } ;
copyRegion . extent . width = static_cast < uint32_t > ( viewport . width ) ;
copyRegion . extent . height = static_cast < uint32_t > ( viewport . height ) ;
copyRegion . extent . depth = 1 ;
vkCmdCopyImage (
cmdBuf ,
offscreen . image ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ,
cubemap . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
1 ,
& copyRegion ) ;
{
VkImageMemoryBarrier imageMemoryBarrier { } ;
imageMemoryBarrier . sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER ;
imageMemoryBarrier . image = offscreen . image ;
imageMemoryBarrier . oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ;
imageMemoryBarrier . newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
imageMemoryBarrier . srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT ;
imageMemoryBarrier . dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ;
imageMemoryBarrier . subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 1 , 0 , 1 } ;
vkCmdPipelineBarrier ( cmdBuf , VK_PIPELINE_STAGE_ALL_COMMANDS_BIT , VK_PIPELINE_STAGE_ALL_COMMANDS_BIT , 0 , 0 , nullptr , 0 , nullptr , 1 , & imageMemoryBarrier ) ;
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vulkanDevice - > flushCommandBuffer ( cmdBuf , queue , false ) ;
}
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
{
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 ) ;
vulkanDevice - > flushCommandBuffer ( cmdBuf , queue , false ) ;
}
2023-05-24 16:10:36 +08:00
2023-06-06 11:40:59 +08:00
vkDestroyRenderPass ( device , renderpass , nullptr ) ;
vkDestroyFramebuffer ( device , offscreen . framebuffer , nullptr ) ;
vkFreeMemory ( device , offscreen . memory , nullptr ) ;
vkDestroyImageView ( device , offscreen . view , nullptr ) ;
vkDestroyImage ( device , offscreen . image , nullptr ) ;
vkDestroyDescriptorPool ( device , descriptorpool , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorsetlayout , nullptr ) ;
vkDestroyPipeline ( device , pipeline , nullptr ) ;
vkDestroyPipelineLayout ( 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 = 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 ;
2023-05-24 16:10:36 +08:00
}
}
2024-04-01 18:05:17 +08:00
// generate BRDF integration map for roughness/NdotV
// 重构到PBR
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : generateBRDFLUT ( )
2023-05-24 16:10:36 +08:00
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-06-06 11:40:59 +08:00
const VkFormat format = VK_FORMAT_R16G16_SFLOAT ;
const int32_t dim = 512 ;
2023-05-24 16:10:36 +08:00
// Image
2023-06-06 11:40:59 +08:00
VkImageCreateInfo imageCI { } ;
imageCI . sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO ;
2023-05-24 16:10:36 +08:00
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 ;
2023-06-06 11:40:59 +08:00
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCI , nullptr , & textures . lutBrdf . image ) ) ;
2023-05-24 16:10:36 +08:00
VkMemoryRequirements memReqs ;
2023-06-06 11:40:59 +08:00
vkGetImageMemoryRequirements ( device , textures . lutBrdf . image , & memReqs ) ;
VkMemoryAllocateInfo memAllocInfo { } ;
memAllocInfo . sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO ;
memAllocInfo . allocationSize = memReqs . size ;
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & textures . lutBrdf . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , textures . lutBrdf . image , textures . lutBrdf . deviceMemory , 0 ) ) ;
// View
VkImageViewCreateInfo viewCI { } ;
viewCI . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ;
2023-05-24 16:10:36 +08:00
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 ;
2023-06-06 11:40:59 +08:00
viewCI . image = textures . lutBrdf . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & viewCI , nullptr , & textures . lutBrdf . view ) ) ;
2023-05-24 16:10:36 +08:00
// Sampler
2023-06-06 11:40:59 +08:00
VkSamplerCreateInfo samplerCI { } ;
samplerCI . sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO ;
2023-05-24 16:10:36 +08:00
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 ;
2023-06-06 11:40:59 +08:00
samplerCI . maxAnisotropy = 1.0f ;
2023-05-24 16:10:36 +08:00
samplerCI . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
2023-06-06 11:40:59 +08:00
VK_CHECK_RESULT ( vkCreateSampler ( device , & samplerCI , nullptr , & textures . lutBrdf . sampler ) ) ;
2023-05-24 16:10:36 +08:00
// FB, Att, RP, Pipe, etc.
2023-06-06 11:40:59 +08:00
VkAttachmentDescription attDesc { } ;
2023-05-24 16:10:36 +08:00
// 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 } ;
2023-06-06 11:40:59 +08:00
VkSubpassDescription subpassDescription { } ;
2023-05-24 16:10:36 +08:00
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 ;
2023-06-06 11:40:59 +08:00
// Create the actual renderpass
VkRenderPassCreateInfo renderPassCI { } ;
renderPassCI . sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO ;
2023-05-24 16:10:36 +08:00
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 ( device , & renderPassCI , nullptr , & renderpass ) ) ;
2023-06-06 11:40:59 +08:00
VkFramebufferCreateInfo framebufferCI { } ;
framebufferCI . sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO ;
2023-05-24 16:10:36 +08:00
framebufferCI . renderPass = renderpass ;
framebufferCI . attachmentCount = 1 ;
2023-06-06 11:40:59 +08:00
framebufferCI . pAttachments = & textures . lutBrdf . view ;
2023-05-24 16:10:36 +08:00
framebufferCI . width = dim ;
framebufferCI . height = dim ;
framebufferCI . layers = 1 ;
VkFramebuffer framebuffer ;
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & framebufferCI , nullptr , & framebuffer ) ) ;
2023-06-06 11:40:59 +08:00
// Desriptors
2023-05-24 16:10:36 +08:00
VkDescriptorSetLayout descriptorsetlayout ;
2023-06-06 11:40:59 +08:00
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI { } ;
descriptorSetLayoutCI . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorsetlayout ) ) ;
2023-05-24 16:10:36 +08:00
// Pipeline layout
VkPipelineLayout pipelinelayout ;
2023-06-06 11:40:59 +08:00
VkPipelineLayoutCreateInfo pipelineLayoutCI { } ;
pipelineLayoutCI . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
pipelineLayoutCI . setLayoutCount = 1 ;
pipelineLayoutCI . pSetLayouts = & descriptorsetlayout ;
2023-05-24 16:10:36 +08:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelinelayout ) ) ;
// Pipeline
2023-06-06 11:40:59 +08:00
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 ;
2023-05-24 16:10:36 +08:00
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
2023-06-06 11:40:59 +08:00
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 ;
2023-05-24 16:10:36 +08:00
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2023-06-06 11:40:59 +08:00
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 ;
2023-05-24 16:10:36 +08:00
pipelineCI . stageCount = 2 ;
pipelineCI . pStages = shaderStages . data ( ) ;
2023-06-06 11:40:59 +08:00
// Look-up-table (from BRDF) pipeline
shaderStages = {
2024-04-08 11:10:30 +08:00
loadShader ( device , PlumageRender : : Setter : : filePath . brdfVertShaderPath , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( device , PlumageRender : : Setter : : filePath . brdfFragShaderPath , VK_SHADER_STAGE_FRAGMENT_BIT )
2023-06-06 11:40:59 +08:00
} ;
2023-05-24 16:10:36 +08:00
VkPipeline pipeline ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
2023-06-06 11:40:59 +08:00
for ( auto shaderStage : shaderStages ) {
vkDestroyShaderModule ( device , shaderStage . module , nullptr ) ;
}
2023-05-24 16:10:36 +08:00
// Render
VkClearValue clearValues [ 1 ] ;
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.0f , 1.0f } } ;
2023-06-06 11:40:59 +08:00
VkRenderPassBeginInfo renderPassBeginInfo { } ;
renderPassBeginInfo . sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO ;
2023-05-24 16:10:36 +08:00
renderPassBeginInfo . renderPass = renderpass ;
renderPassBeginInfo . renderArea . extent . width = dim ;
renderPassBeginInfo . renderArea . extent . height = dim ;
renderPassBeginInfo . clearValueCount = 1 ;
renderPassBeginInfo . pClearValues = clearValues ;
renderPassBeginInfo . framebuffer = framebuffer ;
VkCommandBuffer cmdBuf = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
vkCmdBeginRenderPass ( cmdBuf , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
2023-06-06 11:40:59 +08:00
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 ;
2023-05-24 16:10:36 +08:00
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 ) ;
vulkanDevice - > flushCommandBuffer ( cmdBuf , queue ) ;
vkQueueWaitIdle ( queue ) ;
vkDestroyPipeline ( device , pipeline , nullptr ) ;
vkDestroyPipelineLayout ( device , pipelinelayout , nullptr ) ;
vkDestroyRenderPass ( device , renderpass , nullptr ) ;
vkDestroyFramebuffer ( device , framebuffer , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorsetlayout , nullptr ) ;
2023-06-06 11:40:59 +08:00
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 = vulkanDevice ;
2023-05-24 16:10:36 +08:00
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 ;
2023-05-25 16:13:37 +08:00
}
2023-06-06 15:52:39 +08:00
2024-04-07 17:29:35 +08:00
// Prepare and initialize uniform buffer containing shader uniforms
// 更新统一缓冲区 done
void PlumageRender : : renderMain : : updateUniformBuffers ( )
2023-05-17 14:49:05 +08:00
{
2024-04-07 17:29:35 +08:00
// Scene
shaderDataScene . projection = camera . matrices . perspective ;
shaderDataScene . view = camera . matrices . view ;
// Center and scale model
float scale = ( 1.0f / std : : max ( models . scene . aabb [ 0 ] [ 0 ] , std : : max ( models . scene . aabb [ 1 ] [ 1 ] , models . scene . aabb [ 2 ] [ 2 ] ) ) ) * 0.5f ;
glm : : vec3 translate = - glm : : vec3 ( models . scene . aabb [ 3 ] [ 0 ] , models . scene . aabb [ 3 ] [ 1 ] , models . scene . aabb [ 3 ] [ 2 ] ) ;
translate + = - 0.5f * glm : : vec3 ( models . scene . aabb [ 0 ] [ 0 ] , models . scene . aabb [ 1 ] [ 1 ] , models . scene . aabb [ 2 ] [ 2 ] ) ;
shaderDataScene . model = glm : : mat4 ( 1.0f ) ;
shaderDataScene . model [ 0 ] [ 0 ] = scale ;
shaderDataScene . model [ 1 ] [ 1 ] = scale ;
shaderDataScene . model [ 2 ] [ 2 ] = scale ;
shaderDataScene . model = glm : : translate ( shaderDataScene . model , translate ) ;
shaderDataScene . camPos = glm : : vec3 (
- camera . position . z * sin ( glm : : radians ( camera . rotation . y ) ) * cos ( glm : : radians ( camera . rotation . x ) ) ,
- camera . position . z * sin ( glm : : radians ( camera . rotation . x ) ) ,
camera . position . z * cos ( glm : : radians ( camera . rotation . y ) ) * cos ( glm : : radians ( camera . rotation . x ) )
) ;
// Skybox
shaderDataSkybox . projection = camera . matrices . perspective ;
shaderDataSkybox . view = camera . matrices . view ;
shaderDataSkybox . model = glm : : mat4 ( glm : : mat3 ( camera . matrices . view ) ) ;
2023-06-06 15:52:39 +08:00
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : updateShaderData ( )
2023-06-06 15:52:39 +08:00
{
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 ) ;
}
2024-04-01 18:05:17 +08:00
// todo: 重写成glfw的
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : windowResized ( )
2023-06-06 15:52:39 +08:00
{
buildCommandBuffers ( ) ;
vkDeviceWaitIdle ( device ) ;
updateUniformBuffers ( ) ;
2023-06-07 10:52:04 +08:00
//update UI
updateUIOverlay ( ) ;
2023-05-17 14:49:05 +08:00
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : prepare ( )
{
//VulkanExampleBase::prepare();
2023-06-06 15:52:39 +08:00
2024-04-07 17:29:35 +08:00
setupCamera ( ) ;
2023-06-06 15:52:39 +08:00
2024-04-07 17:29:35 +08:00
loadAssets ( ) ;
generateBRDFLUT ( ) ;
generateCubemaps ( ) ;
prepareUniformBuffers ( ) ;
setupDescriptors ( ) ;
preparePipelines ( ) ;
2024-04-08 11:10:30 +08:00
if ( ! PlumageRender : : Setter : : settings . headless )
2024-04-07 17:29:35 +08:00
{
2024-04-08 11:10:30 +08:00
gui = new UI ( vulkanDevice , renderPass , queue , pipelineCache , PlumageRender : : renderMain : : settings . sampleCount ) ;
2024-04-07 17:29:35 +08:00
updateUIOverlay ( ) ;
}
buildCommandBuffers ( ) ;
2023-06-06 15:52:39 +08:00
2024-04-07 17:29:35 +08:00
prepared = true ;
}
2023-06-06 15:52:39 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : setupCamera ( )
{
camera . type = Camera : : CameraType : : lookat ;
2023-06-06 15:52:39 +08:00
2024-04-08 11:10:30 +08:00
camera . setPerspective ( 45.0f , ( float ) PlumageRender : : Setter : : settings . width / ( float ) PlumageRender : : Setter : : settings . height , 0.1f , 256.0f ) ;
2024-04-07 17:29:35 +08:00
camera . rotationSpeed = 0.25f ;
camera . movementSpeed = 0.1f ;
camera . setPosition ( { 0.0f , 0.0f , - 1.0f } ) ;
camera . setRotation ( { 0.0f , 0.0f , 0.0f } ) ;
}
2023-05-17 14:49:05 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : submitWork ( VkCommandBuffer cmdBuffer , VkQueue queue )
2024-03-22 18:05:18 +08:00
{
VkSubmitInfo submitInfo = vks : : initializers : : submitInfo ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & cmdBuffer ;
2024-03-26 14:59:37 +08:00
VkFenceCreateInfo fenceInfo = vks : : initializers : : fenceCreateInfo ( ) ;
VkFence fence ;
VK_CHECK_RESULT ( vkCreateFence ( device , & fenceInfo , nullptr , & fence ) ) ;
2024-03-22 18:05:18 +08:00
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , fence ) ) ;
VK_CHECK_RESULT ( vkWaitForFences ( device , 1 , & fence , VK_TRUE , UINT64_MAX ) ) ;
2024-03-26 14:59:37 +08:00
vkDestroyFence ( device , fence , nullptr ) ;
2024-03-22 18:05:18 +08:00
}
2024-04-01 18:05:17 +08:00
// todo :根据physicalDeviceIndex确定子文件夹路径, frameIndex确定fileName
// 移动到fileSystem里
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : writeImageToFile ( std : : string filePath )
2024-03-22 18:05:18 +08:00
{
2024-03-26 14:59:37 +08:00
2024-03-26 15:17:51 +08:00
bool screenshotSaved = false ;
bool supportsBlit = true ;
2024-03-26 14:59:37 +08:00
2024-03-26 15:17:51 +08:00
// Check blit support for source and destination
VkFormatProperties formatProps ;
2024-03-26 14:59:37 +08:00
2024-03-26 15:17:51 +08:00
// Check if the device supports blitting from optimal images (the swapchain images are in optimal format)
vkGetPhysicalDeviceFormatProperties ( physicalDevice , swapChain . colorFormat , & 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 ;
}
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// Check if the device supports blitting to linear images
vkGetPhysicalDeviceFormatProperties ( 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 ;
}
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// Source for the copy is the last rendered swapchain image
VkImage srcImage = swapChain . images [ currentBuffer ] ;
2024-03-29 18:11:09 +08:00
2024-03-26 15:17:51 +08:00
// 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 ;
2024-04-08 11:10:30 +08:00
imageCreateCI . extent . width = PlumageRender : : renderMain : : settings . width ;
imageCreateCI . extent . height = PlumageRender : : renderMain : : settings . height ;
2024-03-26 15:17:51 +08:00
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 ( device , & imageCreateCI , nullptr , & dstImage ) ) ;
// Create memory to back up the image
2024-03-22 18:05:18 +08:00
VkMemoryRequirements memRequirements ;
VkMemoryAllocateInfo memAllocInfo ( vks : : initializers : : memoryAllocateInfo ( ) ) ;
VkDeviceMemory dstImageMemory ;
vkGetImageMemoryRequirements ( device , dstImage , & memRequirements ) ;
memAllocInfo . allocationSize = memRequirements . size ;
2024-03-26 15:17:51 +08:00
// Memory must be host visible to copy from
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memRequirements . memoryTypeBits , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ) ;
2024-03-22 18:05:18 +08:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & dstImageMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , dstImage , dstImageMemory , 0 ) ) ;
2024-03-26 15:17:51 +08:00
// Do the actual blit from the swapchain image to our host visible destination image
VkCommandBuffer copyCmd = 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 ,
2024-03-29 18:11:09 +08:00
//VK_IMAGE_LAYOUT_UNDEFINED,
2024-03-26 15:17:51 +08:00
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 ;
2024-04-08 11:10:30 +08:00
blitSize . x = PlumageRender : : renderMain : : settings . width ;
blitSize . y = PlumageRender : : renderMain : : settings . height ;
2024-03-26 15:17:51 +08:00
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 ;
2024-04-08 11:10:30 +08:00
imageCopyRegion . extent . width = PlumageRender : : renderMain : : settings . width ;
imageCopyRegion . extent . height = PlumageRender : : renderMain : : settings . height ;
2024-03-26 15:17:51 +08:00
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 ) ;
}
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// 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 } ) ;
2024-04-08 11:10:30 +08:00
if ( ! PlumageRender : : Setter : : settings . headless )
2024-03-29 18:11:09 +08:00
{
// 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 } ) ;
}
2024-03-26 15:17:51 +08:00
vulkanDevice - > flushCommandBuffer ( copyCmd , queue ) ;
// Get layout of the image (including row pitch)
VkImageSubresource subResource { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 0 } ;
2024-03-22 18:05:18 +08:00
VkSubresourceLayout subResourceLayout ;
vkGetImageSubresourceLayout ( device , dstImage , & subResource , & subResourceLayout ) ;
2024-03-26 15:17:51 +08:00
// Map image memory so we can start copying from it
const char * data ;
vkMapMemory ( device , dstImageMemory , 0 , VK_WHOLE_SIZE , 0 , ( void * * ) & data ) ;
data + = subResourceLayout . offset ;
2024-03-22 18:05:18 +08:00
2024-03-26 15:17:51 +08:00
// 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 ( ) , swapChain . colorFormat ) ! = formatsBGR . end ( ) ) ;
}
2024-03-22 18:05:18 +08:00
2024-04-08 11:10:30 +08:00
if ( PlumageRender : : Setter : : settings . outputPNGimage )
2024-03-26 15:17:51 +08:00
{
2024-03-29 11:04:47 +08:00
if ( colorSwizzle )
2024-03-26 15:17:51 +08:00
{
2024-03-29 15:45:45 +08:00
// 暂时不改, 此处需要将BGR通道改成RGB格式
2024-04-08 11:10:30 +08:00
stbi_write_png ( filePath . c_str ( ) , PlumageRender : : renderMain : : settings . width , PlumageRender : : renderMain : : settings . height , 4 , data , static_cast < int > ( subResourceLayout . rowPitch ) ) ;
2024-03-29 11:04:47 +08:00
}
else
{
2024-04-08 11:10:30 +08:00
stbi_write_png ( filePath . c_str ( ) , PlumageRender : : renderMain : : settings . width , PlumageRender : : renderMain : : settings . height , 4 , data , static_cast < int > ( subResourceLayout . rowPitch ) ) ;
2024-03-29 11:04:47 +08:00
}
}
else
{
std : : ofstream file ( filePath , std : : ios : : out | std : : ios : : binary ) ;
// ppm header
2024-04-08 11:10:30 +08:00
file < < " P6 \n " < < PlumageRender : : renderMain : : settings . width < < " \n " < < PlumageRender : : renderMain : : settings . height < < " \n " < < 255 < < " \n " ;
2024-03-29 11:04:47 +08:00
// ppm binary pixel data
2024-04-08 11:10:30 +08:00
for ( uint32_t y = 0 ; y < PlumageRender : : renderMain : : settings . height ; y + + )
2024-03-29 11:04:47 +08:00
{
unsigned int * row = ( unsigned int * ) data ;
2024-04-08 11:10:30 +08:00
for ( uint32_t x = 0 ; x < PlumageRender : : renderMain : : settings . width ; x + + )
2024-03-26 15:17:51 +08:00
{
2024-03-29 11:04:47 +08:00
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 + + ;
2024-03-22 18:05:18 +08:00
}
2024-03-29 11:04:47 +08:00
data + = subResourceLayout . rowPitch ;
2024-03-22 18:05:18 +08:00
}
2024-03-29 11:04:47 +08:00
file . close ( ) ;
2024-03-22 18:05:18 +08:00
}
2024-03-29 11:04:47 +08:00
2024-03-26 18:04:18 +08:00
std : : cout < < " Screenshot saved to " < < filePath < < std : : endl ;
2024-03-22 18:05:18 +08:00
// Clean up resources
vkUnmapMemory ( device , dstImageMemory ) ;
vkFreeMemory ( device , dstImageMemory , nullptr ) ;
vkDestroyImage ( device , dstImage , nullptr ) ;
2024-03-26 15:17:51 +08:00
screenshotSaved = true ;
2024-03-25 11:51:10 +08:00
2024-03-22 18:05:18 +08:00
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : outputImageSequence ( )
2024-03-22 18:05:18 +08:00
{
2024-03-28 15:23:40 +08:00
// 比较已保存的帧数和设置里的开始帧数,在生成前清理上一次生成的图片序列
2024-04-08 11:10:30 +08:00
if ( savedFrameCounter = = PlumageRender : : renderMain : : settings . startFrameCount )
2024-03-28 11:12:47 +08:00
{
std : : cout < < " clean up directory for image sequence generation " < < std : : endl ;
removeImageSequence ( ) ;
}
2024-03-28 15:23:40 +08:00
// 根据显卡编号设置输出路径( todo: 提前到配置里)
2024-04-08 11:10:30 +08:00
PlumageRender : : renderMain : : filePath . deviceSpecFilePath = PlumageRender : : renderMain : : filePath . imageOutputPath + " /device " + std : : to_string ( selectedPhysicalDeviceIndex ) ;
2024-03-28 15:23:40 +08:00
// 非第一次生成,生成结束的边界条件
2024-04-08 11:10:30 +08:00
if ( savedFrameCounter > PlumageRender : : renderMain : : settings . endFrameIndex )
2024-03-25 11:51:10 +08:00
{
2024-03-28 15:23:40 +08:00
// 避免重复改变为true带来的无效性能开销
if ( signal . imageSequenceOutputComplete )
2024-03-27 17:29:32 +08:00
{
return ;
}
2024-03-28 15:23:40 +08:00
// 生成结束的信号标志置为true
2024-03-27 17:29:32 +08:00
signal . imageSequenceOutputComplete = true ;
2024-03-28 15:23:40 +08:00
// 构造ffmpeg脚本需要的路径变量(提前到配置)
2024-03-27 17:29:32 +08:00
std : : string fileName = " /%dresult.ppm " ;
2024-04-08 11:10:30 +08:00
PlumageRender : : Setter : : filePath . totalImageOutputPath = PlumageRender : : renderMain : : filePath . deviceSpecFilePath + fileName ;
2024-03-26 18:04:18 +08:00
return ;
2024-03-25 11:51:10 +08:00
}
2024-03-28 15:23:40 +08:00
// 路径存在性检查,不存在则创建
2024-04-08 11:10:30 +08:00
if ( ! std : : filesystem : : exists ( PlumageRender : : Setter : : filePath . deviceSpecFilePath . c_str ( ) ) )
2024-03-26 14:59:37 +08:00
{
2024-04-08 11:10:30 +08:00
std : : filesystem : : create_directories ( PlumageRender : : Setter : : filePath . deviceSpecFilePath . c_str ( ) ) ;
2024-03-26 14:59:37 +08:00
}
2024-03-28 15:23:40 +08:00
// 拼接图片序列编号到路径里
2024-03-28 11:12:47 +08:00
std : : string fileName = " / " + std : : to_string ( savedFrameCounter ) + " result.ppm " ;
2024-04-08 11:10:30 +08:00
PlumageRender : : Setter : : filePath . totalImageOutputPath = PlumageRender : : renderMain : : filePath . deviceSpecFilePath + fileName ;
2024-03-26 18:04:18 +08:00
//std::cout << outputPath << std::endl;
2024-03-28 15:23:40 +08:00
// 写入文件
2024-04-08 11:10:30 +08:00
writeImageToFile ( PlumageRender : : Setter : : filePath . totalImageOutputPath . c_str ( ) ) ;
2024-03-28 15:23:40 +08:00
// 写入一帧后已保存帧数+1
2024-03-26 18:04:18 +08:00
savedFrameCounter + + ;
2024-03-22 18:05:18 +08:00
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : imageSequenceToVideo ( )
2024-03-27 17:29:32 +08:00
{
2024-03-28 15:23:40 +08:00
// 边界条件,图片序列输出未完成
2024-03-27 17:29:32 +08:00
if ( ! signal . imageSequenceOutputComplete )
{
return ;
}
2024-03-28 15:23:40 +08:00
// 边界条件,图片序列到视频的输出已完成
2024-03-27 17:29:32 +08:00
if ( signal . imageSequenceToVideoComplete )
{
return ;
}
2024-03-28 15:23:40 +08:00
// 拼接视频保存的设备编号路径(提前到配置文件进行)
2024-04-08 11:10:30 +08:00
std : : string deviceFilePath = PlumageRender : : renderMain : : filePath . videoOutputPath + " /device " + std : : to_string ( selectedPhysicalDeviceIndex ) ;
2024-03-28 15:23:40 +08:00
// 判断路径是否存在,不存在则创建
if ( std : : filesystem : : exists ( deviceFilePath . c_str ( ) ) )
2024-03-27 17:29:32 +08:00
{
std : : filesystem : : create_directories ( deviceFilePath . c_str ( ) ) ;
}
2024-03-28 15:23:40 +08:00
// 构造结果视频路径
2024-03-27 17:29:32 +08:00
std : : string resultVideoPath = deviceFilePath + " /result.mp4 " ;
2024-03-28 15:23:40 +08:00
// 构造脚本需要参数,图片序列路径和设定的帧率
2024-04-08 11:10:30 +08:00
std : : string commandLineImageSequencePath = PlumageRender : : renderMain : : filePath . totalImageOutputPath ;
2024-03-27 17:29:32 +08:00
//std::string commandLineCodecAndResultPath = resultVideoPath;
2024-04-08 11:10:30 +08:00
std : : string commandLineFrameRate = std : : to_string ( PlumageRender : : renderMain : : settings . videoFrameRate ) ;
2024-03-28 15:23:40 +08:00
// 根据不同系统使用不同脚本
2024-03-27 17:29:32 +08:00
# if defined(_WIN32)
2024-04-08 11:10:30 +08:00
std : : string commandLine = PlumageRender : : renderMain : : filePath . image2videoBatFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath ;
2024-03-27 17:29:32 +08:00
# else
std : : string commandLine = filePath . image2videoShFilePath + " " + commandLineFrameRate + " " + commandLineImageSequencePath + " " + resultVideoPath ;
# endif
std : : cout < < commandLine < < std : : endl ;
std : : system ( commandLine . c_str ( ) ) ;
2024-03-28 15:23:40 +08:00
// 视频输出完成, 置标志为true
2024-03-27 17:29:32 +08:00
signal . imageSequenceToVideoComplete = true ;
std : : cout < < " vidoe codec complete,saved in: " < < resultVideoPath < < std : : endl ;
2024-03-28 11:12:47 +08:00
std : : cout < < " star to clean up image sequence " < < std : : endl ;
removeImageSequence ( ) ;
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : removeImageSequence ( )
2024-03-28 11:12:47 +08:00
{
2024-03-28 15:23:40 +08:00
// 函数非第一次运行的边界条件
2024-04-08 11:10:30 +08:00
if ( savedFrameCounter ! = PlumageRender : : renderMain : : settings . startFrameCount )
2024-03-28 11:12:47 +08:00
{
2024-03-28 15:23:40 +08:00
// 检查视频输出完成的标志位
2024-03-28 11:12:47 +08:00
if ( ! signal . imageSequenceToVideoComplete )
{
return ;
}
}
2024-03-28 15:23:40 +08:00
// 遍历删除图片序列文件和空文件夹
2024-04-08 11:10:30 +08:00
if ( std : : filesystem : : exists ( PlumageRender : : Setter : : filePath . deviceSpecFilePath ) )
2024-03-28 11:12:47 +08:00
{
2024-04-08 11:10:30 +08:00
for ( const auto & entry : std : : filesystem : : directory_iterator ( PlumageRender : : Setter : : filePath . deviceSpecFilePath ) )
2024-03-28 11:12:47 +08:00
{
if ( std : : filesystem : : is_directory ( entry . path ( ) ) )
{
std : : filesystem : : remove_all ( entry . path ( ) ) ;
}
else
{
std : : filesystem : : remove ( entry . path ( ) ) ;
}
}
2024-04-08 11:10:30 +08:00
std : : filesystem : : remove ( PlumageRender : : Setter : : filePath . deviceSpecFilePath ) ;
2024-03-28 11:12:47 +08:00
std : : cout < < " clean up complete " < < std : : endl ;
}
return ;
2024-03-27 17:29:32 +08:00
}
2024-03-29 18:11:09 +08:00
2024-03-22 18:05:18 +08:00
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : render ( )
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +08:00
if ( ! prepared ) {
return ;
}
2024-04-08 11:10:30 +08:00
if ( ! PlumageRender : : Setter : : settings . headless )
2024-03-29 18:11:09 +08:00
{
updateUIOverlay ( ) ;
}
2024-03-22 18:05:18 +08:00
//加入写到文件的函数
//swapChainImage = swapChain.images[frameIndex];
2024-03-26 14:59:37 +08:00
//outputImageSequeue(swapChainImage,filePath.imageSequenceFilePath);
2024-03-25 11:51:10 +08:00
2024-03-26 18:04:18 +08:00
outputImageSequence ( ) ;
2024-03-29 18:11:09 +08:00
VK_CHECK_RESULT ( vkWaitForFences ( device , 1 , & waitFences [ frameIndex ] , VK_TRUE , UINT64_MAX ) ) ;
2024-03-27 17:29:32 +08:00
imageSequenceToVideo ( ) ;
2024-03-26 14:59:37 +08:00
VK_CHECK_RESULT ( vkResetFences ( device , 1 , & waitFences [ frameIndex ] ) ) ;
2023-06-06 15:52:39 +08:00
VkResult acquire = swapChain . acquireNextImage ( presentCompleteSemaphores [ frameIndex ] , & currentBuffer ) ;
if ( ( acquire = = VK_ERROR_OUT_OF_DATE_KHR ) | | ( acquire = = VK_SUBOPTIMAL_KHR ) ) {
windowResize ( ) ;
}
else {
VK_CHECK_RESULT ( acquire ) ;
2024-03-22 18:05:18 +08:00
2024-03-26 14:59:37 +08:00
2023-06-06 15:52:39 +08:00
}
2024-03-29 18:11:09 +08:00
2023-06-06 15:52:39 +08:00
// Update UBOs
updateUniformBuffers ( ) ;
2024-04-07 17:29:35 +08:00
UniformBufferSet [ currentUB ] = uniformBuffers [ currentBuffer ] ;
2023-06-06 15:52:39 +08:00
memcpy ( currentUB . scene . mapped , & shaderDataScene , sizeof ( shaderDataScene ) ) ;
memcpy ( currentUB . params . mapped , & shaderData , sizeof ( shaderData ) ) ;
memcpy ( currentUB . skybox . mapped , & shaderDataSkybox , sizeof ( shaderDataSkybox ) ) ;
const VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
VkSubmitInfo submitInfo { } ;
submitInfo . sType = VK_STRUCTURE_TYPE_SUBMIT_INFO ;
submitInfo . pWaitDstStageMask = & waitDstStageMask ;
submitInfo . pWaitSemaphores = & presentCompleteSemaphores [ frameIndex ] ;
submitInfo . waitSemaphoreCount = 1 ;
submitInfo . pSignalSemaphores = & renderCompleteSemaphores [ frameIndex ] ;
submitInfo . signalSemaphoreCount = 1 ;
submitInfo . pCommandBuffers = & commandBuffers [ currentBuffer ] ;
submitInfo . commandBufferCount = 1 ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , waitFences [ frameIndex ] ) ) ;
2024-03-26 14:59:37 +08:00
2024-03-22 18:05:18 +08:00
//显示队列
2024-03-29 18:11:09 +08:00
2023-06-06 15:52:39 +08:00
VkResult present = swapChain . queuePresent ( queue , currentBuffer , renderCompleteSemaphores [ frameIndex ] ) ;
if ( ! ( ( present = = VK_SUCCESS ) | | ( present = = VK_SUBOPTIMAL_KHR ) ) ) {
if ( present = = VK_ERROR_OUT_OF_DATE_KHR ) {
windowResize ( ) ;
return ;
}
else {
VK_CHECK_RESULT ( present ) ;
}
}
frameIndex + = 1 ;
frameIndex % = renderAhead ;
if ( ! paused ) {
2024-04-08 11:10:30 +08:00
if ( PlumageRender : : Setter : : settings . rotateModel ) {
2023-06-06 15:52:39 +08:00
modelrot . y + = frameTimer * 35.0f ;
if ( modelrot . y > 360.0f ) {
modelrot . y - = 360.0f ;
}
}
if ( ( animate ) & & ( models . scene . animations . size ( ) > 0 ) ) {
animationTimer + = frameTimer ;
if ( animationTimer > models . scene . animations [ animationIndex ] . end ) {
animationTimer - = models . scene . animations [ animationIndex ] . end ;
}
models . scene . updateAnimation ( animationIndex , animationTimer ) ;
}
updateShaderData ( ) ;
2024-04-08 11:10:30 +08:00
if ( PlumageRender : : Setter : : settings . rotateModel ) {
2023-06-06 15:52:39 +08:00
updateUniformBuffers ( ) ;
}
}
2023-05-17 14:49:05 +08:00
if ( camera . updated ) {
updateUniformBuffers ( ) ;
}
2024-03-22 18:05:18 +08:00
2023-05-17 14:49:05 +08:00
}
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : fileDropped ( std : : string filename )
2023-06-07 16:16:53 +08:00
{
vkDeviceWaitIdle ( device ) ;
loadScene ( filename ) ;
setupDescriptors ( ) ;
buildCommandBuffers ( ) ;
2024-03-28 11:12:47 +08:00
2023-06-07 16:16:53 +08:00
}
2024-04-01 18:05:17 +08:00
// 重构到单独的UI里
2024-04-07 17:29:35 +08:00
void PlumageRender : : renderMain : : updateUIOverlay ( )
2023-05-17 14:49:05 +08:00
{
2023-06-17 01:18:15 +08:00
2023-06-07 00:45:10 +08:00
2023-05-17 14:49:05 +08:00
}
2023-05-25 16:27:50 +08:00
2024-04-02 12:08:46 +08:00
2023-06-07 16:16:53 +08:00
2024-04-01 18:05:17 +08:00
// 完全重写, 避免OS specific
2024-04-02 12:08:46 +08:00
/*
2024-04-01 18:05:17 +08:00
PlumageRender * plumageRender ;
2024-04-02 12:08:46 +08:00
2023-06-06 17:18:45 +08:00
# if defined(_WIN32)
LRESULT CALLBACK WndProc ( HWND hWnd , UINT uMsg , WPARAM wParam , LPARAM lParam )
{
if ( plumageRender ! = NULL )
{
plumageRender - > handleMessages ( hWnd , uMsg , wParam , lParam ) ;
}
return ( DefWindowProc ( hWnd , uMsg , wParam , lParam ) ) ;
}
int APIENTRY WinMain ( HINSTANCE hInstance , HINSTANCE , LPSTR , int )
{
2024-04-01 13:45:00 +08:00
VulkanBackend : : Setter setter ;
for ( int32_t i = 0 ; i < __argc ; i + + ) { setter . args . push_back ( __argv [ i ] ) ; } ;
2023-06-06 17:18:45 +08:00
plumageRender = new PlumageRender ( ) ;
2024-03-29 18:11:09 +08:00
2023-06-06 17:18:45 +08:00
plumageRender - > initVulkan ( ) ;
2024-04-08 11:10:30 +08:00
if ( ! plumageRender - > PlumageRender : : Setter : : settings . headless )
2024-03-29 18:11:09 +08:00
{
plumageRender - > setupWindow ( hInstance , WndProc ) ;
}
2023-06-06 17:18:45 +08:00
plumageRender - > prepare ( ) ;
plumageRender - > renderLoop ( ) ;
delete ( plumageRender ) ;
return 0 ;
}
# endif
2024-04-02 12:08:46 +08:00
*/
int main ( )
{
2024-04-07 17:29:35 +08:00
PlumageRender : : renderMain * plumageRender ;
PlumageRender : : Setter setter ;
2024-04-08 11:10:30 +08:00
if ( ! PlumageRender : : Setter : : settings . headless )
2024-04-02 12:08:46 +08:00
{
2024-04-08 11:10:30 +08:00
plumageRender - > initWindow ( PlumageRender : : Setter : : settings . width , PlumageRender : : renderMain : : settings . height ) ;
2024-04-07 17:29:35 +08:00
2024-04-02 12:08:46 +08:00
}
2024-04-07 17:29:35 +08:00
plumageRender - > initVulkan ( ) ;
2024-04-02 12:08:46 +08:00
return 0 ;
}