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
2023-06-06 17:18:45 +08:00
2023-06-07 00:45:10 +08:00
PlumageRender : : PlumageRender ( )
2023-05-17 14:49:05 +08:00
{
2023-06-05 16:40:39 +08:00
title = " plumage render " ;
2023-05-17 14:49:05 +08:00
}
2023-06-05 21:31:21 +08:00
void PlumageRender : : renderNode ( glTFModel : : Node * node , uint32_t cbIndex , glTFModel : : Material : : AlphaMode alphaMode ) {
if ( node - > mesh ) {
// Render mesh primitives
for ( glTFModel : : Primitive * primitive : node - > mesh - > primitives ) {
if ( primitive - > material . alphaMode = = alphaMode ) {
VkPipeline pipeline = VK_NULL_HANDLE ;
switch ( alphaMode ) {
case glTFModel : : Material : : ALPHAMODE_OPAQUE :
case glTFModel : : Material : : ALPHAMODE_MASK :
pipeline = primitive - > material . doubleSided ? pipelines . pbrDoubleSided : pipelines . pbr ;
break ;
case glTFModel : : Material : : ALPHAMODE_BLEND :
pipeline = pipelines . pbrAlphaBlend ;
break ;
}
if ( pipeline ! = boundPipeline ) {
vkCmdBindPipeline ( commandBuffers [ cbIndex ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
boundPipeline = pipeline ;
}
const std : : vector < VkDescriptorSet > descriptorsets = {
descriptorSets [ cbIndex ] . scene ,
primitive - > material . descriptorSet ,
node - > mesh - > uniformBuffer . descriptorSet ,
} ;
vkCmdBindDescriptorSets ( commandBuffers [ cbIndex ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , static_cast < uint32_t > ( descriptorsets . size ( ) ) , descriptorsets . data ( ) , 0 , NULL ) ;
// Pass material parameters as push constants
PushConstBlockMaterial pushConstBlockMaterial { } ;
pushConstBlockMaterial . emissiveFactor = primitive - > material . emissiveFactor ;
// To save push constant space, availabilty and texture coordiante set are combined
// -1 = texture not used for this material, >= 0 texture used and index of texture coordinate set
pushConstBlockMaterial . colorTextureSet = primitive - > material . baseColorTexture ! = nullptr ? primitive - > material . texCoordSets . baseColor : - 1 ;
pushConstBlockMaterial . normalTextureSet = primitive - > material . normalTexture ! = nullptr ? primitive - > material . texCoordSets . normal : - 1 ;
pushConstBlockMaterial . occlusionTextureSet = primitive - > material . occlusionTexture ! = nullptr ? primitive - > material . texCoordSets . occlusion : - 1 ;
pushConstBlockMaterial . emissiveTextureSet = primitive - > material . emissiveTexture ! = nullptr ? primitive - > material . texCoordSets . emissive : - 1 ;
2023-06-05 22:37:31 +08:00
pushConstBlockMaterial . alphaMask = static_cast < float > ( primitive - > material . alphaMode = = glTFModel : : Material : : ALPHAMODE_MASK ) ;
2023-06-05 21:31:21 +08:00
pushConstBlockMaterial . alphaMaskCutoff = primitive - > material . alphaCutoff ;
// TODO: glTF specs states that metallic roughness should be preferred, even if specular glosiness is present
if ( primitive - > material . pbrWorkflows . metallicRoughness ) {
// Metallic roughness workflow
pushConstBlockMaterial . workflow = static_cast < float > ( PBR_WORKFLOW_METALLIC_ROUGHNESS ) ;
pushConstBlockMaterial . baseColorFactor = primitive - > material . baseColorFactor ;
pushConstBlockMaterial . metallicFactor = primitive - > material . metallicFactor ;
pushConstBlockMaterial . roughnessFactor = primitive - > material . roughnessFactor ;
pushConstBlockMaterial . PhysicalDescriptorTextureSet = primitive - > material . metallicRoughnessTexture ! = nullptr ? primitive - > material . texCoordSets . metallicRoughness : - 1 ;
pushConstBlockMaterial . colorTextureSet = primitive - > material . baseColorTexture ! = nullptr ? primitive - > material . texCoordSets . baseColor : - 1 ;
}
if ( primitive - > material . pbrWorkflows . specularGlossiness ) {
// Specular glossiness workflow
pushConstBlockMaterial . workflow = static_cast < float > ( PBR_WORKFLOW_SPECULAR_GLOSINESS ) ;
pushConstBlockMaterial . PhysicalDescriptorTextureSet = primitive - > material . extension . specularGlossinessTexture ! = nullptr ? primitive - > material . texCoordSets . specularGlossiness : - 1 ;
pushConstBlockMaterial . colorTextureSet = primitive - > material . extension . diffuseTexture ! = nullptr ? primitive - > material . texCoordSets . baseColor : - 1 ;
pushConstBlockMaterial . diffuseFactor = primitive - > material . extension . diffuseFactor ;
pushConstBlockMaterial . specularFactor = glm : : vec4 ( primitive - > material . extension . specularFactor , 1.0f ) ;
}
vkCmdPushConstants ( commandBuffers [ cbIndex ] , pipelineLayout , VK_SHADER_STAGE_FRAGMENT_BIT , 0 , sizeof ( PushConstBlockMaterial ) , & pushConstBlockMaterial ) ;
if ( primitive - > hasIndices ) {
vkCmdDrawIndexed ( commandBuffers [ cbIndex ] , primitive - > indexCount , 1 , primitive - > firstIndex , 0 , 0 ) ;
}
else {
vkCmdDraw ( commandBuffers [ cbIndex ] , primitive - > vertexCount , 1 , 0 , 0 ) ;
}
}
}
} ;
for ( auto child : node - > children ) {
renderNode ( child , cbIndex , alphaMode ) ;
}
2023-06-05 22:37:31 +08:00
}
2023-05-17 14:49:05 +08:00
2023-06-02 09:56:49 +08:00
void PlumageRender : : 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 ] ;
if ( settings . multiSampling ) {
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 ;
renderPassBeginInfo . renderArea . extent . width = width ;
renderPassBeginInfo . renderArea . extent . height = height ;
2023-06-05 22:37:31 +08:00
renderPassBeginInfo . clearValueCount = 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 { } ;
viewport . width = ( float ) width ;
viewport . height = ( float ) height ;
viewport . minDepth = 0.0f ;
viewport . maxDepth = 1.0f ;
vkCmdSetViewport ( currentCB , 0 , 1 , & viewport ) ;
VkRect2D scissor { } ;
scissor . extent = { width , height } ;
vkCmdSetScissor ( currentCB , 0 , 1 , & scissor ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
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
2023-06-07 10:52:04 +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
2023-06-05 22:37:31 +08:00
void PlumageRender : : loadScene ( std : : string filename )
{
std : : cout < < " Loading scene from " < < filename < < std : : endl ;
models . scene . destroy ( device ) ;
animationIndex = 0 ;
animationTimer = 0.0f ;
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
models . scene . loadFromFile ( filename , vulkanDevice , queue ) ;
auto tFileLoad = std : : chrono : : duration < double , std : : milli > ( std : : chrono : : high_resolution_clock : : now ( ) - tStart ) . count ( ) ;
std : : cout < < " Loading took " < < tFileLoad < < " ms " < < std : : endl ;
2023-06-07 16:16:53 +08:00
camera . setPosition ( { 0.0f , 0.0f , - 1.0f } ) ;
2023-06-05 22:37:31 +08:00
camera . setRotation ( { 0.0f , 0.0f , 0.0f } ) ;
}
void PlumageRender : : loadEnvironment ( std : : string filename )
{
std : : cout < < " Loading environment from " < < filename < < std : : endl ;
if ( textures . environmentCube . image ) {
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
2023-06-02 09:56:49 +08:00
void PlumageRender : : 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
2023-06-07 10:52:04 +08:00
textures . empty . loadFromFile ( PlumageRender : : filePath . emptyEnvmapFilePath , VK_FORMAT_R8G8B8A8_UNORM , vulkanDevice , queue ) ;
2023-06-05 22:37:31 +08:00
2023-06-06 11:40:59 +08:00
std : : string sceneFile = filePath . glTFModelFilePath ;
std : : string envMapFile = filePath . envMapFilePath ;
2023-06-05 22:37:31 +08:00
for ( size_t i = 0 ; i < args . size ( ) ; i + + ) {
if ( ( std : : string ( args [ i ] ) . find ( " .gltf " ) ! = std : : string : : npos ) | | ( std : : string ( args [ i ] ) . find ( " .glb " ) ! = std : : string : : npos ) ) {
std : : ifstream file ( args [ i ] ) ;
if ( file . good ( ) ) {
sceneFile = args [ i ] ;
}
else {
std : : cout < < " could not load \" " < < args [ i ] < < " \" " < < std : : endl ;
}
}
if ( std : : string ( args [ i ] ) . find ( " .ktx " ) ! = std : : string : : npos ) {
std : : ifstream file ( args [ i ] ) ;
if ( file . good ( ) ) {
envMapFile = args [ i ] ;
}
else {
std : : cout < < " could not load \" " < < args [ i ] < < " \" " < < std : : endl ;
}
}
}
loadScene ( sceneFile . c_str ( ) ) ;
2023-06-07 10:52:04 +08:00
models . skybox . loadFromFile ( PlumageRender : : filePath . skyboxModleFilePath , vulkanDevice , queue ) ;
2023-06-05 22:37:31 +08:00
loadEnvironment ( envMapFile . c_str ( ) ) ;
2023-05-17 14:49:05 +08:00
}
2023-06-06 11:40:59 +08:00
void PlumageRender : : 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 )
*/
2023-06-06 11:40:59 +08:00
if ( node - > mesh ) {
VkDescriptorSetAllocateInfo descriptorSetAllocInfo { } ;
descriptorSetAllocInfo . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
descriptorSetAllocInfo . descriptorPool = descriptorPool ;
descriptorSetAllocInfo . pSetLayouts = & descriptorSetLayouts . node ;
descriptorSetAllocInfo . descriptorSetCount = 1 ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & descriptorSetAllocInfo , & node - > mesh - > uniformBuffer . descriptorSet ) ) ;
VkWriteDescriptorSet writeDescriptorSet { } ;
writeDescriptorSet . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSet . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
writeDescriptorSet . descriptorCount = 1 ;
writeDescriptorSet . dstSet = node - > mesh - > uniformBuffer . descriptorSet ;
writeDescriptorSet . dstBinding = 0 ;
writeDescriptorSet . pBufferInfo = & node - > mesh - > uniformBuffer . descriptor ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
2023-05-25 16:13:37 +08:00
}
2023-06-06 11:40:59 +08:00
for ( auto & child : node - > children ) {
setupNodeDescriptorSet ( child ) ;
}
}
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
void PlumageRender : : setupDescriptors ( )
{
/*
Descriptor Pool
*/
uint32_t imageSamplerCount = 0 ;
uint32_t materialCount = 0 ;
uint32_t meshCount = 0 ;
2024-03-26 18:04:18 +08:00
// Environment samplers (radiance, irradiance, brdflut)
2023-06-06 11:40:59 +08:00
imageSamplerCount + = 3 ;
std : : vector < glTFModel : : Model * > modellist = { & models . skybox , & models . scene } ;
for ( auto & model : modellist ) {
for ( auto & material : model - > materials ) {
imageSamplerCount + = 5 ;
materialCount + + ;
}
for ( auto node : model - > linearNodes ) {
if ( node - > mesh ) {
meshCount + + ;
}
}
}
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
std : : vector < VkDescriptorPoolSize > poolSizes = {
{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , ( 4 + meshCount ) * swapChain . imageCount } ,
{ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , imageSamplerCount * swapChain . imageCount }
2023-05-17 14:49:05 +08:00
} ;
2023-06-06 11:40:59 +08:00
VkDescriptorPoolCreateInfo descriptorPoolCI { } ;
descriptorPoolCI . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO ;
descriptorPoolCI . poolSizeCount = 2 ;
descriptorPoolCI . pPoolSizes = poolSizes . data ( ) ;
descriptorPoolCI . maxSets = ( 2 + materialCount + meshCount ) * swapChain . imageCount ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolCI , nullptr , & descriptorPool ) ) ;
2023-05-25 00:29:04 +08:00
2023-06-06 11:40:59 +08:00
/*
Descriptor sets
*/
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
// Scene (matrices and environment maps)
2023-05-24 11:12:54 +08:00
{
2023-06-06 11:40:59 +08:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
{ 0 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 , VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 1 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 2 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 3 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 4 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
2023-05-25 16:13:37 +08:00
} ;
2023-06-06 11:40:59 +08:00
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI { } ;
descriptorSetLayoutCI . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
descriptorSetLayoutCI . pBindings = setLayoutBindings . data ( ) ;
descriptorSetLayoutCI . bindingCount = static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . scene ) ) ;
for ( auto i = 0 ; i < descriptorSets . size ( ) ; i + + ) {
VkDescriptorSetAllocateInfo descriptorSetAllocInfo { } ;
descriptorSetAllocInfo . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
descriptorSetAllocInfo . descriptorPool = descriptorPool ;
descriptorSetAllocInfo . pSetLayouts = & descriptorSetLayouts . scene ;
descriptorSetAllocInfo . descriptorSetCount = 1 ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & descriptorSetAllocInfo , & descriptorSets [ i ] . scene ) ) ;
std : : array < VkWriteDescriptorSet , 5 > writeDescriptorSets { } ;
writeDescriptorSets [ 0 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
writeDescriptorSets [ 0 ] . descriptorCount = 1 ;
writeDescriptorSets [ 0 ] . dstSet = descriptorSets [ i ] . scene ;
writeDescriptorSets [ 0 ] . dstBinding = 0 ;
writeDescriptorSets [ 0 ] . pBufferInfo = & uniformBuffers [ i ] . scene . descriptor ;
writeDescriptorSets [ 1 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 1 ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
writeDescriptorSets [ 1 ] . descriptorCount = 1 ;
writeDescriptorSets [ 1 ] . dstSet = descriptorSets [ i ] . scene ;
writeDescriptorSets [ 1 ] . dstBinding = 1 ;
writeDescriptorSets [ 1 ] . pBufferInfo = & uniformBuffers [ i ] . params . descriptor ;
writeDescriptorSets [ 2 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 2 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
writeDescriptorSets [ 2 ] . descriptorCount = 1 ;
writeDescriptorSets [ 2 ] . dstSet = descriptorSets [ i ] . scene ;
writeDescriptorSets [ 2 ] . dstBinding = 2 ;
writeDescriptorSets [ 2 ] . pImageInfo = & textures . irradianceCube . descriptor ;
writeDescriptorSets [ 3 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 3 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
writeDescriptorSets [ 3 ] . descriptorCount = 1 ;
writeDescriptorSets [ 3 ] . dstSet = descriptorSets [ i ] . scene ;
writeDescriptorSets [ 3 ] . dstBinding = 3 ;
writeDescriptorSets [ 3 ] . pImageInfo = & textures . prefilteredCube . descriptor ;
writeDescriptorSets [ 4 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 4 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
writeDescriptorSets [ 4 ] . descriptorCount = 1 ;
writeDescriptorSets [ 4 ] . dstSet = descriptorSets [ i ] . scene ;
writeDescriptorSets [ 4 ] . dstBinding = 4 ;
writeDescriptorSets [ 4 ] . pImageInfo = & textures . lutBrdf . descriptor ;
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
}
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// Material (samplers)
{
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
{ 0 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 1 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 2 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 3 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
{ 4 , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , VK_SHADER_STAGE_FRAGMENT_BIT , nullptr } ,
2023-05-25 16:13:37 +08:00
} ;
2023-06-06 11:40:59 +08:00
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI { } ;
descriptorSetLayoutCI . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
descriptorSetLayoutCI . pBindings = setLayoutBindings . data ( ) ;
descriptorSetLayoutCI . bindingCount = static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . material ) ) ;
// Per-Material descriptor sets
for ( auto & material : models . scene . materials ) {
VkDescriptorSetAllocateInfo descriptorSetAllocInfo { } ;
descriptorSetAllocInfo . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
descriptorSetAllocInfo . descriptorPool = descriptorPool ;
descriptorSetAllocInfo . pSetLayouts = & descriptorSetLayouts . material ;
descriptorSetAllocInfo . descriptorSetCount = 1 ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & descriptorSetAllocInfo , & material . descriptorSet ) ) ;
std : : vector < VkDescriptorImageInfo > imageDescriptors = {
textures . empty . descriptor ,
textures . empty . descriptor ,
material . normalTexture ? material . normalTexture - > descriptor : textures . empty . descriptor ,
material . occlusionTexture ? material . occlusionTexture - > descriptor : textures . empty . descriptor ,
material . emissiveTexture ? material . emissiveTexture - > descriptor : textures . empty . descriptor
} ;
if ( material . pbrWorkflows . metallicRoughness ) {
if ( material . baseColorTexture ) {
imageDescriptors [ 0 ] = material . baseColorTexture - > descriptor ;
}
if ( material . metallicRoughnessTexture ) {
imageDescriptors [ 1 ] = material . metallicRoughnessTexture - > descriptor ;
}
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
if ( material . pbrWorkflows . specularGlossiness ) {
if ( material . extension . diffuseTexture ) {
imageDescriptors [ 0 ] = material . extension . diffuseTexture - > descriptor ;
}
if ( material . extension . specularGlossinessTexture ) {
imageDescriptors [ 1 ] = material . extension . specularGlossinessTexture - > descriptor ;
}
}
2023-05-24 11:12:54 +08:00
2023-06-06 11:40:59 +08:00
std : : array < VkWriteDescriptorSet , 5 > writeDescriptorSets { } ;
for ( size_t i = 0 ; i < imageDescriptors . size ( ) ; i + + ) {
writeDescriptorSets [ i ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ i ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
writeDescriptorSets [ i ] . descriptorCount = 1 ;
writeDescriptorSets [ i ] . dstSet = material . descriptorSet ;
writeDescriptorSets [ i ] . dstBinding = static_cast < uint32_t > ( i ) ;
writeDescriptorSets [ i ] . pImageInfo = & imageDescriptors [ i ] ;
}
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
2023-05-25 16:13:37 +08:00
}
2023-06-06 11:40:59 +08:00
// Model node (matrices)
2023-05-25 16:13:37 +08:00
{
2023-06-06 11:40:59 +08:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
{ 0 , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 , VK_SHADER_STAGE_VERTEX_BIT , nullptr } ,
} ;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI { } ;
descriptorSetLayoutCI . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO ;
descriptorSetLayoutCI . pBindings = setLayoutBindings . data ( ) ;
descriptorSetLayoutCI . bindingCount = static_cast < uint32_t > ( setLayoutBindings . size ( ) ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . node ) ) ;
// Per-Node descriptor set
for ( auto & node : models . scene . nodes ) {
setupNodeDescriptorSet ( node ) ;
}
2023-05-25 16:13:37 +08:00
}
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
}
2023-05-25 16:13:37 +08:00
2023-06-06 11:40:59 +08:00
// Skybox (fixed set)
for ( auto i = 0 ; i < uniformBuffers . size ( ) ; i + + ) {
VkDescriptorSetAllocateInfo descriptorSetAllocInfo { } ;
descriptorSetAllocInfo . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO ;
descriptorSetAllocInfo . descriptorPool = descriptorPool ;
descriptorSetAllocInfo . pSetLayouts = & descriptorSetLayouts . scene ;
descriptorSetAllocInfo . descriptorSetCount = 1 ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & descriptorSetAllocInfo , & descriptorSets [ i ] . skybox ) ) ;
std : : array < VkWriteDescriptorSet , 3 > writeDescriptorSets { } ;
writeDescriptorSets [ 0 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 0 ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
writeDescriptorSets [ 0 ] . descriptorCount = 1 ;
writeDescriptorSets [ 0 ] . dstSet = descriptorSets [ i ] . skybox ;
writeDescriptorSets [ 0 ] . dstBinding = 0 ;
writeDescriptorSets [ 0 ] . pBufferInfo = & uniformBuffers [ i ] . skybox . descriptor ;
writeDescriptorSets [ 1 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 1 ] . descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ;
writeDescriptorSets [ 1 ] . descriptorCount = 1 ;
writeDescriptorSets [ 1 ] . dstSet = descriptorSets [ i ] . skybox ;
writeDescriptorSets [ 1 ] . dstBinding = 1 ;
writeDescriptorSets [ 1 ] . pBufferInfo = & uniformBuffers [ i ] . params . descriptor ;
writeDescriptorSets [ 2 ] . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET ;
writeDescriptorSets [ 2 ] . descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ;
writeDescriptorSets [ 2 ] . descriptorCount = 1 ;
writeDescriptorSets [ 2 ] . dstSet = descriptorSets [ i ] . skybox ;
writeDescriptorSets [ 2 ] . dstBinding = 2 ;
writeDescriptorSets [ 2 ] . pImageInfo = & textures . prefilteredCube . descriptor ;
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , nullptr ) ;
2023-05-17 14:49:05 +08:00
}
}
2023-06-02 09:56:49 +08:00
void PlumageRender : : preparePipelines ( )
2023-05-17 14:49:05 +08:00
{
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_BACK_BIT ;
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 ;
if ( settings . multiSampling ) {
multisampleStateCI . rasterizationSamples = settings . sampleCount ;
}
std : : vector < VkDynamicState > dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT ,
VK_DYNAMIC_STATE_SCISSOR
2023-05-17 14:49:05 +08:00
} ;
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 ( ) ) ;
// Pipeline layout
const std : : vector < VkDescriptorSetLayout > setLayouts = {
descriptorSetLayouts . scene , descriptorSetLayouts . material , descriptorSetLayouts . node
2023-05-17 14:49:05 +08:00
} ;
2023-06-06 11:40:59 +08:00
VkPipelineLayoutCreateInfo pipelineLayoutCI { } ;
pipelineLayoutCI . sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO ;
pipelineLayoutCI . setLayoutCount = static_cast < uint32_t > ( setLayouts . size ( ) ) ;
pipelineLayoutCI . pSetLayouts = setLayouts . data ( ) ;
VkPushConstantRange pushConstantRange { } ;
pushConstantRange . size = sizeof ( PushConstBlockMaterial ) ;
pushConstantRange . stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT ;
pipelineLayoutCI . pushConstantRangeCount = 1 ;
pipelineLayoutCI . pPushConstantRanges = & pushConstantRange ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelineLayout ) ) ;
// Vertex bindings an attributes
VkVertexInputBindingDescription vertexInputBinding = { 0 , sizeof ( glTFModel : : Model : : Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX } ;
std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
{ 0 , 0 , VK_FORMAT_R32G32B32_SFLOAT , 0 } ,
{ 1 , 0 , VK_FORMAT_R32G32B32_SFLOAT , sizeof ( float ) * 3 } ,
{ 2 , 0 , VK_FORMAT_R32G32_SFLOAT , sizeof ( float ) * 6 } ,
{ 3 , 0 , VK_FORMAT_R32G32_SFLOAT , sizeof ( float ) * 8 } ,
{ 4 , 0 , VK_FORMAT_R32G32B32A32_SFLOAT , sizeof ( float ) * 10 } ,
{ 5 , 0 , VK_FORMAT_R32G32B32A32_SFLOAT , sizeof ( float ) * 14 } ,
{ 6 , 0 , VK_FORMAT_R32G32B32A32_SFLOAT , sizeof ( float ) * 18 }
} ;
VkPipelineVertexInputStateCreateInfo vertexInputStateCI { } ;
vertexInputStateCI . sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO ;
vertexInputStateCI . vertexBindingDescriptionCount = 1 ;
vertexInputStateCI . pVertexBindingDescriptions = & vertexInputBinding ;
2023-05-17 14:49:05 +08:00
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
2023-06-06 11:40:59 +08:00
// Pipelines
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2023-05-17 14:49:05 +08:00
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 ;
2023-05-17 14:49:05 +08:00
pipelineCI . pInputAssemblyState = & inputAssemblyStateCI ;
2023-06-06 11:40:59 +08:00
pipelineCI . pVertexInputState = & vertexInputStateCI ;
2023-05-17 14:49:05 +08:00
pipelineCI . pRasterizationState = & rasterizationStateCI ;
pipelineCI . pColorBlendState = & colorBlendStateCI ;
pipelineCI . pMultisampleState = & multisampleStateCI ;
pipelineCI . pViewportState = & viewportStateCI ;
pipelineCI . pDepthStencilState = & depthStencilStateCI ;
pipelineCI . pDynamicState = & dynamicStateCI ;
pipelineCI . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
pipelineCI . pStages = shaderStages . data ( ) ;
2024-03-26 14:59:37 +08:00
if ( settings . multiSampling ) {
multisampleStateCI . rasterizationSamples = settings . sampleCount ;
}
2023-05-17 14:49:05 +08:00
2023-06-06 11:40:59 +08:00
// Skybox pipeline (background cube)
shaderStages = {
2023-06-07 10:52:04 +08:00
loadShader ( device , PlumageRender : : filePath . skyboxVertShaderPath , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( device , PlumageRender : : filePath . skyboxFragShaderPath , VK_SHADER_STAGE_FRAGMENT_BIT )
2023-06-06 11:40:59 +08:00
} ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . skybox ) ) ;
for ( auto shaderStage : shaderStages ) {
vkDestroyShaderModule ( device , shaderStage . module , nullptr ) ;
}
// PBR pipeline
shaderStages = {
2023-06-07 10:52:04 +08:00
loadShader ( device , PlumageRender : : filePath . pbrVertShaderPath , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( device , PlumageRender : : filePath . pbrFragShaderPath , VK_SHADER_STAGE_FRAGMENT_BIT )
2023-06-06 11:40:59 +08:00
} ;
depthStencilStateCI . depthWriteEnable = VK_TRUE ;
depthStencilStateCI . depthTestEnable = VK_TRUE ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . pbr ) ) ;
rasterizationStateCI . cullMode = VK_CULL_MODE_NONE ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . pbrDoubleSided ) ) ;
rasterizationStateCI . cullMode = VK_CULL_MODE_NONE ;
blendAttachmentState . blendEnable = VK_TRUE ;
blendAttachmentState . colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT ;
blendAttachmentState . srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA ;
blendAttachmentState . dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ;
blendAttachmentState . colorBlendOp = VK_BLEND_OP_ADD ;
blendAttachmentState . srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ;
blendAttachmentState . dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO ;
blendAttachmentState . alphaBlendOp = VK_BLEND_OP_ADD ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . pbrAlphaBlend ) ) ;
for ( auto shaderStage : shaderStages ) {
vkDestroyShaderModule ( device , shaderStage . module , nullptr ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-25 11:38:10 +08:00
//Create Tone Mapping render pipeline
2023-06-06 11:40:59 +08:00
//CreateToneMappingPipeline();
2024-03-25 11:51:10 +08:00
2023-05-17 14:49:05 +08:00
}
2023-05-25 16:13:37 +08:00
2023-06-06 15:52:39 +08:00
// generate two cube maps
// irradiance cube map
// prefileter environment cube map
2023-06-06 11:40:59 +08:00
void PlumageRender : : 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 ;
2023-06-07 10:52:04 +08:00
shaderStages [ 0 ] = loadShader ( device , PlumageRender : : filePath . filterVertShaderPath , VK_SHADER_STAGE_VERTEX_BIT ) ;
2023-06-06 11:40:59 +08:00
switch ( target ) {
case IRRADIANCE :
2023-06-07 10:52:04 +08:00
shaderStages [ 1 ] = loadShader ( device , PlumageRender : : filePath . irradianceFragShaderPath , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2023-06-06 11:40:59 +08:00
break ;
case PREFILTEREDENV :
2023-06-07 10:52:04 +08:00
shaderStages [ 1 ] = loadShader ( device , PlumageRender : : 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
}
}
2023-06-06 15:52:39 +08:00
// generate BRDF integration map for roughness/NdotV
void PlumageRender : : 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 = {
2023-06-07 10:52:04 +08:00
loadShader ( device , PlumageRender : : filePath . brdfVertShaderPath , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( device , PlumageRender : : 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
2023-05-17 14:49:05 +08:00
// Prepare and initialize uniform buffer containing shader uniforms
2023-06-02 09:56:49 +08:00
void PlumageRender : : prepareUniformBuffers ( )
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +08:00
for ( auto & uniformBuffer : uniformBuffers ) {
uniformBuffer . scene . create ( vulkanDevice , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , sizeof ( shaderDataScene ) ) ;
uniformBuffer . skybox . create ( vulkanDevice , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , sizeof ( shaderDataSkybox ) ) ;
uniformBuffer . params . create ( vulkanDevice , VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT , sizeof ( shaderData ) ) ;
2023-05-25 16:13:37 +08:00
}
2023-05-17 14:49:05 +08:00
updateUniformBuffers ( ) ;
}
2023-06-02 09:56:49 +08:00
void PlumageRender : : updateUniformBuffers ( )
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +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 ) ) ;
}
void PlumageRender : : updateShaderData ( )
{
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 ) ;
}
void PlumageRender : : windowResized ( )
{
buildCommandBuffers ( ) ;
vkDeviceWaitIdle ( device ) ;
updateUniformBuffers ( ) ;
2023-06-07 10:52:04 +08:00
//update UI
updateUIOverlay ( ) ;
2023-05-17 14:49:05 +08:00
}
2023-06-02 09:56:49 +08:00
void PlumageRender : : prepare ( )
2023-05-17 14:49:05 +08:00
{
VulkanExampleBase : : prepare ( ) ;
2023-06-06 15:52:39 +08:00
camera . type = Camera : : CameraType : : lookat ;
camera . setPerspective ( 45.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
camera . rotationSpeed = 0.25f ;
camera . movementSpeed = 0.1f ;
2023-06-07 16:16:53 +08:00
camera . setPosition ( { 0.0f , 0.0f , - 1.0f } ) ;
2023-06-06 15:52:39 +08:00
camera . setRotation ( { 0.0f , 0.0f , 0.0f } ) ;
waitFences . resize ( renderAhead ) ;
presentCompleteSemaphores . resize ( renderAhead ) ;
renderCompleteSemaphores . resize ( renderAhead ) ;
commandBuffers . resize ( swapChain . imageCount ) ;
uniformBuffers . resize ( swapChain . imageCount ) ;
descriptorSets . resize ( swapChain . imageCount ) ;
// Command buffer execution fences
for ( auto & waitFence : waitFences ) {
VkFenceCreateInfo fenceCI { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO , nullptr , VK_FENCE_CREATE_SIGNALED_BIT } ;
VK_CHECK_RESULT ( vkCreateFence ( device , & fenceCI , nullptr , & waitFence ) ) ;
}
// Queue ordering semaphores
for ( auto & semaphore : presentCompleteSemaphores ) {
VkSemaphoreCreateInfo semaphoreCI { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO , nullptr , 0 } ;
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCI , nullptr , & semaphore ) ) ;
}
for ( auto & semaphore : renderCompleteSemaphores ) {
VkSemaphoreCreateInfo semaphoreCI { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO , nullptr , 0 } ;
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCI , nullptr , & semaphore ) ) ;
}
// Command buffers
{
VkCommandBufferAllocateInfo cmdBufAllocateInfo { } ;
cmdBufAllocateInfo . sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO ;
cmdBufAllocateInfo . commandPool = cmdPool ;
cmdBufAllocateInfo . level = VK_COMMAND_BUFFER_LEVEL_PRIMARY ;
cmdBufAllocateInfo . commandBufferCount = static_cast < uint32_t > ( commandBuffers . size ( ) ) ;
VK_CHECK_RESULT ( vkAllocateCommandBuffers ( device , & cmdBufAllocateInfo , commandBuffers . data ( ) ) ) ;
}
2023-05-17 14:49:05 +08:00
loadAssets ( ) ;
2023-06-06 15:52:39 +08:00
generateBRDFLUT ( ) ;
generateCubemaps ( ) ;
2023-05-17 14:49:05 +08:00
prepareUniformBuffers ( ) ;
setupDescriptors ( ) ;
preparePipelines ( ) ;
2023-06-06 15:52:39 +08:00
2023-06-07 10:52:04 +08:00
gui = new UI ( vulkanDevice , renderPass , queue , pipelineCache , settings . sampleCount ) ;
updateUIOverlay ( ) ;
2023-06-06 15:52:39 +08:00
2023-05-17 14:49:05 +08:00
buildCommandBuffers ( ) ;
2023-06-06 15:52:39 +08:00
2023-05-17 14:49:05 +08:00
prepared = true ;
}
2024-03-26 14:59:37 +08:00
void PlumageRender : : 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
}
// todo :根据physicalDeviceIndex确定子文件夹路径, frameIndex确定fileName
2024-03-25 11:51:10 +08:00
void PlumageRender : : 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 ] ;
// 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 = width ;
imageCreateCI . extent . height = 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 ( 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 ,
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 = width ;
blitSize . y = 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 = width ;
imageCopyRegion . extent . height = 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 ) ;
}
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 } ) ;
// 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 } ) ;
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-03-29 11:04:47 +08:00
if ( 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格式
stbi_write_png ( filePath . c_str ( ) , width , height , 4 , data , static_cast < int > ( subResourceLayout . rowPitch ) ) ;
2024-03-29 11:04:47 +08:00
}
else
{
stbi_write_png ( filePath . c_str ( ) , width , height , 4 , data , static_cast < int > ( subResourceLayout . rowPitch ) ) ;
}
}
else
{
std : : ofstream file ( filePath , std : : ios : : out | std : : ios : : binary ) ;
// ppm header
file < < " P6 \n " < < width < < " \n " < < height < < " \n " < < 255 < < " \n " ;
// ppm binary pixel data
for ( uint32_t y = 0 ; y < height ; y + + )
{
unsigned int * row = ( unsigned int * ) data ;
for ( uint32_t x = 0 ; x < 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-03-26 14:59:37 +08:00
void PlumageRender : : outputImageSequence ( )
2024-03-22 18:05:18 +08:00
{
2024-03-28 15:23:40 +08:00
// 比较已保存的帧数和设置里的开始帧数,在生成前清理上一次生成的图片序列
2024-03-28 11:12:47 +08:00
if ( savedFrameCounter = = settings . startFrameCount )
{
std : : cout < < " clean up directory for image sequence generation " < < std : : endl ;
removeImageSequence ( ) ;
}
2024-03-28 15:23:40 +08:00
// 根据显卡编号设置输出路径( todo: 提前到配置里)
2024-03-28 11:12:47 +08:00
filePath . deviceSpecFilePath = filePath . imageOutputPath + " /device " + std : : to_string ( selectedPhysicalDeviceIndex ) ;
2024-03-28 15:23:40 +08:00
// 非第一次生成,生成结束的边界条件
2024-03-27 17:29:32 +08:00
if ( savedFrameCounter > settings . outputFrameCount )
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-03-28 11:12:47 +08:00
filePath . totalImageOutputPath = 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
// 路径存在性检查,不存在则创建
if ( ! std : : filesystem : : exists ( filePath . deviceSpecFilePath . c_str ( ) ) )
2024-03-26 14:59:37 +08:00
{
2024-03-28 11:12:47 +08:00
std : : filesystem : : create_directories ( 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 " ;
filePath . totalImageOutputPath = 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-03-27 17:29:32 +08:00
writeImageToFile ( 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-03-27 17:29:32 +08:00
void PlumageRender : : imageSequenceToVideo ( )
{
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-03-27 17:29:32 +08:00
std : : string deviceFilePath = 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-03-27 17:29:32 +08:00
std : : string commandLineImageSequencePath = filePath . totalImageOutputPath ;
//std::string commandLineCodecAndResultPath = resultVideoPath;
std : : string commandLineFrameRate = std : : to_string ( settings . videoFrameRate ) ;
2024-03-28 15:23:40 +08:00
// 根据不同系统使用不同脚本
2024-03-27 17:29:32 +08:00
# if defined(_WIN32)
std : : string commandLine = 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 ( ) ) ;
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 ( ) ;
}
void PlumageRender : : removeImageSequence ( )
{
2024-03-28 15:23:40 +08:00
// 函数非第一次运行的边界条件
2024-03-28 11:12:47 +08:00
if ( savedFrameCounter ! = settings . startFrameCount )
{
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-03-28 11:12:47 +08:00
if ( std : : filesystem : : exists ( filePath . deviceSpecFilePath ) )
{
for ( const auto & entry : std : : filesystem : : directory_iterator ( filePath . deviceSpecFilePath ) )
{
if ( std : : filesystem : : is_directory ( entry . path ( ) ) )
{
std : : filesystem : : remove_all ( entry . path ( ) ) ;
}
else
{
std : : filesystem : : remove ( entry . path ( ) ) ;
}
}
std : : filesystem : : remove ( filePath . deviceSpecFilePath ) ;
std : : cout < < " clean up complete " < < std : : endl ;
}
return ;
2024-03-27 17:29:32 +08:00
}
2024-03-26 14:59:37 +08:00
uint32_t PlumageRender : : getMemoryTypeIndex ( uint32_t typeBits , VkMemoryPropertyFlags properties )
2024-03-22 18:05:18 +08:00
{
2024-03-26 14:59:37 +08:00
VkPhysicalDeviceMemoryProperties deviceMemoryProperties ;
vkGetPhysicalDeviceMemoryProperties ( physicalDevice , & deviceMemoryProperties ) ;
for ( uint32_t i = 0 ; i < deviceMemoryProperties . memoryTypeCount ; i + + )
{
if ( ( typeBits & 1 ) = = 1 )
{
if ( ( deviceMemoryProperties . memoryTypes [ i ] . propertyFlags & properties ) = = properties )
{
return i ;
}
}
typeBits > > = 1 ;
2024-03-22 18:05:18 +08:00
}
2024-03-26 14:59:37 +08:00
return 0 ;
2024-03-22 18:05:18 +08:00
}
2023-06-02 09:56:49 +08:00
void PlumageRender : : render ( )
2023-05-17 14:49:05 +08:00
{
2023-06-06 15:52:39 +08:00
if ( ! prepared ) {
return ;
}
2023-06-07 10:52:04 +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 14:59:37 +08:00
VK_CHECK_RESULT ( vkWaitForFences ( device , 1 , & waitFences [ frameIndex ] , VK_TRUE , UINT64_MAX ) ) ;
2024-03-26 18:04:18 +08:00
outputImageSequence ( ) ;
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
}
// Update UBOs
updateUniformBuffers ( ) ;
UniformBufferSet currentUB = uniformBuffers [ currentBuffer ] ;
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
//显示队列
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-03-22 18:05:18 +08:00
if ( 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-03-22 18:05:18 +08:00
if ( 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
}
2023-06-07 16:16:53 +08:00
void PlumageRender : : fileDropped ( std : : string filename )
{
vkDeviceWaitIdle ( device ) ;
loadScene ( filename ) ;
setupDescriptors ( ) ;
buildCommandBuffers ( ) ;
2024-03-28 11:12:47 +08:00
2023-06-07 16:16:53 +08:00
}
2023-05-17 14:49:05 +08:00
2023-06-07 00:45:10 +08:00
void PlumageRender : : updateUIOverlay ( )
2023-05-17 14:49:05 +08:00
{
2023-06-07 00:45:10 +08:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
ImVec2 lastDisplaySize = io . DisplaySize ;
io . DisplaySize = ImVec2 ( ( float ) width , ( float ) height ) ;
io . DeltaTime = frameTimer ;
io . MousePos = ImVec2 ( mousePos . x , mousePos . y ) ;
io . MouseDown [ 0 ] = mouseButtons . left ;
io . MouseDown [ 1 ] = mouseButtons . right ;
gui - > pushConstBlock . scale = glm : : vec2 ( 2.0f / io . DisplaySize . x , 2.0f / io . DisplaySize . y ) ;
gui - > pushConstBlock . translate = glm : : vec2 ( - 1.0f ) ;
bool updateShaderParams = false ;
bool updateCBs = false ;
float scale = 1.0f ;
2023-06-17 01:18:15 +08:00
bool boolTitleWindowShow = false ;
2023-06-07 00:45:10 +08:00
ImGui : : NewFrame ( ) ;
2023-06-17 01:18:15 +08:00
ImGui : : SetNextWindowPos ( ImVec2 ( 10000 , 10000 ) ) ;
//ImGui::SetNextWindowSize(ImVec2(200 * scale, (models.scene.animations.size() > 0 ? 440 : 360) * scale), ImGuiSetCond_Always);
ImGui : : Begin ( " " , nullptr , ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoBringToFrontOnFocus ) ;
2023-06-07 00:45:10 +08:00
ImGui : : PushItemWidth ( 100.0f * scale ) ;
2023-06-07 10:52:04 +08:00
2023-06-17 01:18:15 +08:00
2023-06-13 14:50:25 +08:00
2023-06-17 01:18:15 +08:00
if ( gui - > beginMainMenuBar ( ) ) {
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuFile ) )
2023-06-17 01:18:15 +08:00
{
2023-06-19 09:47:00 +08:00
if ( gui - > menuItem ( chineseUI . menuOpenNewModel ) )
2023-06-17 01:18:15 +08:00
{
std : : wstring filename = L " " ;
wchar_t buffer [ MAX_PATH ] ;
OPENFILENAMEW ofn ;
ZeroMemory ( & buffer , sizeof ( buffer ) ) ;
ZeroMemory ( & ofn , sizeof ( ofn ) ) ;
ofn . lStructSize = sizeof ( ofn ) ;
ofn . lpstrFilter = L " glTF files \0 *.gltf;*.glb \0 " ;
ofn . lpstrFile = buffer ;
ofn . nMaxFile = MAX_PATH ;
ofn . lpstrTitle = L " Select a glTF file to load " ;
ofn . Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR ;
if ( GetOpenFileNameW ( & ofn ) ) {
filename = buffer ;
2023-06-07 00:45:10 +08:00
2023-06-17 01:18:15 +08:00
}
if ( ! filename . empty ( ) ) {
vkDeviceWaitIdle ( device ) ;
std : : wstring_convert < std : : codecvt_utf8 < wchar_t > > converter ;
std : : string stringFilename = converter . to_bytes ( filename ) ;
loadScene ( stringFilename ) ;
setupDescriptors ( ) ;
updateCBs = true ;
2024-03-28 11:12:47 +08:00
signal . imageSequenceOutputComplete = false ;
signal . imageSequenceToVideoComplete = false ;
savedFrameCounter = 1 ;
2023-06-17 01:18:15 +08:00
}
}
gui - > endMenu ( ) ;
2023-06-07 00:45:10 +08:00
}
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuEnvironment ) )
2023-06-17 01:18:15 +08:00
{
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuEnvironmentConfig ) )
2023-06-17 01:18:15 +08:00
{
if ( gui - > combo ( chineseUI . environmentMap , selectedEnvironment , environments ) ) {
vkDeviceWaitIdle ( device ) ;
loadEnvironment ( environments [ selectedEnvironment ] ) ;
setupDescriptors ( ) ;
updateCBs = true ;
}
2023-06-19 09:47:00 +08:00
if ( gui - > checkbox ( chineseUI . environmentBackGround , & displayBackground ) ) {
2023-06-17 01:18:15 +08:00
updateShaderParams = true ;
}
if ( gui - > slider ( " Exposure " , & shaderData . exposure , 0.1f , 10.0f ) ) {
updateShaderParams = true ;
}
if ( gui - > slider ( " Gamma " , & shaderData . gamma , 0.1f , 4.0f ) ) {
updateShaderParams = true ;
}
if ( gui - > slider ( " IBL " , & shaderData . scaleIBLAmbient , 0.0f , 1.0f ) ) {
updateShaderParams = true ;
}
gui - > endMenu ( ) ;
}
gui - > endMenu ( ) ;
2023-05-25 16:13:37 +08:00
}
2023-06-17 01:18:15 +08:00
if ( gui - > beginMenu ( " debug " ) )
{
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuDebugInput ) )
2023-06-17 01:18:15 +08:00
{
const std : : vector < std : : string > debugNamesInputs = {
2023-06-07 00:45:10 +08:00
" none " , " Base color " , " Normal " , " Occlusion " , " Emissive " , " Metallic " , " Roughness "
2023-06-17 01:18:15 +08:00
} ;
if ( gui - > combo ( chineseUI . debugInput , & debugViewInputs , debugNamesInputs ) ) {
shaderData . debugViewInputs = static_cast < float > ( debugViewInputs ) ;
updateShaderParams = true ;
}
gui - > endMenu ( ) ;
}
if ( gui - > beginMenu ( " PBR " ) )
{
const std : : vector < std : : string > debugNamesEquation = {
2023-06-07 00:45:10 +08:00
" none " , " Diff (l,n) " , " F (l,h) " , " G (l,v,h) " , " D (h) " , " Specular "
2023-06-17 01:18:15 +08:00
} ;
if ( gui - > combo ( chineseUI . debugPBREquation , & debugViewEquation , debugNamesEquation ) ) {
shaderData . debugViewEquation = static_cast < float > ( debugViewEquation ) ;
updateShaderParams = true ;
}
gui - > endMenu ( ) ;
}
2023-06-19 10:09:08 +08:00
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuDebugFrameRate ) )
2023-06-17 01:18:15 +08:00
{
gui - > text ( " %.1d fps (%.2f ms) " , lastFPS , ( 1000.0f / lastFPS ) ) ;
gui - > endMenu ( ) ;
}
gui - > endMenu ( ) ;
2023-06-07 00:45:10 +08:00
}
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuAnimation ) )
2023-06-17 01:18:15 +08:00
{
if ( models . scene . animations . size ( ) > 0 )
{
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuAnimationActivation ) )
2023-06-17 01:18:15 +08:00
{
gui - > checkbox ( chineseUI . pauseAnimation , & animate ) ;
gui - > endMenu ( ) ;
}
2023-06-19 09:47:00 +08:00
if ( gui - > beginMenu ( chineseUI . menuAnimationAnimationSequence ) )
2023-06-17 01:18:15 +08:00
{
std : : vector < std : : string > animationNames ;
for ( auto animation : models . scene . animations ) {
animationNames . push_back ( animation . name ) ;
}
gui - > combo ( chineseUI . animationSeq , & animationIndex , animationNames ) ;
gui - > endMenu ( ) ;
}
2023-06-07 00:45:10 +08:00
}
2023-06-17 01:18:15 +08:00
else
{
2023-06-19 09:47:00 +08:00
gui - > text ( chineseUI . menuAnimationNoAnimation ) ;
2023-06-17 01:18:15 +08:00
}
gui - > endMenu ( ) ;
2023-06-01 16:41:14 +08:00
}
2023-06-19 10:09:08 +08:00
2023-06-17 01:18:15 +08:00
gui - > endMainMenuBar ( ) ;
2023-06-07 00:45:10 +08:00
}
2023-06-17 01:18:15 +08:00
2023-06-07 00:45:10 +08:00
ImGui : : PopItemWidth ( ) ;
ImGui : : End ( ) ;
ImGui : : Render ( ) ;
ImDrawData * imDrawData = ImGui : : GetDrawData ( ) ;
// Check if ui buffers need to be recreated
if ( imDrawData ) {
VkDeviceSize vertexBufferSize = imDrawData - > TotalVtxCount * sizeof ( ImDrawVert ) ;
VkDeviceSize indexBufferSize = imDrawData - > TotalIdxCount * sizeof ( ImDrawIdx ) ;
bool updateBuffers = ( gui - > vertexBuffer . buffer = = VK_NULL_HANDLE ) | | ( gui - > vertexBuffer . count ! = imDrawData - > TotalVtxCount ) | | ( gui - > indexBuffer . buffer = = VK_NULL_HANDLE ) | | ( gui - > indexBuffer . count ! = imDrawData - > TotalIdxCount ) ;
if ( updateBuffers ) {
vkDeviceWaitIdle ( device ) ;
if ( gui - > vertexBuffer . buffer ) {
gui - > vertexBuffer . destroy ( ) ;
}
gui - > vertexBuffer . create ( vulkanDevice , VK_BUFFER_USAGE_VERTEX_BUFFER_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT , vertexBufferSize ) ;
gui - > vertexBuffer . count = imDrawData - > TotalVtxCount ;
if ( gui - > indexBuffer . buffer ) {
gui - > indexBuffer . destroy ( ) ;
}
gui - > indexBuffer . create ( vulkanDevice , VK_BUFFER_USAGE_INDEX_BUFFER_BIT , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT , indexBufferSize ) ;
gui - > indexBuffer . count = imDrawData - > TotalIdxCount ;
2023-06-02 16:40:03 +08:00
}
2023-06-01 16:41:14 +08:00
2023-06-07 00:45:10 +08:00
// Upload data
ImDrawVert * vtxDst = ( ImDrawVert * ) gui - > vertexBuffer . mapped ;
ImDrawIdx * idxDst = ( ImDrawIdx * ) gui - > indexBuffer . mapped ;
for ( int n = 0 ; n < imDrawData - > CmdListsCount ; n + + ) {
const ImDrawList * cmd_list = imDrawData - > CmdLists [ n ] ;
memcpy ( vtxDst , cmd_list - > VtxBuffer . Data , cmd_list - > VtxBuffer . Size * sizeof ( ImDrawVert ) ) ;
memcpy ( idxDst , cmd_list - > IdxBuffer . Data , cmd_list - > IdxBuffer . Size * sizeof ( ImDrawIdx ) ) ;
vtxDst + = cmd_list - > VtxBuffer . Size ;
idxDst + = cmd_list - > IdxBuffer . Size ;
2023-06-01 00:05:36 +08:00
}
2023-06-07 00:45:10 +08:00
gui - > vertexBuffer . flush ( ) ;
gui - > indexBuffer . flush ( ) ;
updateCBs = updateCBs | | updateBuffers ;
}
if ( lastDisplaySize . x ! = io . DisplaySize . x | | lastDisplaySize . y ! = io . DisplaySize . y ) {
updateCBs = true ;
}
if ( updateCBs ) {
vkDeviceWaitIdle ( device ) ;
buildCommandBuffers ( ) ;
vkDeviceWaitIdle ( device ) ;
2023-06-01 00:05:36 +08:00
}
2023-06-07 00:45:10 +08:00
if ( updateShaderParams ) {
updateShaderData ( ) ;
}
2023-05-17 14:49:05 +08:00
}
2023-05-25 16:27:50 +08:00
2023-06-07 16:16:53 +08:00
2023-06-06 17:18:45 +08:00
PlumageRender * plumageRender ;
// OS specific macros for the example main entry points
# 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 )
{
for ( int32_t i = 0 ; i < __argc ; i + + ) { PlumageRender : : args . push_back ( __argv [ i ] ) ; } ;
plumageRender = new PlumageRender ( ) ;
plumageRender - > initVulkan ( ) ;
plumageRender - > setupWindow ( hInstance , WndProc ) ;
plumageRender - > prepare ( ) ;
plumageRender - > renderLoop ( ) ;
delete ( plumageRender ) ;
return 0 ;
}
# endif