2023-05-17 14:49:05 +08:00
/*
* Vulkan Example - glTF scene loading and rendering
*
* Copyright ( C ) 2020 - 2022 by Sascha Willems - www . saschawillems . de
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
/*
* Shows how to load and display a simple scene from a glTF file
* Note that this isn ' t a complete glTF loader and only basic functions are shown here
* This means no complex materials , no animations , no skins , etc .
* For details on how glTF 2.0 works , see the official spec at https : //github.com/KhronosGroup/glTF/tree/master/specification/2.0
*
* Other samples will load models using a dedicated model loader with more features ( see base / VulkanglTFModel . hpp )
*
* If you are looking for a complete glTF implementation , check out https : //github.com/SaschaWillems/Vulkan-glTF-PBR/
*/
# include "homework1.h"
/*
glTF loading functions
The following functions take a glTF input model loaded via tinyglTF and convert all required data into our own structure
*/
void VulkanglTFModel : : loadImages ( tinygltf : : Model & input )
{
images . resize ( input . images . size ( ) ) ;
for ( size_t i = 0 ; i < input . images . size ( ) ; i + + ) {
tinygltf : : Image & glTFImage = input . images [ i ] ;
// Get the image data from the glTF loader
unsigned char * buffer = nullptr ;
VkDeviceSize bufferSize = 0 ;
bool deleteBuffer = false ;
// We convert RGB-only images to RGBA, as most devices don't support RGB-formats in Vulkan
if ( glTFImage . component = = 3 ) {
bufferSize = glTFImage . width * glTFImage . height * 4 ;
buffer = new unsigned char [ bufferSize ] ;
unsigned char * rgba = buffer ;
unsigned char * rgb = & glTFImage . image [ 0 ] ;
for ( size_t i = 0 ; i < glTFImage . width * glTFImage . height ; + + i ) {
memcpy ( rgba , rgb , sizeof ( unsigned char ) * 3 ) ;
rgba + = 4 ;
rgb + = 3 ;
}
deleteBuffer = true ;
}
else {
buffer = & glTFImage . image [ 0 ] ;
bufferSize = glTFImage . image . size ( ) ;
}
// Load texture from image buffer
images [ i ] . texture . fromBuffer ( buffer , bufferSize , VK_FORMAT_R8G8B8A8_UNORM , glTFImage . width , glTFImage . height , vulkanDevice , copyQueue ) ;
if ( deleteBuffer ) {
delete [ ] buffer ;
}
}
}
void VulkanglTFModel : : loadTextures ( tinygltf : : Model & input )
{
textures . resize ( input . textures . size ( ) ) ;
for ( size_t i = 0 ; i < input . textures . size ( ) ; i + + ) {
textures [ i ] . imageIndex = input . textures [ i ] . source ;
}
}
void VulkanglTFModel : : loadMaterials ( tinygltf : : Model & input )
{
materials . resize ( input . materials . size ( ) ) ;
for ( size_t i = 0 ; i < input . materials . size ( ) ; i + + ) {
// We only read the most basic properties required for our sample
tinygltf : : Material glTFMaterial = input . materials [ i ] ;
// Get the base color factor
if ( glTFMaterial . values . find ( " baseColorFactor " ) ! = glTFMaterial . values . end ( ) ) {
materials [ i ] . baseColorFactor = glm : : make_vec4 ( glTFMaterial . values [ " baseColorFactor " ] . ColorFactor ( ) . data ( ) ) ;
}
// Get base color texture index
if ( glTFMaterial . values . find ( " baseColorTexture " ) ! = glTFMaterial . values . end ( ) ) {
materials [ i ] . baseColorTextureIndex = glTFMaterial . values [ " baseColorTexture " ] . TextureIndex ( ) ;
}
2023-05-22 22:52:27 +08:00
if ( glTFMaterial . values . find ( " metallicRoughnessTexture " ) ! = glTFMaterial . values . end ( ) ) {
materials [ i ] . matalicRoughTextureIndex = glTFMaterial . values [ " metallicRoughnessTexture " ] . TextureIndex ( ) ;
}
if ( glTFMaterial . additionalValues . find ( " normalTexture " ) ! = glTFMaterial . additionalValues . end ( ) )
{
materials [ i ] . normalMapTextureIndex = glTFMaterial . additionalValues [ " normalTexture " ] . TextureIndex ( ) ;
}
if ( glTFMaterial . emissiveTexture . index ! = - 1 )
{
materials [ i ] . emissiveTextureIndex = glTFMaterial . emissiveTexture . index ;
}
if ( glTFMaterial . emissiveFactor . size ( ) = = 3 )
{
materials [ i ] . materialData . values . emissiveFactor = glm : : make_vec3 ( glTFMaterial . emissiveFactor . data ( ) ) ;
}
if ( glTFMaterial . values . find ( " baseColorFactor " ) ! = glTFMaterial . values . end ( ) )
{
materials [ i ] . materialData . values . baseColorFactor = glm : : make_vec4 ( glTFMaterial . values [ " baseColorFactor " ] . ColorFactor ( ) . data ( ) ) ;
}
2023-05-17 14:49:05 +08:00
}
}
2023-05-18 11:49:09 +08:00
2023-05-17 14:49:05 +08:00
//animation loader
void VulkanglTFModel : : loadAnimations ( tinygltf : : Model & input )
{
animations . resize ( input . animations . size ( ) ) ;
for ( size_t i = 0 ; i < input . animations . size ( ) ; i + + )
{
tinygltf : : Animation glTFAnimation = input . animations [ i ] ;
animations [ i ] . name = glTFAnimation . name ;
2023-05-17 16:50:09 +08:00
// Samplers
2023-05-17 14:49:05 +08:00
animations [ i ] . samplers . resize ( glTFAnimation . samplers . size ( ) ) ;
for ( size_t j = 0 ; j < glTFAnimation . samplers . size ( ) ; j + + )
{
tinygltf : : AnimationSampler glTFSampler = glTFAnimation . samplers [ j ] ;
AnimationSampler & dstSampler = animations [ i ] . samplers [ j ] ;
dstSampler . interpolation = glTFSampler . interpolation ;
2023-05-17 16:50:09 +08:00
// Read sampler keyframe input time values
2023-05-17 14:49:05 +08:00
{
const tinygltf : : Accessor & accessor = input . accessors [ glTFSampler . input ] ;
const tinygltf : : BufferView & bufferView = input . bufferViews [ accessor . bufferView ] ;
const tinygltf : : Buffer & buffer = input . buffers [ bufferView . buffer ] ;
2023-05-17 16:50:09 +08:00
const void * dataPtr = & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] ;
const float * buf = static_cast < const float * > ( dataPtr ) ;
2023-05-17 14:49:05 +08:00
for ( size_t index = 0 ; index < accessor . count ; index + + )
{
dstSampler . inputs . push_back ( buf [ index ] ) ;
}
2023-05-17 16:50:09 +08:00
// Adjust animation's start and end times
2023-05-17 14:49:05 +08:00
for ( auto input : animations [ i ] . samplers [ j ] . inputs )
{
if ( input < animations [ i ] . start )
{
animations [ i ] . start = input ;
} ;
if ( input > animations [ i ] . end )
{
animations [ i ] . end = input ;
}
}
}
2023-05-17 16:50:09 +08:00
// Read sampler keyframe output translate/rotate/scale values
2023-05-17 14:49:05 +08:00
{
2023-05-17 16:50:09 +08:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFSampler . output ] ;
2023-05-17 14:49:05 +08:00
const tinygltf : : BufferView & bufferView = input . bufferViews [ accessor . bufferView ] ;
const tinygltf : : Buffer & buffer = input . buffers [ bufferView . buffer ] ;
2023-05-17 16:50:09 +08:00
const void * dataPtr = & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] ;
2023-05-17 14:49:05 +08:00
switch ( accessor . type )
{
2023-05-17 16:50:09 +08:00
case TINYGLTF_TYPE_VEC3 : {
const glm : : vec3 * buf = static_cast < const glm : : vec3 * > ( dataPtr ) ;
2023-05-17 14:49:05 +08:00
for ( size_t index = 0 ; index < accessor . count ; index + + )
{
dstSampler . outputsVec4 . push_back ( glm : : vec4 ( buf [ index ] , 0.0f ) ) ;
}
break ;
}
2023-05-17 16:50:09 +08:00
case TINYGLTF_TYPE_VEC4 : {
const glm : : vec4 * buf = static_cast < const glm : : vec4 * > ( dataPtr ) ;
2023-05-17 14:49:05 +08:00
for ( size_t index = 0 ; index < accessor . count ; index + + )
{
dstSampler . outputsVec4 . push_back ( buf [ index ] ) ;
}
break ;
}
2023-05-17 16:50:09 +08:00
default : {
std : : cout < < " unknown type " < < std : : endl ;
break ;
2023-05-17 14:49:05 +08:00
}
}
}
}
2023-05-17 16:50:09 +08:00
// Channels
2023-05-17 14:49:05 +08:00
animations [ i ] . channels . resize ( glTFAnimation . channels . size ( ) ) ;
for ( size_t j = 0 ; j < glTFAnimation . channels . size ( ) ; j + + )
{
tinygltf : : AnimationChannel glTFChannel = glTFAnimation . channels [ j ] ;
AnimationChannel & dstChannel = animations [ i ] . channels [ j ] ;
dstChannel . path = glTFChannel . target_path ;
dstChannel . samplerIndex = glTFChannel . sampler ;
dstChannel . node = nodeFromIndex ( glTFChannel . target_node ) ;
}
}
}
2023-05-25 00:29:04 +08:00
/*
2023-05-18 11:49:09 +08:00
// load skins from glTF model
void VulkanglTFModel : : loadSkins ( tinygltf : : Model & input )
{
skins . resize ( input . skins . size ( ) ) ;
2023-05-22 11:21:13 +08:00
if ( skins . size ( ) > 0 )
2023-05-18 11:49:09 +08:00
{
2023-05-22 11:21:13 +08:00
for ( size_t i = 0 ; i < input . skins . size ( ) ; i + + )
{
tinygltf : : Skin glTFSkin = input . skins [ i ] ;
2023-05-18 11:49:09 +08:00
2023-05-22 11:21:13 +08:00
skins [ i ] . name = glTFSkin . name ;
//follow the tree structure,find the root node of skeleton by index
skins [ i ] . skeletonRoot = nodeFromIndex ( glTFSkin . skeleton ) ;
2023-05-18 11:49:09 +08:00
2023-05-22 11:21:13 +08:00
//join nodes
for ( int jointIndex : glTFSkin . joints )
{
Node * node = nodeFromIndex ( jointIndex ) ;
if ( node )
{
skins [ i ] . joints . push_back ( node ) ;
}
}
//get the inverse bind matrices
if ( glTFSkin . inverseBindMatrices > - 1 )
{
const tinygltf : : Accessor & accessor = input . accessors [ glTFSkin . inverseBindMatrices ] ;
const tinygltf : : BufferView & bufferview = input . bufferViews [ accessor . bufferView ] ;
const tinygltf : : Buffer & buffer = input . buffers [ bufferview . buffer ] ;
skins [ i ] . inverseBindMatrices . resize ( accessor . count ) ;
memcpy ( skins [ i ] . inverseBindMatrices . data ( ) , & buffer . data [ accessor . byteOffset + bufferview . byteOffset ] , accessor . count * sizeof ( glm : : mat4 ) ) ;
//create a host visible shader buffer to store inverse bind matrices for this skin
VK_CHECK_RESULT (
vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& skins [ i ] . ssbo ,
sizeof ( glm : : mat4 ) * skins [ i ] . inverseBindMatrices . size ( ) ,
skins [ i ] . inverseBindMatrices . data ( ) ) ) ;
VK_CHECK_RESULT ( skins [ i ] . ssbo . map ( ) ) ;
}
2023-05-18 11:49:09 +08:00
}
2023-05-22 11:21:13 +08:00
2023-05-18 11:49:09 +08:00
}
2023-05-22 11:21:13 +08:00
2023-05-18 11:49:09 +08:00
2023-05-25 00:29:04 +08:00
} */
2023-05-18 11:49:09 +08:00
//glTF nodes loading helper function
//rewrite node loader,simplify logic
//Search node from parent to children by index
VulkanglTFModel : : Node * VulkanglTFModel : : findNode ( Node * parent , uint32_t index )
{
Node * nodeFound = nullptr ;
if ( parent - > index = = index )
{
return parent ;
}
for ( auto & child : parent - > children )
{
nodeFound = findNode ( child , index ) ;
if ( nodeFound )
{
break ;
}
}
return nodeFound ;
} //iterate vector of nodes to check weather nodes exist or not
VulkanglTFModel : : Node * VulkanglTFModel : : nodeFromIndex ( uint32_t index )
{
Node * nodeFound = nullptr ;
for ( auto & node : nodes )
{
nodeFound = findNode ( node , index ) ;
if ( nodeFound )
{
break ;
}
}
return nodeFound ;
}
2023-05-17 14:49:05 +08:00
//node loader
void VulkanglTFModel : : loadNode ( const tinygltf : : Node & inputNode , const tinygltf : : Model & input , VulkanglTFModel : : Node * parent , uint32_t nodeIndex , std : : vector < uint32_t > & indexBuffer , std : : vector < VulkanglTFModel : : Vertex > & vertexBuffer )
{
VulkanglTFModel : : Node * node = new VulkanglTFModel : : Node { } ;
node - > matrix = glm : : mat4 ( 1.0f ) ;
2023-05-25 11:38:10 +08:00
node - > parent = parent ;
2023-05-17 14:49:05 +08:00
node - > index = nodeIndex ;
2023-05-25 11:38:10 +08:00
// Get the local node matrix
// It's either made up from translation, rotation, scale or a 4x4 matrix
if ( inputNode . translation . size ( ) = = 3 ) {
node - > matrix = glm : : translate ( node - > matrix , glm : : vec3 ( glm : : make_vec3 ( inputNode . translation . data ( ) ) ) ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-25 11:38:10 +08:00
if ( inputNode . rotation . size ( ) = = 4 ) {
2023-05-17 14:49:05 +08:00
glm : : quat q = glm : : make_quat ( inputNode . rotation . data ( ) ) ;
2023-05-25 11:38:10 +08:00
node - > matrix * = glm : : mat4 ( q ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-25 11:38:10 +08:00
if ( inputNode . scale . size ( ) = = 3 ) {
node - > matrix = glm : : scale ( node - > matrix , glm : : vec3 ( glm : : make_vec3 ( inputNode . scale . data ( ) ) ) ) ;
2023-05-22 22:52:27 +08:00
}
2023-05-25 11:38:10 +08:00
if ( inputNode . matrix . size ( ) = = 16 ) {
2023-05-17 14:49:05 +08:00
node - > matrix = glm : : make_mat4x4 ( inputNode . matrix . data ( ) ) ;
2023-05-25 11:38:10 +08:00
} ;
2023-05-17 14:49:05 +08:00
2023-05-25 11:38:10 +08:00
// Load node's children
if ( inputNode . children . size ( ) > 0 ) {
for ( size_t i = 0 ; i < inputNode . children . size ( ) ; i + + ) {
2023-05-17 16:50:09 +08:00
loadNode ( input . nodes [ inputNode . children [ i ] ] , input , node , inputNode . children [ i ] , indexBuffer , vertexBuffer ) ;
2023-05-17 14:49:05 +08:00
}
}
2023-05-25 11:38:10 +08:00
// If the node contains mesh data, we load vertices and indices from the buffers
// In glTF this is done via accessors and buffer views
if ( inputNode . mesh > - 1 ) {
2023-05-17 14:49:05 +08:00
const tinygltf : : Mesh mesh = input . meshes [ inputNode . mesh ] ;
2023-05-25 11:38:10 +08:00
// Iterate through all primitives of this node's mesh
for ( size_t i = 0 ; i < mesh . primitives . size ( ) ; i + + ) {
const tinygltf : : Primitive & glTFPrimitive = mesh . primitives [ i ] ;
2023-05-17 14:49:05 +08:00
uint32_t firstIndex = static_cast < uint32_t > ( indexBuffer . size ( ) ) ;
uint32_t vertexStart = static_cast < uint32_t > ( vertexBuffer . size ( ) ) ;
uint32_t indexCount = 0 ;
2023-05-25 11:38:10 +08:00
// Vertices
2023-05-17 14:49:05 +08:00
{
2023-05-25 11:38:10 +08:00
const float * positionBuffer = nullptr ;
const float * normalsBuffer = nullptr ;
const float * texCoordsBuffer = nullptr ;
const float * tangentsBuffer = nullptr ;
size_t vertexCount = 0 ;
// Get buffer data for vertex positions
if ( glTFPrimitive . attributes . find ( " POSITION " ) ! = glTFPrimitive . attributes . end ( ) ) {
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " POSITION " ) - > second ] ;
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
positionBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2023-05-17 14:49:05 +08:00
vertexCount = accessor . count ;
}
2023-05-25 11:38:10 +08:00
// Get buffer data for vertex normals
if ( glTFPrimitive . attributes . find ( " NORMAL " ) ! = glTFPrimitive . attributes . end ( ) ) {
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " NORMAL " ) - > second ] ;
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
normalsBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-25 11:38:10 +08:00
// Get buffer data for vertex texture coordinates
// glTF supports multiple sets, we only load the first one
if ( glTFPrimitive . attributes . find ( " TEXCOORD_0 " ) ! = glTFPrimitive . attributes . end ( ) ) {
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " TEXCOORD_0 " ) - > second ] ;
2023-05-20 15:09:51 +08:00
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
2023-05-25 11:38:10 +08:00
texCoordsBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2023-05-20 15:09:51 +08:00
}
2023-05-17 14:49:05 +08:00
2023-05-25 11:38:10 +08:00
if ( glTFPrimitive . attributes . find ( " TANGENT " ) ! = glTFPrimitive . attributes . end ( ) )
2023-05-17 14:49:05 +08:00
{
2023-05-25 11:38:10 +08:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " TANGENT " ) - > second ] ;
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
tangentsBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-20 15:09:51 +08:00
2023-05-25 11:38:10 +08:00
// Append data to model's vertex buffer
for ( size_t v = 0 ; v < vertexCount ; v + + ) {
2023-05-17 14:49:05 +08:00
Vertex vert { } ;
vert . pos = glm : : vec4 ( glm : : make_vec3 ( & positionBuffer [ v * 3 ] ) , 1.0f ) ;
vert . normal = glm : : normalize ( glm : : vec3 ( normalsBuffer ? glm : : make_vec3 ( & normalsBuffer [ v * 3 ] ) : glm : : vec3 ( 0.0f ) ) ) ;
2023-05-25 11:38:10 +08:00
vert . uv = texCoordsBuffer ? glm : : make_vec2 ( & texCoordsBuffer [ v * 2 ] ) : glm : : vec3 ( 0.0f ) ;
2023-05-20 15:09:51 +08:00
vert . tangent = tangentsBuffer ? glm : : normalize ( glm : : make_vec3 ( & tangentsBuffer [ v * 4 ] ) ) : glm : : vec3 ( 0.0f ) ;
2023-05-25 11:38:10 +08:00
vert . color = glm : : vec3 ( 1.0f , 1.0f , nodeIndex ) ; //Temp set index in color attribute
2023-05-17 14:49:05 +08:00
vertexBuffer . push_back ( vert ) ;
}
}
2023-05-25 11:38:10 +08:00
// Indices
2023-05-17 14:49:05 +08:00
{
2023-05-25 11:38:10 +08:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . indices ] ;
const tinygltf : : BufferView & bufferView = input . bufferViews [ accessor . bufferView ] ;
const tinygltf : : Buffer & buffer = input . buffers [ bufferView . buffer ] ;
2023-05-17 14:49:05 +08:00
indexCount + = static_cast < uint32_t > ( accessor . count ) ;
2023-05-25 11:38:10 +08:00
// glTF supports different component types of indices
switch ( accessor . componentType ) {
2023-05-17 14:49:05 +08:00
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT : {
2023-05-25 11:38:10 +08:00
const uint32_t * buf = reinterpret_cast < const uint32_t * > ( & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] ) ;
for ( size_t index = 0 ; index < accessor . count ; index + + ) {
2023-05-17 14:49:05 +08:00
indexBuffer . push_back ( buf [ index ] + vertexStart ) ;
}
break ;
}
2023-05-25 11:38:10 +08:00
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT : {
const uint16_t * buf = reinterpret_cast < const uint16_t * > ( & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] ) ;
for ( size_t index = 0 ; index < accessor . count ; index + + ) {
2023-05-17 14:49:05 +08:00
indexBuffer . push_back ( buf [ index ] + vertexStart ) ;
}
break ;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE : {
2023-05-25 11:38:10 +08:00
const uint8_t * buf = reinterpret_cast < const uint8_t * > ( & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] ) ;
for ( size_t index = 0 ; index < accessor . count ; index + + ) {
2023-05-17 14:49:05 +08:00
indexBuffer . push_back ( buf [ index ] + vertexStart ) ;
}
break ;
}
default :
2023-05-25 11:38:10 +08:00
std : : cerr < < " Index component type " < < accessor . componentType < < " not supported! " < < std : : endl ;
2023-05-17 14:49:05 +08:00
return ;
}
}
Primitive primitive { } ;
primitive . firstIndex = firstIndex ;
primitive . indexCount = indexCount ;
2023-05-25 11:38:10 +08:00
primitive . materialIndex = glTFPrimitive . material ;
2023-05-17 14:49:05 +08:00
node - > mesh . primitives . push_back ( primitive ) ;
}
}
2023-05-25 11:38:10 +08:00
if ( parent ) {
2023-05-17 14:49:05 +08:00
parent - > children . push_back ( node ) ;
}
2023-05-25 11:38:10 +08:00
else {
2023-05-17 14:49:05 +08:00
nodes . push_back ( node ) ;
}
}
/*
vertex skinning functions
*/
glm : : mat4 VulkanglTFModel : : getNodeMatrix ( VulkanglTFModel : : Node * node )
{
glm : : mat4 nodeMatrix = node - > getLocalMatrix ( ) ;
VulkanglTFModel : : Node * currentParent = node - > parent ;
while ( currentParent )
{
nodeMatrix = currentParent - > getLocalMatrix ( ) * nodeMatrix ;
currentParent = currentParent - > parent ;
}
return nodeMatrix ;
}
2023-05-18 11:49:09 +08:00
void VulkanglTFModel : : updateNodeMatrix ( Node * node , std : : vector < glm : : mat4 > & nodeMatrics )
{
if ( node - > skin < = - 1 )
{
nodeMatrics [ node - > index ] = getNodeMatrix ( node ) ;
for ( auto & child : node - > children )
{
2023-05-20 15:09:51 +08:00
updateNodeMatrix ( child , nodeMatrics ) ;
2023-05-18 11:49:09 +08:00
}
}
}
2023-05-17 14:49:05 +08:00
void VulkanglTFModel : : updateJoints ( VulkanglTFModel : : Node * node )
{
if ( node - > skin > - 1 )
{
glm : : mat4 inversTransform = glm : : inverse ( getNodeMatrix ( node ) ) ;
Skin skin = skins [ node - > skin ] ;
size_t numJoints = ( uint32_t ) skin . joints . size ( ) ;
std : : vector < glm : : mat4 > jointMatrices ( numJoints ) ;
for ( size_t i = 0 ; i < numJoints ; i + + )
{
jointMatrices [ i ] = getNodeMatrix ( skin . joints [ i ] ) * skin . inverseBindMatrices [ i ] ;
jointMatrices [ i ] = inversTransform * jointMatrices [ i ] ;
}
skin . ssbo . copyTo ( jointMatrices . data ( ) , jointMatrices . size ( ) * sizeof ( glm : : mat4 ) ) ;
}
for ( auto & child : node - > children )
{
updateJoints ( child ) ;
}
}
2023-05-18 11:49:09 +08:00
void VulkanglTFModel : : updateAnimation ( float deltaTime , vks : : Buffer buffer )
2023-05-17 14:49:05 +08:00
{
2023-05-17 16:50:09 +08:00
if ( activeAnimation > static_cast < uint32_t > ( animations . size ( ) ) - 1 )
2023-05-17 14:49:05 +08:00
{
2023-05-17 16:50:09 +08:00
std : : cout < < " No animation with index " < < activeAnimation < < std : : endl ;
2023-05-17 14:49:05 +08:00
return ;
}
Animation & animation = animations [ activeAnimation ] ;
animation . currentTime + = deltaTime ;
if ( animation . currentTime > animation . end )
{
animation . currentTime - = animation . end ;
}
2023-05-17 16:50:09 +08:00
2023-05-17 14:49:05 +08:00
for ( auto & channel : animation . channels )
{
AnimationSampler & sampler = animation . samplers [ channel . samplerIndex ] ;
2023-05-18 11:49:09 +08:00
for ( size_t i = 0 ; i < sampler . inputs . size ( ) - 1 ; + + i )
2023-05-17 14:49:05 +08:00
{
if ( sampler . interpolation ! = " LINEAR " )
{
2023-05-17 16:50:09 +08:00
std : : cout < < " This sample only supports linear interpolations \n " ;
2023-05-17 14:49:05 +08:00
continue ;
}
2023-05-17 16:50:09 +08:00
// Get the input keyframe values for the current time stamp
2023-05-17 14:49:05 +08:00
if ( ( animation . currentTime > = sampler . inputs [ i ] ) & & ( animation . currentTime < = sampler . inputs [ i + 1 ] ) )
{
2023-05-18 11:49:09 +08:00
float ratio = ( animation . currentTime - sampler . inputs [ i ] ) / ( sampler . inputs [ i + 1 ] - sampler . inputs [ i ] ) ;
2023-05-17 14:49:05 +08:00
if ( channel . path = = " translation " )
{
2023-05-18 11:49:09 +08:00
channel . node - > translation = glm : : mix ( sampler . outputsVec4 [ i ] , sampler . outputsVec4 [ i + 1 ] , ratio ) ;
2023-05-22 11:21:13 +08:00
channel . node - > bAnimateNode = true ;
2023-05-17 14:49:05 +08:00
}
if ( channel . path = = " rotation " )
{
glm : : quat q1 ;
q1 . x = sampler . outputsVec4 [ i ] . x ;
q1 . y = sampler . outputsVec4 [ i ] . y ;
q1 . z = sampler . outputsVec4 [ i ] . z ;
q1 . w = sampler . outputsVec4 [ i ] . w ;
glm : : quat q2 ;
2023-05-17 16:50:09 +08:00
q2 . x = sampler . outputsVec4 [ i + 1 ] . x ;
q2 . y = sampler . outputsVec4 [ i + 1 ] . y ;
q2 . z = sampler . outputsVec4 [ i + 1 ] . z ;
q2 . w = sampler . outputsVec4 [ i + 1 ] . w ;
2023-05-17 14:49:05 +08:00
2023-05-18 11:49:09 +08:00
channel . node - > rotation = glm : : normalize ( glm : : slerp ( q1 , q2 , ratio ) ) ;
channel . node - > bAnimateNode = true ;
2023-05-17 14:49:05 +08:00
}
if ( channel . path = = " scale " )
{
2023-05-18 11:49:09 +08:00
channel . node - > scale = glm : : mix ( sampler . outputsVec4 [ i ] , sampler . outputsVec4 [ i + 1 ] , ratio ) ;
channel . node - > bAnimateNode = true ;
2023-05-17 14:49:05 +08:00
}
}
}
}
2023-05-18 11:49:09 +08:00
//if no skin in model , update node matrix to update animation stage
std : : vector < glm : : mat4 > nodeMatrics ( nodeCount ) ;
2023-05-17 14:49:05 +08:00
for ( auto & node : nodes )
{
2023-05-22 22:52:27 +08:00
//updateJoints(node);
2023-05-18 11:49:09 +08:00
updateNodeMatrix ( node , nodeMatrics ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-18 11:49:09 +08:00
buffer . copyTo ( nodeMatrics . data ( ) , nodeCount * sizeof ( glm : : mat4 ) ) ;
2023-05-17 14:49:05 +08:00
}
/*
glTF rendering functions
*/
// Draw a single node including child nodes (if present)
void VulkanglTFModel : : drawNode ( VkCommandBuffer commandBuffer , VkPipelineLayout pipelineLayout , VulkanglTFModel : : Node node )
{
if ( node . mesh . primitives . size ( ) > 0 ) {
// Pass the node's matrix via push constants
// Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
glm : : mat4 nodeMatrix = node . matrix ;
VulkanglTFModel : : Node * currentParent = node . parent ;
while ( currentParent ) {
nodeMatrix = currentParent - > matrix * nodeMatrix ;
currentParent = currentParent - > parent ;
}
for ( VulkanglTFModel : : Primitive & primitive : node . mesh . primitives ) {
2023-05-22 22:52:27 +08:00
if ( primitive . indexCount > 0 ) {
2023-05-17 14:49:05 +08:00
// Get the texture index for this primitive
2023-05-22 22:52:27 +08:00
if ( textures . size ( ) > 0 )
{
VulkanglTFModel : : Texture texture = textures [ materials [ primitive . materialIndex ] . baseColorTextureIndex ] ;
2023-05-23 15:52:04 +08:00
VulkanglTFModel : : Texture normalMap = textures [ materials [ primitive . materialIndex ] . normalMapTextureIndex ] ;
VulkanglTFModel : : Texture roughMetalMap = textures [ materials [ primitive . materialIndex ] . matalicRoughTextureIndex ] ;
2023-05-22 22:52:27 +08:00
if ( materials [ primitive . materialIndex ] . emissiveTextureIndex > = 0 )
{
2023-05-23 15:52:04 +08:00
VulkanglTFModel : : Texture emissiveMap = textures [ materials [ primitive . materialIndex ] . emissiveTextureIndex ] ;
2023-05-22 22:52:27 +08:00
vkCmdBindDescriptorSets ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 4 , 1 , & images [ emissiveMap . imageIndex ] . descriptorSet , 0 , nullptr ) ;
}
// Bind the descriptor for the current primitive's texture
vkCmdBindDescriptorSets ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 1 , 1 , & images [ texture . imageIndex ] . descriptorSet , 0 , nullptr ) ;
vkCmdBindDescriptorSets ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 2 , 1 , & images [ normalMap . imageIndex ] . descriptorSet , 0 , nullptr ) ;
vkCmdBindDescriptorSets ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 3 , 1 , & images [ roughMetalMap . imageIndex ] . descriptorSet , 0 , nullptr ) ;
vkCmdBindDescriptorSets ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 5 , 1 , & materials [ primitive . materialIndex ] . materialData . descriptorSet , 0 , nullptr ) ;
}
2023-05-17 14:49:05 +08:00
vkCmdDrawIndexed ( commandBuffer , primitive . indexCount , 1 , primitive . firstIndex , 0 , 0 ) ;
}
}
}
2023-05-19 00:08:15 +08:00
for ( auto & child : node . children ) {
2023-05-17 14:49:05 +08:00
drawNode ( commandBuffer , pipelineLayout , * child ) ;
}
}
// Draw the glTF scene starting at the top-level-nodes
2023-05-25 00:29:04 +08:00
void VulkanglTFModel : : draw ( VkCommandBuffer commandBuffer , VkPipelineLayout pipelineLayout )
2023-05-17 14:49:05 +08:00
{
// All vertices and indices are stored in single buffers, so we only need to bind once
VkDeviceSize offsets [ 1 ] = { 0 } ;
vkCmdBindVertexBuffers ( commandBuffer , 0 , 1 , & vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( commandBuffer , indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
// Render all nodes at top-level
for ( auto & node : nodes ) {
drawNode ( commandBuffer , pipelineLayout , * node ) ;
}
}
VulkanExample : : VulkanExample ( ) :
VulkanExampleBase ( ENABLE_VALIDATION )
{
title = " homework1 " ;
camera . type = Camera : : CameraType : : lookat ;
camera . flipY = true ;
camera . setPosition ( glm : : vec3 ( 0.0f , - 0.1f , - 1.0f ) ) ;
camera . setRotation ( glm : : vec3 ( 0.0f , 45.0f , 0.0f ) ) ;
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
}
2023-05-23 11:30:21 +08:00
void VulkanExample : : setupFrameBuffer ( )
{
2023-05-25 11:38:10 +08:00
VulkanExampleBase : : setupFrameBuffer ( ) ;
2023-05-23 11:30:21 +08:00
if ( pbrFrameBuffer . bCreate & & ( pbrFrameBuffer . fbo . width ! = width | | pbrFrameBuffer . fbo . height ! = height ) )
{
pbrFrameBuffer . color . destroy ( device ) ;
pbrFrameBuffer . depth . destroy ( device ) ;
pbrFrameBuffer . fbo . destroy ( device ) ;
vkDestroySampler ( device , colorSampler , nullptr ) ;
}
2023-05-17 14:49:05 +08:00
2023-05-23 11:30:21 +08:00
pbrFrameBuffer . fbo . setSize ( width , height ) ;
VkFormat attachDepthFormat ;
VkBool32 validDepthFormat = vks : : tools : : getSupportedDepthFormat ( physicalDevice , & attachDepthFormat ) ;
assert ( validDepthFormat ) ;
2023-05-25 11:38:10 +08:00
2023-05-23 15:52:04 +08:00
VulkanExample : : createAttachment ( VK_FORMAT_R8G8B8A8_UNORM , VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT , & pbrFrameBuffer . color , width , height ) ;
VulkanExample : : createAttachment ( attachDepthFormat , VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT , & pbrFrameBuffer . depth , width , height ) ;
2023-05-23 11:30:21 +08:00
2023-05-23 15:52:04 +08:00
std : : array < VkAttachmentDescription , 2 > attachs = { } ;
for ( uint32_t i = 0 ; i < static_cast < uint32_t > ( attachs . size ( ) ) ; i + + )
{
attachs [ i ] . samples = VK_SAMPLE_COUNT_1_BIT ;
attachs [ i ] . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachs [ i ] . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
attachs [ i ] . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
attachs [ i ] . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
attachs [ i ] . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
attachs [ i ] . finalLayout = 1 ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL ;
}
attachs [ 0 ] . format = pbrFrameBuffer . color . format ;
attachs [ 1 ] . format = pbrFrameBuffer . depth . format ;
2023-05-23 11:30:21 +08:00
2023-05-23 15:52:04 +08:00
VkAttachmentReference colorRefference = { } ;
colorRefference . attachment = 0 ;
colorRefference . layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ;
VkAttachmentReference depthRefference = { } ;
colorRefference . attachment = 1 ;
colorRefference . layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ;
VkSubpassDescription subpass = { } ;
subpass . pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS ;
subpass . pColorAttachments = & colorRefference ;
subpass . colorAttachmentCount = 1 ;
subpass . pDepthStencilAttachment = & depthRefference ;
std : : array < VkSubpassDependency , 2 > dependencies ;
//To test src 0
dependencies [ 0 ] . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 0 ] . dstSubpass = 0 ;
dependencies [ 0 ] . srcStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ;
dependencies [ 0 ] . dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependencies [ 0 ] . srcAccessMask = VK_ACCESS_SHADER_READ_BIT ;
dependencies [ 0 ] . dstAccessMask = 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_FRAGMENT_SHADER_BIT ;
dependencies [ 1 ] . srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ;
dependencies [ 1 ] . dstAccessMask = VK_ACCESS_SHADER_READ_BIT ;
dependencies [ 1 ] . dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT ;
VkRenderPassCreateInfo renderPassCI = { } ;
renderPassCI . sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO ;
renderPassCI . pAttachments = attachs . data ( ) ;
renderPassCI . attachmentCount = static_cast < uint32_t > ( attachs . size ( ) ) ;
renderPassCI . pSubpasses = & subpass ;
renderPassCI . pDependencies = dependencies . data ( ) ;
renderPassCI . dependencyCount = 2 ;
VK_CHECK_RESULT ( vkCreateRenderPass ( device , & renderPassCI , nullptr , & pbrFrameBuffer . fbo . renderPass ) ) ;
// FBO
VkImageView attachments [ 2 ] = { pbrFrameBuffer . color . imageView , pbrFrameBuffer . depth . imageView } ;
VkFramebufferCreateInfo frameBufferCreateInfo = vks : : initializers : : framebufferCreateInfo ( ) ;
frameBufferCreateInfo . renderPass = pbrFrameBuffer . fbo . renderPass ;
frameBufferCreateInfo . pAttachments = attachments ;
frameBufferCreateInfo . attachmentCount = 2 ;
frameBufferCreateInfo . width = pbrFrameBuffer . fbo . width ;
frameBufferCreateInfo . height = pbrFrameBuffer . fbo . height ;
frameBufferCreateInfo . layers = 1 ;
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & frameBufferCreateInfo , nullptr , & pbrFrameBuffer . fbo . frameBuffer ) ) ;
VkSamplerCreateInfo samplerCI = vks : : initializers : : samplerCreateInfo ( ) ;
samplerCI . magFilter = VK_FILTER_NEAREST ;
2023-05-23 17:32:20 +08:00
samplerCI . minFilter = VK_FILTER_NEAREST ;
samplerCI . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
samplerCI . addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
samplerCI . addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
samplerCI . addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
samplerCI . minLod = 0.0f ;
samplerCI . maxLod = 1.0f ;
samplerCI . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
2023-05-25 00:29:04 +08:00
VK_CHECK_RESULT ( vkCreateSampler ( device , & samplerCI , nullptr , & colorSampler ) ) ;
2023-05-23 17:32:20 +08:00
if ( tonemappingDescriptorSet ! = VK_NULL_HANDLE )
{
auto imageInfo = vks : : initializers : : descriptorImageInfo ( colorSampler , pbrFrameBuffer . color . imageView , VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( tonemappingDescriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & imageInfo ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
}
pbrFrameBuffer . bCreate = true ;
2023-05-23 11:30:21 +08:00
}
2023-05-17 14:49:05 +08:00
void VulkanExample : : getEnabledFeatures ( )
{
// Fill mode non solid is required for wireframe display
if ( deviceFeatures . fillModeNonSolid ) {
enabledFeatures . fillModeNonSolid = VK_TRUE ;
} ;
}
void VulkanExample : : buildCommandBuffers ( )
{
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
VkClearValue clearValues [ 2 ] ;
2023-05-19 00:08:15 +08:00
clearValues [ 0 ] . color = defaultClearColor ;
2023-05-25 00:29:04 +08:00
clearValues [ 0 ] . color = { { 0.25f , 0.25f , 0.25f , 1.0f } } ;
2023-05-17 14:49:05 +08:00
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
2023-05-25 00:29:04 +08:00
renderPassBeginInfo . renderPass = pbrFrameBuffer . fbo . 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 ;
renderPassBeginInfo . clearValueCount = 2 ;
renderPassBeginInfo . pClearValues = clearValues ;
const VkViewport viewport = vks : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
const VkRect2D scissor = vks : : initializers : : rect2D ( width , height , 0 , 0 ) ;
for ( int32_t i = 0 ; i < drawCmdBuffers . size ( ) ; + + i )
{
2023-05-25 00:29:04 +08:00
renderPassBeginInfo . framebuffer = pbrFrameBuffer . fbo . frameBuffer ;
2023-05-17 14:49:05 +08:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
vkCmdBeginRenderPass ( drawCmdBuffers [ i ] , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
vkCmdSetViewport ( drawCmdBuffers [ i ] , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
// Bind scene matrices descriptor to set 0
2023-05-25 00:29:04 +08:00
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayouts . pbrLayout , 0 , 1 , & descriptorSet , 0 , nullptr ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayouts . pbrLayout , 6 , 1 , & skinDescriptorSet , 0 , nullptr ) ;
2023-05-25 15:29:25 +08:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , wireframe ? wireframePipeline : solidPipeline ) ;
2023-05-25 00:29:04 +08:00
glTFModel . draw ( drawCmdBuffers [ i ] , pipelineLayouts . pbrLayout ) ;
2023-05-17 14:49:05 +08:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2023-05-23 17:32:20 +08:00
2023-05-25 00:29:04 +08:00
{
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
renderPassBeginInfo . renderPass = renderPass ;
renderPassBeginInfo . framebuffer = VulkanExampleBase : : frameBuffers [ i ] ;
renderPassBeginInfo . renderArea . extent . width = width ;
renderPassBeginInfo . renderArea . extent . height = height ;
renderPassBeginInfo . clearValueCount = 2 ;
renderPassBeginInfo . pClearValues = clearValues ;
vkCmdBeginRenderPass ( drawCmdBuffers [ i ] , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
vkCmdSetViewport ( drawCmdBuffers [ i ] , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayouts . tonemappingLayout , 0 , 1 , & tonemappingDescriptorSet , 0 , NULL ) ;
2023-05-25 15:29:25 +08:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , toneMappingPipeline ) ;
2023-05-25 00:29:04 +08:00
vkCmdDraw ( drawCmdBuffers [ i ] , 3 , 1 , 0 , 0 ) ;
drawUI ( drawCmdBuffers [ i ] ) ;
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
}
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2023-05-17 14:49:05 +08:00
}
}
2023-05-25 00:29:04 +08:00
void VulkanExample : : loadglTFFile ( std : : string filename , VulkanglTFModel & model , bool bSkyboxFlag )
2023-05-17 14:49:05 +08:00
{
tinygltf : : Model glTFInput ;
tinygltf : : TinyGLTF gltfContext ;
std : : string error , warning ;
this - > device = device ;
2023-05-25 00:29:04 +08:00
# if defined(__ANDROID__)
// On Android all assets are packed with the apk in a compressed form, so we need to open them using the asset manager
// We let tinygltf handle this, by passing the asset manager of our app
tinygltf : : asset_manager = androidApp - > activity - > assetManager ;
# endif
2023-05-17 14:49:05 +08:00
bool fileLoaded = gltfContext . LoadASCIIFromFile ( & glTFInput , & error , & warning , filename ) ;
// Pass some Vulkan resources required for setup and rendering to the glTF model loading class
2023-05-25 00:29:04 +08:00
model . vulkanDevice = vulkanDevice ;
model . copyQueue = queue ;
2023-05-17 14:49:05 +08:00
std : : vector < uint32_t > indexBuffer ;
std : : vector < VulkanglTFModel : : Vertex > vertexBuffer ;
2023-05-25 00:29:04 +08:00
if ( fileLoaded ) {
model . nodeCount = static_cast < uint32_t > ( glTFInput . nodes . size ( ) ) ;
model . loadImages ( glTFInput ) ;
model . loadMaterials ( glTFInput ) ;
model . loadTextures ( glTFInput ) ;
2023-05-17 14:49:05 +08:00
const tinygltf : : Scene & scene = glTFInput . scenes [ 0 ] ;
for ( size_t i = 0 ; i < scene . nodes . size ( ) ; i + + ) {
const tinygltf : : Node node = glTFInput . nodes [ scene . nodes [ i ] ] ;
2023-05-25 00:29:04 +08:00
model . loadNode ( node , glTFInput , nullptr , scene . nodes [ i ] , indexBuffer , vertexBuffer ) ;
2023-05-24 17:07:38 +08:00
}
2023-05-25 00:29:04 +08:00
model . loadAnimations ( glTFInput ) ;
2023-05-17 14:49:05 +08:00
}
else {
vks : : tools : : exitFatal ( " Could not open the glTF file. \n \n The file is part of the additional asset pack. \n \n Run \" download_assets.py \" in the repository root to download the latest version. " , - 1 ) ;
return ;
}
// Create and upload vertex and index buffer
// We will be using one single vertex buffer and one single index buffer for the whole glTF scene
// Primitives (of the glTF model) will then index into these using index offsets
size_t vertexBufferSize = vertexBuffer . size ( ) * sizeof ( VulkanglTFModel : : Vertex ) ;
size_t indexBufferSize = indexBuffer . size ( ) * sizeof ( uint32_t ) ;
2023-05-25 00:29:04 +08:00
model . indices . count = static_cast < uint32_t > ( indexBuffer . size ( ) ) ;
2023-05-17 14:49:05 +08:00
// Create host visible staging buffers (source)
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_TRANSFER_SRC_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
vertexBufferSize ,
& vertexStaging . buffer ,
& vertexStaging . memory ,
vertexBuffer . data ( ) ) ) ;
// Index data
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_TRANSFER_SRC_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
indexBufferSize ,
& indexStaging . buffer ,
& indexStaging . memory ,
indexBuffer . data ( ) ) ) ;
// Create device local buffers (target)
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
vertexBufferSize ,
2023-05-25 00:29:04 +08:00
& model . vertices . buffer ,
& model . vertices . memory ) ) ;
2023-05-17 14:49:05 +08:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
indexBufferSize ,
2023-05-25 00:29:04 +08:00
& model . indices . buffer ,
& model . indices . memory ) ) ;
2023-05-17 14:49:05 +08:00
// Copy data from staging buffers (host) do device local buffer (gpu)
VkCommandBuffer copyCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
VkBufferCopy copyRegion = { } ;
copyRegion . size = vertexBufferSize ;
vkCmdCopyBuffer (
copyCmd ,
vertexStaging . buffer ,
2023-05-25 00:29:04 +08:00
model . vertices . buffer ,
2023-05-17 14:49:05 +08:00
1 ,
& copyRegion ) ;
copyRegion . size = indexBufferSize ;
vkCmdCopyBuffer (
copyCmd ,
indexStaging . buffer ,
2023-05-25 00:29:04 +08:00
model . indices . buffer ,
2023-05-17 14:49:05 +08:00
1 ,
& copyRegion ) ;
vulkanDevice - > flushCommandBuffer ( copyCmd , queue , true ) ;
// Free staging resources
vkDestroyBuffer ( device , vertexStaging . buffer , nullptr ) ;
vkFreeMemory ( device , vertexStaging . memory , nullptr ) ;
vkDestroyBuffer ( device , indexStaging . buffer , nullptr ) ;
vkFreeMemory ( device , indexStaging . memory , nullptr ) ;
}
void VulkanExample : : loadAssets ( )
{
2023-05-24 16:10:36 +08:00
loadglTFFile ( getAssetPath ( ) + " buster_drone/busterDrone.gltf " , glTFModel ) ;
loadglTFFile ( getAssetPath ( ) + " models/cube.gltf " , skyboxModel , true ) ;
ibltextures . skyboxCube . loadFromFile ( getAssetPath ( ) + " textures/hdr/pisa_cube.ktx " , VK_FORMAT_R16G16B16A16_SFLOAT , vulkanDevice , queue ) ;
2023-05-24 17:07:38 +08:00
2023-05-17 14:49:05 +08:00
}
void VulkanExample : : setupDescriptors ( )
{
/*
This sample uses separate descriptor sets ( and layouts ) for the matrices and materials ( textures )
*/
std : : vector < VkDescriptorPoolSize > poolSizes = {
2023-05-24 11:12:54 +08:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 4 ) ,
2023-05-17 16:50:09 +08:00
// One combined image sampler per material image/texture
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , static_cast < uint32_t > ( glTFModel . images . size ( ) ) ) ,
// One ssbo per skin
2023-05-24 17:07:38 +08:00
//vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, static_cast<uint32_t>(glTFModel.skins.size())),
2023-05-24 11:12:54 +08:00
// sampler descriptor
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 4 ) ,
//animation storage buffer
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , 1 )
2023-05-17 14:49:05 +08:00
} ;
2023-05-25 00:29:04 +08:00
// One set for matrices and one per model image/texture
const uint32_t maxSetCount = static_cast < uint32_t > ( glTFModel . images . size ( ) ) + 6 ;
2023-05-17 14:49:05 +08:00
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , maxSetCount ) ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2023-05-18 17:17:57 +08:00
// Descriptor set layouts
2023-05-24 11:12:54 +08:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
{
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ,
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 1 ) ,
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 2 ) ,
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 3 ) ,
} ;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
2023-05-17 14:49:05 +08:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . matrices ) ) ;
2023-05-25 00:29:04 +08:00
2023-05-24 11:12:54 +08:00
VkDescriptorSetLayoutBinding materialBufferLayoutBinding = vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ;
descriptorSetLayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( & materialBufferLayoutBinding , 1 ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . materialUniform ) ) ;
2023-05-25 00:29:04 +08:00
2023-05-17 14:49:05 +08:00
// Descriptor set layout for passing material textures
2023-05-24 11:12:54 +08:00
VkDescriptorSetLayoutBinding setLayoutBinding = vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ;
descriptorSetLayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( & setLayoutBinding , 1 ) ;
2023-05-17 14:49:05 +08:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . textures ) ) ;
2023-05-25 00:29:04 +08:00
2023-05-24 11:12:54 +08:00
setLayoutBinding = vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 0 ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . ssbo ) ) ;
2023-05-17 16:50:09 +08:00
// Descriptor set layout for passing skin joint matrices
2023-05-24 11:12:54 +08:00
2023-05-24 17:07:38 +08:00
//setLayoutBinding = vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0);
//VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &descriptorSetLayouts.jointMatrices));
2023-05-17 14:49:05 +08:00
2023-05-17 16:50:09 +08:00
// The pipeline layout uses three sets:
// Set 0 = Scene matrices (VS)
// Set 1 = Joint matrices (VS)
// Set 2 = Material texture (FS)
2023-05-24 17:07:38 +08:00
std : : array < VkDescriptorSetLayout , 7 > setLayouts = {
2023-05-17 14:49:05 +08:00
descriptorSetLayouts . matrices ,
2023-05-24 17:07:38 +08:00
//descriptorSetLayouts.jointMatrices,
2023-05-24 11:12:54 +08:00
descriptorSetLayouts . textures ,
descriptorSetLayouts . textures ,
descriptorSetLayouts . textures ,
descriptorSetLayouts . textures ,
descriptorSetLayouts . materialUniform ,
descriptorSetLayouts . ssbo ,
} ;
2023-05-17 16:50:09 +08:00
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks : : initializers : : pipelineLayoutCreateInfo ( setLayouts . data ( ) , static_cast < uint32_t > ( setLayouts . size ( ) ) ) ;
2023-05-25 00:29:04 +08:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelineLayouts . pbrLayout ) ) ;
2023-05-17 14:49:05 +08:00
// Descriptor set for scene matrices
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . matrices , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2023-05-24 11:12:54 +08:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets =
{
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & shaderData . buffer . descriptor ) ,
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , & ibltextures . irradianceCube . descriptor ) ,
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 2 , & ibltextures . lutBrdf . descriptor ) ,
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 3 , & ibltextures . prefilteredCube . descriptor ) ,
} ;
vkUpdateDescriptorSets ( device , 4 , writeDescriptorSets . data ( ) , 0 , nullptr ) ;
for ( auto & material : glTFModel . materials )
{
const VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . materialUniform , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & material . materialData . descriptorSet ) ) ;
2023-05-25 11:38:10 +08:00
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet (
material . materialData . descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & material . materialData . buffer . descriptor ) ;
2023-05-17 14:49:05 +08:00
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
}
2023-05-25 11:38:10 +08:00
// Descriptor sets for materials
for ( auto & image : glTFModel . images ) {
2023-05-17 14:49:05 +08:00
const VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . textures , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & image . descriptorSet ) ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( image . descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & image . texture . descriptor ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
}
2023-05-25 00:29:04 +08:00
{
const VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . ssbo , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & skinDescriptorSet ) ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( skinDescriptorSet , VK_DESCRIPTOR_TYPE_STORAGE_BUFFER , 0 , & shaderData . skinSSBO . descriptor ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
}
2023-05-25 11:38:10 +08:00
//Tone Mapping pipeline layout
2023-05-24 11:12:54 +08:00
{
2023-05-25 11:38:10 +08:00
auto pipelineLayoutCI = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorSetLayouts . textures , 1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelineLayouts . tonemappingLayout ) ) ;
2023-05-24 11:12:54 +08:00
2023-05-25 11:38:10 +08:00
const VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . textures , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & tonemappingDescriptorSet ) ) ;
2023-05-24 11:12:54 +08:00
2023-05-25 11:38:10 +08:00
auto imageInfo = vks : : initializers : : descriptorImageInfo ( colorSampler , pbrFrameBuffer . color . imageView , VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( tonemappingDescriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & imageInfo ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
2023-05-24 11:12:54 +08:00
}
2023-05-17 14:49:05 +08:00
}
void VulkanExample : : preparePipelines ( )
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_BACK_BIT , VK_FRONT_FACE_COUNTER_CLOCKWISE , 0 ) ;
VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentStateCI ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_TRUE , VK_TRUE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportStateCI = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT , 0 ) ;
const std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables . data ( ) , static_cast < uint32_t > ( dynamicStateEnables . size ( ) ) , 0 ) ;
// Vertex input bindings and attributes
const std : : vector < VkVertexInputBindingDescription > vertexInputBindings = {
vks : : initializers : : vertexInputBindingDescription ( 0 , sizeof ( VulkanglTFModel : : Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX ) ,
} ;
const std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
2023-05-24 17:07:38 +08:00
vks : : initializers : : vertexInputAttributeDescription ( 0 , 0 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , pos ) ) , // Location 0: Position
vks : : initializers : : vertexInputAttributeDescription ( 0 , 1 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , normal ) ) , // Location 1: Normal
vks : : initializers : : vertexInputAttributeDescription ( 0 , 2 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , uv ) ) , // Location 2: Texture coordinates
vks : : initializers : : vertexInputAttributeDescription ( 0 , 3 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , color ) ) , // Location 3: Color
vks : : initializers : : vertexInputAttributeDescription ( 0 , 4 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , tangent ) ) , // Location 4 : Tangent
2023-05-17 14:49:05 +08:00
} ;
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputStateCI . vertexBindingDescriptionCount = static_cast < uint32_t > ( vertexInputBindings . size ( ) ) ;
vertexInputStateCI . pVertexBindingDescriptions = vertexInputBindings . data ( ) ;
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
2023-05-25 11:38:10 +08:00
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages = {
2023-05-17 14:49:05 +08:00
loadShader ( getHomeworkShadersPath ( ) + " homework1/mesh.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( getHomeworkShadersPath ( ) + " homework1/mesh.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT )
} ;
2023-05-24 17:07:38 +08:00
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelineLayouts . pbrLayout , pbrFrameBuffer . fbo . renderPass , 0 ) ;
2023-05-17 14:49:05 +08:00
pipelineCI . pVertexInputState = & vertexInputStateCI ;
pipelineCI . pInputAssemblyState = & inputAssemblyStateCI ;
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 ( ) ;
2023-05-25 15:29:25 +08:00
2023-05-17 14:49:05 +08:00
// Solid rendering pipeline
2023-05-25 15:29:25 +08:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & solidPipeline ) ) ;
2023-05-17 14:49:05 +08:00
// Wire frame rendering pipeline
if ( deviceFeatures . fillModeNonSolid ) {
rasterizationStateCI . polygonMode = VK_POLYGON_MODE_LINE ;
rasterizationStateCI . lineWidth = 1.0f ;
2023-05-25 15:29:25 +08:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & wireframePipeline ) ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-25 11:38:10 +08:00
//Create Tone Mapping render pipeline
2023-05-24 17:07:38 +08:00
prepareToneMappingPipeline ( ) ;
2023-05-17 14:49:05 +08:00
}
2023-05-24 17:07:38 +08:00
2023-05-24 11:12:54 +08:00
void VulkanExample : : prepareToneMappingPipeline ( )
{
2023-05-25 15:29:25 +08:00
if ( toneMappingPipeline ! = VK_NULL_HANDLE )
2023-05-24 11:12:54 +08:00
{
2023-05-25 15:29:25 +08:00
vkDestroyPipeline ( device , toneMappingPipeline , nullptr ) ;
toneMappingPipeline = VK_NULL_HANDLE ;
2023-05-24 11:12:54 +08:00
}
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_BACK_BIT , VK_FRONT_FACE_COUNTER_CLOCKWISE , 0 ) ;
VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentStateCI ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_TRUE , VK_TRUE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportStateCI = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT , 0 ) ;
const std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables . data ( ) , static_cast < uint32_t > ( dynamicStateEnables . size ( ) ) , 0 ) ;
VkPipelineVertexInputStateCreateInfo emptyInputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
const std : : string fragPath = ToneMapping ? " homework1/tonemapping_enable.frag.spv " : " homework1/tonemapping_disable.frag.spv " ;
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages = {
loadShader ( getHomeworkShadersPath ( ) + " homework1/genbrdflut.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( getHomeworkShadersPath ( ) + fragPath , VK_SHADER_STAGE_FRAGMENT_BIT )
} ;
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelineLayouts . tonemappingLayout , renderPass , 0 ) ;
pipelineCI . pVertexInputState = & emptyInputState ;
pipelineCI . pInputAssemblyState = & inputAssemblyStateCI ;
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 ( ) ;
2023-05-25 15:29:25 +08:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & toneMappingPipeline ) ) ;
2023-05-24 11:12:54 +08:00
}
2023-05-17 14:49:05 +08:00
// Prepare and initialize uniform buffer containing shader uniforms
void VulkanExample : : prepareUniformBuffers ( )
{
// Vertex shader uniform buffer block
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& shaderData . buffer ,
sizeof ( shaderData . values ) ) ) ;
2023-05-24 11:12:54 +08:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& shaderData . skinSSBO ,
sizeof ( glm : : mat4 ) * glTFModel . nodeCount ) ) ;
2023-05-25 11:38:10 +08:00
// Map persistent
VK_CHECK_RESULT ( shaderData . buffer . map ( ) ) ;
VK_CHECK_RESULT ( shaderData . skinSSBO . map ( ) ) ;
2023-05-24 11:12:54 +08:00
for ( auto & material : glTFModel . materials )
{
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
& material . materialData . buffer ,
sizeof ( VulkanglTFModel : : MaterialData : : Values ) ,
& material . materialData . values
) ) ;
}
2023-05-25 11:38:10 +08:00
2023-05-24 11:12:54 +08:00
2023-05-17 14:49:05 +08:00
updateUniformBuffers ( ) ;
}
void VulkanExample : : updateUniformBuffers ( )
{
shaderData . values . projection = camera . matrices . perspective ;
shaderData . values . model = camera . matrices . view ;
2023-05-24 11:12:54 +08:00
shaderData . values . viewPos = camera . viewPos ;
shaderData . values . bFlagSet . x = normalMapping ;
shaderData . values . bFlagSet . y = pbrEnabled ;
2023-05-17 14:49:05 +08:00
memcpy ( shaderData . buffer . mapped , & shaderData . values , sizeof ( shaderData . values ) ) ;
}
2023-05-24 16:10:36 +08:00
// --------- BRDF LUT precompute preparation ----------------
void VulkanExample : : generateIrradianceCubemap ( )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
constexpr VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT ;
constexpr int32_t dim = 64 ;
const uint32_t numMips = static_cast < uint32_t > ( floor ( log2 ( dim ) ) ) + 1 ;
VkImageCreateInfo imageCI = vks : : initializers : : imageCreateInfo ( ) ;
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 , & ibltextures . irradianceCube . image ) )
// allocate memory for irradiance cube map
VkMemoryAllocateInfo memAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , ibltextures . irradianceCube . image , & memReqs ) ;
memAlloc . allocationSize = memReqs . size ;
memAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAlloc , nullptr , & ibltextures . irradianceCube . deviceMemory ) )
VK_CHECK_RESULT ( vkBindImageMemory ( device , ibltextures . irradianceCube . image , ibltextures . irradianceCube . deviceMemory , 0 ) )
VkImageViewCreateInfo viewCI = vks : : initializers : : imageViewCreateInfo ( ) ;
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 = ibltextures . irradianceCube . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & viewCI , nullptr , & ibltextures . irradianceCube . view ) )
// set up sampler and image view
VkSamplerCreateInfo samplerCI = vks : : initializers : : samplerCreateInfo ( ) ;
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 . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
VK_CHECK_RESULT ( vkCreateSampler ( device , & samplerCI , nullptr , & ibltextures . irradianceCube . sampler ) )
ibltextures . irradianceCube . descriptor . imageView = ibltextures . irradianceCube . view ;
ibltextures . irradianceCube . descriptor . sampler = ibltextures . irradianceCube . sampler ;
ibltextures . irradianceCube . descriptor . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
ibltextures . irradianceCube . device = vulkanDevice ;
//Setup Framebuffer and so on
VkAttachmentDescription attachDescription = { } ;
attachDescription . format = format ;
attachDescription . samples = VK_SAMPLE_COUNT_1_BIT ;
attachDescription . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attachDescription . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
attachDescription . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
attachDescription . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
attachDescription . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
attachDescription . 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 ;
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 ;
//set up render pass
VkRenderPassCreateInfo renderPassCI = vks : : initializers : : renderPassCreateInfo ( ) ;
renderPassCI . attachmentCount = 1 ;
renderPassCI . pAttachments = & attachDescription ;
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 image
VkImageCreateInfo imageCreateInfo = vks : : initializers : : imageCreateInfo ( ) ;
imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ;
imageCreateInfo . format = format ;
imageCreateInfo . extent . width = dim ;
imageCreateInfo . extent . height = dim ;
imageCreateInfo . extent . depth = 1 ;
imageCreateInfo . mipLevels = 1 ;
imageCreateInfo . arrayLayers = 1 ;
imageCreateInfo . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCreateInfo . tiling = VK_IMAGE_TILING_OPTIMAL ;
imageCreateInfo . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
imageCreateInfo . usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT ;
imageCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCreateInfo , nullptr , & offscreen . image ) )
// allocate memory
VkMemoryAllocateInfo imageCIMemAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
VkMemoryRequirements imageCIMemReqs ;
vkGetImageMemoryRequirements ( device , offscreen . image , & imageCIMemReqs ) ;
imageCIMemAlloc . allocationSize = imageCIMemReqs . size ;
imageCIMemAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( imageCIMemReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & imageCIMemAlloc , nullptr , & offscreen . memory ) )
VK_CHECK_RESULT ( vkBindImageMemory ( device , offscreen . image , offscreen . memory , 0 ) )
// create color image view
VkImageViewCreateInfo colorImageView = vks : : initializers : : imageViewCreateInfo ( ) ;
colorImageView . viewType = VK_IMAGE_VIEW_TYPE_2D ;
colorImageView . format = format ;
colorImageView . flags = 0 ;
colorImageView . subresourceRange = { } ;
colorImageView . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
colorImageView . subresourceRange . baseMipLevel = 0 ;
colorImageView . subresourceRange . levelCount = 1 ;
colorImageView . subresourceRange . baseArrayLayer = 0 ;
colorImageView . subresourceRange . layerCount = 1 ;
colorImageView . image = offscreen . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & colorImageView , nullptr , & offscreen . view ) )
// set up framebuffer for offscreen image
VkFramebufferCreateInfo fbufCreateInfo = vks : : initializers : : framebufferCreateInfo ( ) ;
fbufCreateInfo . renderPass = renderpass ;
fbufCreateInfo . attachmentCount = 1 ;
fbufCreateInfo . pAttachments = & offscreen . view ;
fbufCreateInfo . width = dim ;
fbufCreateInfo . height = dim ;
fbufCreateInfo . layers = 1 ;
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & fbufCreateInfo , nullptr , & offscreen . framebuffer ) )
VkCommandBuffer layoutCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
vks : : tools : : setImageLayout (
layoutCmd ,
offscreen . image ,
VK_IMAGE_ASPECT_COLOR_BIT ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ) ;
vulkanDevice - > flushCommandBuffer ( layoutCmd , queue , true ) ;
// create descriptor set layout
VkDescriptorSetLayout descriptorsetlayout ;
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
{
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ,
} ;
VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorsetlayoutCI , nullptr , & descriptorsetlayout ) ) ;
// allocate pool
std : : vector < VkDescriptorPoolSize > poolSizes = { vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 ) } ;
VkDescriptorPoolCreateInfo descriptorPoolCI = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
VkDescriptorPool descriptorpool ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolCI , nullptr , & descriptorpool ) ) ;
//write to poos
VkDescriptorSet descriptorset ;
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorpool , & descriptorsetlayout , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorset ) ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( descriptorset , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & ibltextures . skyboxCube . descriptor ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
// push matrix
VkPipelineLayout pipelinelayout ;
std : : vector < VkPushConstantRange > pushConstantRanges =
{
vks : : initializers : : pushConstantRange ( VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , sizeof ( IrradiancePushBlock ) , 0 )
} ;
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorsetlayout , 1 ) ;
pipelineLayoutCI . pushConstantRangeCount = 1 ;
pipelineLayoutCI . pPushConstantRanges = pushConstantRanges . data ( ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelinelayout ) ) ;
//Pipeline Setting
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_NONE , VK_FRONT_FACE_COUNTER_CLOCKWISE ) ;
VkPipelineColorBlendAttachmentState blendAttachmentState = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_FALSE , VK_FALSE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportState = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 ) ;
VkPipelineMultisampleStateCreateInfo multisampleState = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT ) ;
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicState = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
const std : : vector < VkVertexInputBindingDescription > vertexInputBindings =
{
vks : : initializers : : vertexInputBindingDescription ( 0 , sizeof ( VulkanglTFModel : : Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX ) ,
} ;
const std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
vks : : initializers : : vertexInputAttributeDescription ( 0 , 0 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , pos ) ) , // Location 0: Position
} ;
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputStateCI . vertexBindingDescriptionCount = static_cast < uint32_t > ( vertexInputBindings . size ( ) ) ;
vertexInputStateCI . pVertexBindingDescriptions = vertexInputBindings . data ( ) ;
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelinelayout , renderpass ) ;
pipelineCI . pInputAssemblyState = & inputAssemblyState ;
pipelineCI . pRasterizationState = & rasterizationState ;
pipelineCI . pColorBlendState = & colorBlendState ;
pipelineCI . pMultisampleState = & multisampleState ;
pipelineCI . pViewportState = & viewportState ;
pipelineCI . pDepthStencilState = & depthStencilState ;
pipelineCI . pDynamicState = & dynamicState ;
pipelineCI . stageCount = 2 ;
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . renderPass = renderpass ;
pipelineCI . pVertexInputState = & vertexInputStateCI ;
shaderStages [ 0 ] = loadShader ( getHomeworkShadersPath ( ) + " homework1/filtercube.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getHomeworkShadersPath ( ) + " homework1/irradiancecube.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
VkPipeline pipeline ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
// offscreen Render pass begin
VkClearValue clearValues [ 1 ] ;
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.2f , 0.0f } } ;
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
renderPassBeginInfo . renderPass = renderpass ;
renderPassBeginInfo . framebuffer = offscreen . framebuffer ;
renderPassBeginInfo . renderArea . extent . width = dim ;
renderPassBeginInfo . renderArea . extent . height = dim ;
renderPassBeginInfo . clearValueCount = 1 ;
renderPassBeginInfo . pClearValues = clearValues ;
//six face in cube map
std : : vector < glm : : mat4 > matrices = {
// POSITIVE_X
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 ) ) ,
// NEGATIVE_X
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 ) ) ,
// POSITIVE_Y
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( - 90.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ,
// NEGATIVE_Y
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( 90.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ,
// POSITIVE_Z
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( 180.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ,
// NEGATIVE_Z
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( 180.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) ) ,
} ;
VkCommandBuffer cmdBuf = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
VkViewport viewport = vks : : initializers : : viewport ( ( float ) dim , ( float ) dim , 0.0f , 1.0f ) ;
VkRect2D scissor = vks : : initializers : : rect2D ( dim , dim , 0 , 0 ) ;
vkCmdSetViewport ( cmdBuf , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( cmdBuf , 0 , 1 , & scissor ) ;
VkImageSubresourceRange subresourceRange = { } ;
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
subresourceRange . baseMipLevel = 0 ;
subresourceRange . levelCount = numMips ;
subresourceRange . layerCount = 6 ;
vks : : tools : : setImageLayout (
cmdBuf ,
ibltextures . irradianceCube . image ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
subresourceRange ) ;
for ( uint32_t m = 0 ; m < numMips ; + + m )
{
for ( uint32_t f = 0 ; f < 6 ; + + f )
{
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 ) ;
// Render scene from cube face's point of view
vkCmdBeginRenderPass ( cmdBuf , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
irradinacePushBlock . mvp = glm : : perspective ( ( float ) ( M_PI / 2.0 ) , 1.0f , 0.1f , 512.0f ) * matrices [ f ] ;
vkCmdPushConstants ( cmdBuf , pipelinelayout , VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , 0 , sizeof ( IrradiancePushBlock ) , & irradinacePushBlock ) ;
vkCmdBindPipeline ( cmdBuf , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
vkCmdBindDescriptorSets ( cmdBuf , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelinelayout , 0 , 1 , & descriptorset , 0 , NULL ) ;
skyboxModel . draw ( cmdBuf , pipelinelayout ) ;
vkCmdEndRenderPass ( cmdBuf ) ;
vks : : tools : : setImageLayout (
cmdBuf ,
offscreen . image ,
VK_IMAGE_ASPECT_COLOR_BIT ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ) ;
VkImageCopy copyRegion = { } ;
copyRegion . srcSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
copyRegion . srcSubresource . layerCount = 1 ;
copyRegion . srcSubresource . mipLevel = 0 ;
copyRegion . srcSubresource . baseArrayLayer = 0 ;
copyRegion . dstSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
copyRegion . dstSubresource . layerCount = 1 ;
copyRegion . dstSubresource . mipLevel = m ;
copyRegion . dstSubresource . baseArrayLayer = f ;
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 ,
ibltextures . irradianceCube . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
1 ,
& copyRegion ) ;
vks : : tools : : setImageLayout ( cmdBuf ,
offscreen . image ,
VK_IMAGE_ASPECT_COLOR_BIT ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
) ;
}
}
vks : : tools : : setImageLayout ( cmdBuf ,
ibltextures . irradianceCube . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ,
subresourceRange ) ;
vulkanDevice - > flushCommandBuffer ( cmdBuf , queue ) ;
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 ) ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
std : : cout < < " Generating irradiance cube with " < < numMips < < " mip levels took " < < tDiff < < " ms " < < std : : endl ;
}
void VulkanExample : : generatePrefilteredCubemap ( )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
constexpr VkFormat format = VK_FORMAT_R32G32B32A32_SFLOAT ;
constexpr int32_t dim = 512 ;
const uint32_t numMips = static_cast < uint32_t > ( floor ( log2 ( dim ) ) ) + 1 ;
VkImageCreateInfo imageCI = vks : : initializers : : imageCreateInfo ( ) ;
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 , & ibltextures . prefilteredCube . image ) ) ;
VkMemoryAllocateInfo memAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , ibltextures . prefilteredCube . image , & memReqs ) ;
memAlloc . allocationSize = memReqs . size ;
memAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAlloc , nullptr , & ibltextures . prefilteredCube . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , ibltextures . prefilteredCube . image , ibltextures . prefilteredCube . deviceMemory , 0 ) ) ;
// Image view
VkImageViewCreateInfo viewCI = vks : : initializers : : imageViewCreateInfo ( ) ;
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 = ibltextures . prefilteredCube . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & viewCI , nullptr , & ibltextures . prefilteredCube . view ) ) ;
// Sampler
VkSamplerCreateInfo samplerCI = vks : : initializers : : samplerCreateInfo ( ) ;
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 . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
VK_CHECK_RESULT ( vkCreateSampler ( device , & samplerCI , nullptr , & ibltextures . prefilteredCube . sampler ) ) ;
ibltextures . prefilteredCube . descriptor . imageView = ibltextures . prefilteredCube . view ;
ibltextures . prefilteredCube . descriptor . sampler = ibltextures . prefilteredCube . sampler ;
ibltextures . prefilteredCube . descriptor . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
ibltextures . prefilteredCube . device = vulkanDevice ;
// 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 = vks : : initializers : : renderPassCreateInfo ( ) ;
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 ) ) ;
//framebuffer
{
// Color attachment
VkImageCreateInfo imageCreateInfo = vks : : initializers : : imageCreateInfo ( ) ;
imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ;
imageCreateInfo . format = format ;
imageCreateInfo . extent . width = dim ;
imageCreateInfo . extent . height = dim ;
imageCreateInfo . extent . depth = 1 ;
imageCreateInfo . mipLevels = 1 ;
imageCreateInfo . arrayLayers = 1 ;
imageCreateInfo . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCreateInfo . tiling = VK_IMAGE_TILING_OPTIMAL ;
imageCreateInfo . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
imageCreateInfo . usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT ;
imageCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCreateInfo , nullptr , & offscreen . image ) ) ;
VkMemoryAllocateInfo memAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , offscreen . image , & memReqs ) ;
memAlloc . allocationSize = memReqs . size ;
memAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAlloc , nullptr , & offscreen . memory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , offscreen . image , offscreen . memory , 0 ) ) ;
VkImageViewCreateInfo colorImageView = vks : : initializers : : imageViewCreateInfo ( ) ;
colorImageView . viewType = VK_IMAGE_VIEW_TYPE_2D ;
colorImageView . format = format ;
colorImageView . flags = 0 ;
colorImageView . subresourceRange = { } ;
colorImageView . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
colorImageView . subresourceRange . baseMipLevel = 0 ;
colorImageView . subresourceRange . levelCount = 1 ;
colorImageView . subresourceRange . baseArrayLayer = 0 ;
colorImageView . subresourceRange . layerCount = 1 ;
colorImageView . image = offscreen . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & colorImageView , nullptr , & offscreen . view ) ) ;
VkFramebufferCreateInfo fbufCreateInfo = vks : : initializers : : framebufferCreateInfo ( ) ;
fbufCreateInfo . renderPass = renderpass ;
fbufCreateInfo . attachmentCount = 1 ;
fbufCreateInfo . pAttachments = & offscreen . view ;
fbufCreateInfo . width = dim ;
fbufCreateInfo . height = dim ;
fbufCreateInfo . layers = 1 ;
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & fbufCreateInfo , nullptr , & offscreen . framebuffer ) ) ;
VkCommandBuffer layoutCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
vks : : tools : : setImageLayout (
layoutCmd ,
offscreen . image ,
VK_IMAGE_ASPECT_COLOR_BIT ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ) ;
vulkanDevice - > flushCommandBuffer ( layoutCmd , queue , true ) ;
}
// Descriptors
VkDescriptorSetLayout descriptorsetlayout ;
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ,
} ;
VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorsetlayoutCI , nullptr , & descriptorsetlayout ) ) ;
// Descriptor Pool
std : : vector < VkDescriptorPoolSize > poolSizes = { vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 ) } ;
VkDescriptorPoolCreateInfo descriptorPoolCI = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
VkDescriptorPool descriptorpool ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolCI , nullptr , & descriptorpool ) ) ;
VkDescriptorSet descriptorset ;
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorpool , & descriptorsetlayout , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorset ) ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( descriptorset , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & ibltextures . skyboxCube . descriptor ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
std : : vector < VkPushConstantRange > pushConstantRanges = {
vks : : initializers : : pushConstantRange ( VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , sizeof ( PrefilterPushBlock ) , 0 ) ,
} ;
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorsetlayout , 1 ) ;
pipelineLayoutCI . pushConstantRangeCount = 1 ;
pipelineLayoutCI . pPushConstantRanges = pushConstantRanges . data ( ) ;
VkPipelineLayout pipelinelayout ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelinelayout ) ) ;
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_NONE , VK_FRONT_FACE_COUNTER_CLOCKWISE ) ;
VkPipelineColorBlendAttachmentState blendAttachmentState = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_FALSE , VK_FALSE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportState = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 ) ;
VkPipelineMultisampleStateCreateInfo multisampleState = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT ) ;
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicState = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
const std : : vector < VkVertexInputBindingDescription > vertexInputBindings =
{
vks : : initializers : : vertexInputBindingDescription ( 0 , sizeof ( VulkanglTFModel : : Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX ) ,
} ;
const std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
vks : : initializers : : vertexInputAttributeDescription ( 0 , 0 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , pos ) ) , // Location 0: Position
} ;
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputStateCI . vertexBindingDescriptionCount = static_cast < uint32_t > ( vertexInputBindings . size ( ) ) ;
vertexInputStateCI . pVertexBindingDescriptions = vertexInputBindings . data ( ) ;
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelinelayout , renderpass ) ;
pipelineCI . pInputAssemblyState = & inputAssemblyState ;
pipelineCI . pRasterizationState = & rasterizationState ;
pipelineCI . pColorBlendState = & colorBlendState ;
pipelineCI . pMultisampleState = & multisampleState ;
pipelineCI . pViewportState = & viewportState ;
pipelineCI . pDepthStencilState = & depthStencilState ;
pipelineCI . pDynamicState = & dynamicState ;
pipelineCI . stageCount = 2 ;
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . renderPass = renderpass ;
pipelineCI . pVertexInputState = & vertexInputStateCI ;
shaderStages [ 0 ] = loadShader ( getHomeworkShadersPath ( ) + " homework1/filtercube.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getHomeworkShadersPath ( ) + " homework1/prefilterenvmap.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
VkPipeline pipeline ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
//Render & build cmd
VkClearValue clearValues [ 1 ] ;
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.2f , 0.0f } } ;
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
// Reuse render pass from example pass
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 = {
// POSITIVE_X
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 ) ) ,
// NEGATIVE_X
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 ) ) ,
// POSITIVE_Y
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( - 90.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ,
// NEGATIVE_Y
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( 90.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ,
// POSITIVE_Z
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( 180.0f ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ,
// NEGATIVE_Z
glm : : rotate ( glm : : mat4 ( 1.0f ) , glm : : radians ( 180.0f ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) ) ,
} ;
VkCommandBuffer cmdBuf = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
VkViewport viewport = vks : : initializers : : viewport ( ( float ) dim , ( float ) dim , 0.0f , 1.0f ) ;
VkRect2D scissor = vks : : initializers : : rect2D ( dim , dim , 0 , 0 ) ;
vkCmdSetViewport ( cmdBuf , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( cmdBuf , 0 , 1 , & scissor ) ;
VkImageSubresourceRange subresourceRange = { } ;
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
subresourceRange . baseMipLevel = 0 ;
subresourceRange . levelCount = numMips ;
subresourceRange . layerCount = 6 ;
vks : : tools : : setImageLayout (
cmdBuf ,
ibltextures . prefilteredCube . image ,
VK_IMAGE_LAYOUT_UNDEFINED ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
subresourceRange ) ;
for ( uint32_t m = 0 ; m < numMips ; + + m )
{
//mip level according to roughness
prefilterPushBlock . roughness = float ( m ) / float ( numMips - 1 ) ;
for ( uint32_t f = 0 ; f < 6 ; + + f )
{
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 ) ;
// Render scene from cube face's point of view
vkCmdBeginRenderPass ( cmdBuf , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
// Update shader push constant block
prefilterPushBlock . mvp = glm : : perspective ( ( float ) ( M_PI / 2.0 ) , 1.0f , 0.1f , 512.0f ) * matrices [ f ] ;
vkCmdPushConstants ( cmdBuf , pipelinelayout , VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT , 0 , sizeof ( PrefilterPushBlock ) , & prefilterPushBlock ) ;
vkCmdBindPipeline ( cmdBuf , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
vkCmdBindDescriptorSets ( cmdBuf , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelinelayout , 0 , 1 , & descriptorset , 0 , nullptr ) ;
skyboxModel . draw ( cmdBuf , pipelinelayout ) ;
vkCmdEndRenderPass ( cmdBuf ) ;
vks : : tools : : setImageLayout (
cmdBuf ,
offscreen . image ,
VK_IMAGE_ASPECT_COLOR_BIT ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ) ;
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 ,
ibltextures . prefilteredCube . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
1 ,
& copyRegion ) ;
//Reset frame buffer image layout
vks : : tools : : setImageLayout (
cmdBuf ,
offscreen . image ,
VK_IMAGE_ASPECT_COLOR_BIT ,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL ,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL ) ;
}
}
//Set format shader read
vks : : tools : : setImageLayout (
cmdBuf ,
ibltextures . prefilteredCube . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ,
subresourceRange ) ;
vulkanDevice - > flushCommandBuffer ( cmdBuf , queue ) ;
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 ) ;
auto tEnd = std : : chrono : : high_resolution_clock : : now ( ) ;
auto tDiff = std : : chrono : : duration < double , std : : milli > ( tEnd - tStart ) . count ( ) ;
std : : cout < < " Generating pre-filtered enivornment cube with " < < numMips < < " mip levels took " < < tDiff < < " ms " < < std : : endl ;
}
void VulkanExample : : generateBRDFLUT ( )
{
auto tStart = std : : chrono : : high_resolution_clock : : now ( ) ;
constexpr VkFormat format = VK_FORMAT_R16G16_SFLOAT ;
constexpr int32_t dim = 512 ;
// Image
VkImageCreateInfo imageCI = vks : : initializers : : imageCreateInfo ( ) ;
imageCI . imageType = VK_IMAGE_TYPE_2D ;
imageCI . format = format ;
imageCI . extent . width = dim ;
imageCI . extent . height = dim ;
imageCI . extent . depth = 1 ;
imageCI . mipLevels = 1 ;
imageCI . arrayLayers = 1 ;
imageCI . samples = VK_SAMPLE_COUNT_1_BIT ;
imageCI . tiling = VK_IMAGE_TILING_OPTIMAL ;
imageCI . usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ;
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCI , nullptr , & ibltextures . lutBrdf . image ) ) ;
VkMemoryAllocateInfo memAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
VkMemoryRequirements memReqs ;
vkGetImageMemoryRequirements ( device , ibltextures . lutBrdf . image , & memReqs ) ;
memAlloc . allocationSize = memReqs . size ;
memAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAlloc , nullptr , & ibltextures . lutBrdf . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , ibltextures . lutBrdf . image , ibltextures . lutBrdf . deviceMemory , 0 ) ) ;
// Image view
VkImageViewCreateInfo viewCI = vks : : initializers : : imageViewCreateInfo ( ) ;
viewCI . viewType = VK_IMAGE_VIEW_TYPE_2D ;
viewCI . format = format ;
viewCI . subresourceRange = { } ;
viewCI . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
viewCI . subresourceRange . levelCount = 1 ;
viewCI . subresourceRange . layerCount = 1 ;
viewCI . image = ibltextures . lutBrdf . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & viewCI , nullptr , & ibltextures . lutBrdf . view ) ) ;
// Sampler
VkSamplerCreateInfo samplerCI = vks : : initializers : : samplerCreateInfo ( ) ;
samplerCI . magFilter = VK_FILTER_LINEAR ;
samplerCI . minFilter = VK_FILTER_LINEAR ;
samplerCI . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
samplerCI . addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
samplerCI . addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
samplerCI . addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
samplerCI . minLod = 0.0f ;
samplerCI . maxLod = 1.0f ;
samplerCI . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
VK_CHECK_RESULT ( vkCreateSampler ( device , & samplerCI , nullptr , & ibltextures . lutBrdf . sampler ) ) ;
ibltextures . lutBrdf . descriptor . imageView = ibltextures . lutBrdf . view ;
ibltextures . lutBrdf . descriptor . sampler = ibltextures . lutBrdf . sampler ;
ibltextures . lutBrdf . descriptor . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
ibltextures . lutBrdf . device = vulkanDevice ;
// FB, Att, RP, Pipe, etc.
VkAttachmentDescription attDesc = { } ;
// Color attachment
attDesc . format = format ;
attDesc . samples = VK_SAMPLE_COUNT_1_BIT ;
attDesc . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ;
attDesc . storeOp = VK_ATTACHMENT_STORE_OP_STORE ;
attDesc . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
attDesc . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
attDesc . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
attDesc . finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
VkAttachmentReference colorReference = { 0 , VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL } ;
VkSubpassDescription subpassDescription = { } ;
subpassDescription . pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS ;
subpassDescription . colorAttachmentCount = 1 ;
subpassDescription . pColorAttachments = & colorReference ;
// Use subpass dependencies for layout transitions
std : : array < VkSubpassDependency , 2 > dependencies ;
dependencies [ 0 ] . srcSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 0 ] . dstSubpass = 0 ;
dependencies [ 0 ] . srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT ;
dependencies [ 0 ] . dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependencies [ 0 ] . srcAccessMask = VK_ACCESS_MEMORY_READ_BIT ;
dependencies [ 0 ] . dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ;
dependencies [ 0 ] . dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT ;
dependencies [ 1 ] . srcSubpass = 0 ;
dependencies [ 1 ] . dstSubpass = VK_SUBPASS_EXTERNAL ;
dependencies [ 1 ] . srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT ;
dependencies [ 1 ] . dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT ;
dependencies [ 1 ] . srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT ;
dependencies [ 1 ] . dstAccessMask = VK_ACCESS_MEMORY_READ_BIT ;
dependencies [ 1 ] . dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT ;
// Create the actual renderpass
VkRenderPassCreateInfo renderPassCI = vks : : initializers : : renderPassCreateInfo ( ) ;
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 ) ) ;
VkFramebufferCreateInfo framebufferCI = vks : : initializers : : framebufferCreateInfo ( ) ;
framebufferCI . renderPass = renderpass ;
framebufferCI . attachmentCount = 1 ;
framebufferCI . pAttachments = & ibltextures . lutBrdf . view ;
framebufferCI . width = dim ;
framebufferCI . height = dim ;
framebufferCI . layers = 1 ;
VkFramebuffer framebuffer ;
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & framebufferCI , nullptr , & framebuffer ) ) ;
// Descriptors
VkDescriptorSetLayout descriptorsetlayout ;
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = { } ;
VkDescriptorSetLayoutCreateInfo descriptorsetlayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorsetlayoutCI , nullptr , & descriptorsetlayout ) ) ;
// Descriptor Pool
std : : vector < VkDescriptorPoolSize > poolSizes = { vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 ) } ;
VkDescriptorPoolCreateInfo descriptorPoolCI = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
VkDescriptorPool descriptorpool ;
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolCI , nullptr , & descriptorpool ) ) ;
// Descriptor sets
VkDescriptorSet descriptorset ;
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorpool , & descriptorsetlayout , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorset ) ) ;
// Pipeline layout
VkPipelineLayout pipelinelayout ;
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorsetlayout , 1 ) ;
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelinelayout ) ) ;
// Pipeline
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_NONE , VK_FRONT_FACE_COUNTER_CLOCKWISE ) ;
VkPipelineColorBlendAttachmentState blendAttachmentState = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_FALSE , VK_FALSE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportState = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 ) ;
VkPipelineMultisampleStateCreateInfo multisampleState = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT ) ;
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicState = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
VkPipelineVertexInputStateCreateInfo emptyInputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelinelayout , renderpass ) ;
pipelineCI . pInputAssemblyState = & inputAssemblyState ;
pipelineCI . pRasterizationState = & rasterizationState ;
pipelineCI . pColorBlendState = & colorBlendState ;
pipelineCI . pMultisampleState = & multisampleState ;
pipelineCI . pViewportState = & viewportState ;
pipelineCI . pDepthStencilState = & depthStencilState ;
pipelineCI . pDynamicState = & dynamicState ;
pipelineCI . stageCount = 2 ;
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . pVertexInputState = & emptyInputState ;
// Look-up-table (from BRDF) pipeline
shaderStages [ 0 ] = loadShader ( getHomeworkShadersPath ( ) + " homework1/genbrdflut.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getHomeworkShadersPath ( ) + " homework1/genbrdflut.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
VkPipeline pipeline ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
// Render
VkClearValue clearValues [ 1 ] ;
clearValues [ 0 ] . color = { { 0.0f , 0.0f , 0.0f , 1.0f } } ;
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
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 ) ;
VkViewport viewport = vks : : initializers : : viewport ( ( float ) dim , ( float ) dim , 0.0f , 1.0f ) ;
VkRect2D scissor = vks : : initializers : : rect2D ( dim , dim , 0 , 0 ) ;
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 ) ;
vkDestroyDescriptorPool ( device , descriptorpool , nullptr ) ;
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 ;
}
//-------------------------- pbr precompute start ----------------------------------
2023-05-23 11:30:21 +08:00
# pragma region pbr render pass setting
void VulkanExample : : createAttachment ( VkFormat format , VkImageUsageFlagBits usage , VulkanExample : : FrameBufferAttachment * attachment , uint32_t width , uint32_t height )
{
VkImageAspectFlags aspectMask = 0 ;
VkImageUsageFlags imageUsage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT ;
attachment - > format = format ;
if ( usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT )
{
aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
imageUsage | = VK_IMAGE_USAGE_SAMPLED_BIT ;
}
if ( usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT )
{
aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT ;
if ( format > = VK_FORMAT_D16_UNORM_S8_UINT )
aspectMask | = VK_IMAGE_ASPECT_STENCIL_BIT ;
}
assert ( aspectMask > 0 ) ;
VkImageCreateInfo image = vks : : initializers : : imageCreateInfo ( ) ;
image . imageType = VK_IMAGE_TYPE_2D ;
image . format = format ;
image . extent . width = width ;
image . extent . height = height ;
image . extent . depth = 1 ;
image . mipLevels = 1 ;
image . arrayLayers = 1 ;
image . samples = VK_SAMPLE_COUNT_1_BIT ;
image . tiling = VK_IMAGE_TILING_OPTIMAL ;
image . usage = imageUsage | usage ;
VkMemoryAllocateInfo memAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
VkMemoryRequirements memReqs ;
VK_CHECK_RESULT ( vkCreateImage ( device , & image , nullptr , & attachment - > image ) ) ;
vkGetImageMemoryRequirements ( device , attachment - > image , & memReqs ) ;
memAlloc . allocationSize = memReqs . size ;
memAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAlloc , nullptr , & attachment - > deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , attachment - > image , attachment - > deviceMemory , 0 ) ) ;
VkImageViewCreateInfo imageView = vks : : initializers : : imageViewCreateInfo ( ) ;
imageView . viewType = VK_IMAGE_VIEW_TYPE_2D ;
imageView . format = format ;
imageView . subresourceRange = { } ;
imageView . subresourceRange . aspectMask = aspectMask ;
imageView . subresourceRange . baseMipLevel = 0 ;
imageView . subresourceRange . levelCount = 1 ;
imageView . subresourceRange . baseArrayLayer = 0 ;
imageView . subresourceRange . layerCount = 1 ;
imageView . image = attachment - > image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & imageView , nullptr , & attachment - > imageView ) ) ;
}
# pragma endregion
2023-05-24 11:12:54 +08:00
// ----------------------- pbr precompute end ---------------------------------------
2023-05-23 11:30:21 +08:00
2023-05-24 11:12:54 +08:00
2023-05-17 14:49:05 +08:00
void VulkanExample : : prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
loadAssets ( ) ;
2023-05-24 16:10:36 +08:00
generateBRDFLUT ( ) ;
generateIrradianceCubemap ( ) ;
generatePrefilteredCubemap ( ) ;
2023-05-17 14:49:05 +08:00
prepareUniformBuffers ( ) ;
setupDescriptors ( ) ;
preparePipelines ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
void VulkanExample : : render ( )
{
renderFrame ( ) ;
if ( camera . updated ) {
updateUniformBuffers ( ) ;
}
if ( ! paused )
{
2023-05-22 11:21:13 +08:00
glTFModel . updateAnimation ( frameTimer , shaderData . skinSSBO ) ;
2023-05-17 14:49:05 +08:00
}
}
void VulkanExample : : viewChanged ( )
{
updateUniformBuffers ( ) ;
}
void VulkanExample : : OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
{
if ( overlay - > header ( " Settings " ) ) {
if ( overlay - > checkBox ( " Wireframe " , & wireframe ) ) {
buildCommandBuffers ( ) ;
}
}
2023-05-18 11:49:09 +08:00
if ( overlay - > header ( " Animation " ) )
{
overlay - > checkBox ( " pause " , & paused ) ;
}
2023-05-17 14:49:05 +08:00
}
VULKAN_EXAMPLE_MAIN ( )