2016-02-16 15:07:25 +01:00
/*
* Vulkan Example - Cube map texture loading and displaying
*
* Copyright ( C ) 2016 by Sascha Willems - www . saschawillems . de
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <vector>
# define GLM_FORCE_RADIANS
2016-03-08 21:52:40 +01:00
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
2016-02-16 15:07:25 +01:00
# include <glm/glm.hpp>
# include <glm/gtc/matrix_transform.hpp>
# include <vulkan/vulkan.h>
# include "vulkanexamplebase.h"
2020-07-28 20:20:38 +02:00
# include "VulkanglTFModel.h"
2019-08-03 10:00:29 +02:00
# include <ktx.h>
# include <ktxvulkan.h>
2016-02-16 15:07:25 +01:00
# define ENABLE_VALIDATION false
class VulkanExample : public VulkanExampleBase
{
public :
2016-06-04 11:03:17 +02:00
bool displaySkybox = true ;
2017-02-09 21:55:35 +01:00
vks : : Texture cubeMap ;
2016-02-16 15:07:25 +01:00
2016-12-24 12:48:01 +01:00
struct Meshes {
2020-07-28 20:20:38 +02:00
vkglTF : : Model skybox ;
std : : vector < vkglTF : : Model > objects ;
2017-11-01 14:22:10 +01:00
int32_t objectIndex = 0 ;
2017-02-11 14:18:24 +01:00
} models ;
2016-02-16 15:07:25 +01:00
struct {
2017-02-12 10:44:51 +01:00
vks : : Buffer object ;
vks : : Buffer skybox ;
2016-12-24 12:48:01 +01:00
} uniformBuffers ;
2016-02-16 15:07:25 +01:00
2016-12-24 12:48:01 +01:00
struct UBOVS {
2016-02-16 15:07:25 +01:00
glm : : mat4 projection ;
2020-04-22 20:58:24 +02:00
glm : : mat4 modelView ;
2020-05-21 15:34:09 +01:00
glm : : mat4 inverseModelview ;
2016-06-04 13:25:40 +02:00
float lodBias = 0.0f ;
2016-02-16 15:07:25 +01:00
} uboVS ;
struct {
VkPipeline skybox ;
VkPipeline reflect ;
} pipelines ;
struct {
VkDescriptorSet object ;
VkDescriptorSet skybox ;
} descriptorSets ;
VkPipelineLayout pipelineLayout ;
VkDescriptorSetLayout descriptorSetLayout ;
2017-11-01 14:22:10 +01:00
std : : vector < std : : string > objectNames ;
2016-02-16 15:07:25 +01:00
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
2017-11-01 14:22:10 +01:00
title = " Cube map textures " ;
2020-04-22 20:58:24 +02:00
camera . type = Camera : : CameraType : : lookat ;
camera . setPosition ( glm : : vec3 ( 0.0f , 0.0f , - 4.0f ) ) ;
2020-07-28 20:20:38 +02:00
camera . setRotation ( glm : : vec3 ( 0.0f ) ) ;
2020-04-22 20:58:24 +02:00
camera . setRotationSpeed ( 0.25f ) ;
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2017-11-01 14:22:10 +01:00
settings . overlay = true ;
2016-02-16 15:07:25 +01:00
}
~ VulkanExample ( )
{
2020-01-10 13:28:56 +01:00
// Clean up used Vulkan resources
2016-02-16 15:07:25 +01:00
// Note : Inherited destructor cleans up resources stored in base class
// Clean up texture resources
vkDestroyImageView ( device , cubeMap . view , nullptr ) ;
vkDestroyImage ( device , cubeMap . image , nullptr ) ;
vkDestroySampler ( device , cubeMap . sampler , nullptr ) ;
vkFreeMemory ( device , cubeMap . deviceMemory , nullptr ) ;
vkDestroyPipeline ( device , pipelines . skybox , nullptr ) ;
vkDestroyPipeline ( device , pipelines . reflect , nullptr ) ;
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
2016-12-24 12:48:01 +01:00
uniformBuffers . object . destroy ( ) ;
uniformBuffers . skybox . destroy ( ) ;
2016-02-16 15:07:25 +01:00
}
2016-03-25 15:29:38 +01:00
void loadCubemap ( std : : string filename , VkFormat format , bool forceLinearTiling )
2016-02-16 15:07:25 +01:00
{
2019-08-03 10:00:29 +02:00
ktxResult result ;
ktxTexture * ktxTexture ;
2016-03-25 15:29:38 +01:00
# if defined(__ANDROID__)
// Textures are stored inside the apk on Android (compressed)
// So they need to be loaded via the asset manager
AAsset * asset = AAssetManager_open ( androidApp - > activity - > assetManager , filename . c_str ( ) , AASSET_MODE_STREAMING ) ;
2019-08-03 10:00:29 +02:00
if ( ! asset ) {
vks : : tools : : exitFatal ( " Could not load texture from " + filename + " \n \n The file may be part of the additional asset pack. \n \n Run \" download_assets.py \" in the repository root to download the latest version. " , - 1 ) ;
}
2016-03-25 15:29:38 +01:00
size_t size = AAsset_getLength ( asset ) ;
assert ( size > 0 ) ;
2019-08-03 18:20:27 +02:00
ktx_uint8_t * textureData = new ktx_uint8_t [ size ] ;
2016-03-25 15:29:38 +01:00
AAsset_read ( asset , textureData , size ) ;
AAsset_close ( asset ) ;
2019-08-03 18:20:27 +02:00
result = ktxTexture_CreateFromMemory ( textureData , size , KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT , & ktxTexture ) ;
delete [ ] textureData ;
2019-08-03 10:00:29 +02:00
# else
if ( ! vks : : tools : : fileExists ( filename ) ) {
vks : : tools : : exitFatal ( " Could not load texture from " + filename + " \n \n The file may be part of the additional asset pack. \n \n Run \" download_assets.py \" in the repository root to download the latest version. " , - 1 ) ;
}
result = ktxTexture_CreateFromNamedFile ( filename . c_str ( ) , KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT , & ktxTexture ) ;
2020-01-10 13:28:56 +01:00
# endif
2019-08-03 10:00:29 +02:00
assert ( result = = KTX_SUCCESS ) ;
2016-02-16 15:07:25 +01:00
2019-08-03 10:00:29 +02:00
// Get properties required for using and upload texture data from the ktx texture object
cubeMap . width = ktxTexture - > baseWidth ;
cubeMap . height = ktxTexture - > baseHeight ;
cubeMap . mipLevels = ktxTexture - > numLevels ;
ktx_uint8_t * ktxTextureData = ktxTexture_GetData ( ktxTexture ) ;
ktx_size_t ktxTextureSize = ktxTexture_GetSize ( ktxTexture ) ;
2016-02-16 15:07:25 +01:00
2017-02-12 11:12:42 +01:00
VkMemoryAllocateInfo memAllocInfo = vks : : initializers : : memoryAllocateInfo ( ) ;
2016-02-16 15:07:25 +01:00
VkMemoryRequirements memReqs ;
2016-05-14 11:46:56 +02:00
// Create a host-visible staging buffer that contains the raw image data
VkBuffer stagingBuffer ;
VkDeviceMemory stagingMemory ;
2017-02-12 11:12:42 +01:00
VkBufferCreateInfo bufferCreateInfo = vks : : initializers : : bufferCreateInfo ( ) ;
2019-08-03 10:00:29 +02:00
bufferCreateInfo . size = ktxTextureSize ;
2016-05-14 11:46:56 +02:00
// This buffer is used as a transfer source for the buffer copy
bufferCreateInfo . usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT ;
bufferCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
2016-02-16 15:07:25 +01:00
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkCreateBuffer ( device , & bufferCreateInfo , nullptr , & stagingBuffer ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 11:46:56 +02:00
// Get memory requirements for the staging buffer (alignment, memory type bits)
vkGetBufferMemoryRequirements ( device , stagingBuffer , & memReqs ) ;
memAllocInfo . allocationSize = memReqs . size ;
// Get memory type index for a host visible buffer
2017-03-04 13:56:09 +01:00
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ) ;
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & stagingMemory ) ) ;
VK_CHECK_RESULT ( vkBindBufferMemory ( device , stagingBuffer , stagingMemory , 0 ) ) ;
2016-05-14 11:46:56 +02:00
// Copy texture data into staging buffer
uint8_t * data ;
2016-05-30 20:57:38 +02:00
VK_CHECK_RESULT ( vkMapMemory ( device , stagingMemory , 0 , memReqs . size , 0 , ( void * * ) & data ) ) ;
2019-08-03 10:00:29 +02:00
memcpy ( data , ktxTextureData , ktxTextureSize ) ;
2016-05-14 11:46:56 +02:00
vkUnmapMemory ( device , stagingMemory ) ;
// Create optimal tiled target image
2017-02-12 11:12:42 +01:00
VkImageCreateInfo imageCreateInfo = vks : : initializers : : imageCreateInfo ( ) ;
2016-05-14 11:46:56 +02:00
imageCreateInfo . imageType = VK_IMAGE_TYPE_2D ;
imageCreateInfo . format = format ;
2016-06-04 11:31:22 +02:00
imageCreateInfo . mipLevels = cubeMap . mipLevels ;
2016-05-14 11:46:56 +02:00
imageCreateInfo . samples = VK_SAMPLE_COUNT_1_BIT ;
2016-02-16 15:07:25 +01:00
imageCreateInfo . tiling = VK_IMAGE_TILING_OPTIMAL ;
2016-05-14 11:46:56 +02:00
imageCreateInfo . sharingMode = VK_SHARING_MODE_EXCLUSIVE ;
2016-06-22 20:30:14 +02:00
imageCreateInfo . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ;
2016-05-14 11:46:56 +02:00
imageCreateInfo . extent = { cubeMap . width , cubeMap . height , 1 } ;
2016-02-16 15:07:25 +01:00
imageCreateInfo . usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ;
2016-05-14 11:46:56 +02:00
// Cube faces count as array layers in Vulkan
2016-02-16 15:07:25 +01:00
imageCreateInfo . arrayLayers = 6 ;
2016-05-14 11:46:56 +02:00
// This flag is required for cube map images
imageCreateInfo . flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT ;
2016-02-16 15:07:25 +01:00
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkCreateImage ( device , & imageCreateInfo , nullptr , & cubeMap . image ) ) ;
2016-02-16 15:07:25 +01:00
vkGetImageMemoryRequirements ( device , cubeMap . image , & memReqs ) ;
memAllocInfo . allocationSize = memReqs . size ;
2016-07-23 20:42:03 +02:00
memAllocInfo . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAllocInfo , nullptr , & cubeMap . deviceMemory ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , cubeMap . image , cubeMap . deviceMemory , 0 ) ) ;
2016-02-16 15:07:25 +01:00
2020-04-20 22:13:51 +02:00
VkCommandBuffer copyCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
2016-03-13 14:03:45 +01:00
2020-01-12 12:54:41 +01:00
// Setup buffer copy regions for each face including all of its miplevels
2016-06-04 11:31:22 +02:00
std : : vector < VkBufferImageCopy > bufferCopyRegions ;
uint32_t offset = 0 ;
for ( uint32_t face = 0 ; face < 6 ; face + + )
{
for ( uint32_t level = 0 ; level < cubeMap . mipLevels ; level + + )
{
2019-08-03 10:00:29 +02:00
// Calculate offset into staging buffer for the current mip level and face
ktx_size_t offset ;
2020-01-10 13:28:56 +01:00
KTX_error_code ret = ktxTexture_GetImageOffset ( ktxTexture , level , 0 , face , & offset ) ;
assert ( ret = = KTX_SUCCESS ) ;
2016-06-04 11:31:22 +02:00
VkBufferImageCopy bufferCopyRegion = { } ;
bufferCopyRegion . imageSubresource . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
bufferCopyRegion . imageSubresource . mipLevel = level ;
bufferCopyRegion . imageSubresource . baseArrayLayer = face ;
bufferCopyRegion . imageSubresource . layerCount = 1 ;
2019-08-03 10:00:29 +02:00
bufferCopyRegion . imageExtent . width = ktxTexture - > baseWidth > > level ;
bufferCopyRegion . imageExtent . height = ktxTexture - > baseHeight > > level ;
2016-06-04 11:31:22 +02:00
bufferCopyRegion . imageExtent . depth = 1 ;
bufferCopyRegion . bufferOffset = offset ;
bufferCopyRegions . push_back ( bufferCopyRegion ) ;
}
}
2016-05-14 11:46:56 +02:00
// Image barrier for optimal image (target)
// Set initial layout for all array layers (faces) of the optimal (target) tiled texture
2016-03-13 14:03:45 +01:00
VkImageSubresourceRange subresourceRange = { } ;
subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ;
subresourceRange . baseMipLevel = 0 ;
2016-06-04 11:31:22 +02:00
subresourceRange . levelCount = cubeMap . mipLevels ;
2016-03-13 14:03:45 +01:00
subresourceRange . layerCount = 6 ;
2017-02-12 13:10:05 +01:00
vks : : tools : : setImageLayout (
2016-05-14 11:46:56 +02:00
copyCmd ,
2016-02-16 15:07:25 +01:00
cubeMap . image ,
2016-06-22 20:30:14 +02:00
VK_IMAGE_LAYOUT_UNDEFINED ,
2016-03-13 14:03:45 +01:00
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
subresourceRange ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 11:46:56 +02:00
// Copy the cube map faces from the staging buffer to the optimal tiled image
vkCmdCopyBufferToImage (
copyCmd ,
stagingBuffer ,
cubeMap . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
2016-06-04 11:31:22 +02:00
static_cast < uint32_t > ( bufferCopyRegions . size ( ) ) ,
bufferCopyRegions . data ( )
2016-05-14 11:46:56 +02:00
) ;
2016-02-16 15:07:25 +01:00
2016-03-13 14:03:45 +01:00
// Change texture image layout to shader read after all faces have been copied
cubeMap . imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL ;
2017-02-12 13:10:05 +01:00
vks : : tools : : setImageLayout (
2016-05-14 11:46:56 +02:00
copyCmd ,
2016-03-13 14:03:45 +01:00
cubeMap . image ,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL ,
cubeMap . imageLayout ,
subresourceRange ) ;
2020-04-20 22:13:51 +02:00
vulkanDevice - > flushCommandBuffer ( copyCmd , queue , true ) ;
2016-02-16 15:07:25 +01:00
// Create sampler
2017-02-12 11:12:42 +01:00
VkSamplerCreateInfo sampler = vks : : initializers : : samplerCreateInfo ( ) ;
2016-02-16 15:07:25 +01:00
sampler . magFilter = VK_FILTER_LINEAR ;
sampler . minFilter = VK_FILTER_LINEAR ;
sampler . mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR ;
sampler . addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE ;
sampler . addressModeV = sampler . addressModeU ;
sampler . addressModeW = sampler . addressModeU ;
sampler . mipLodBias = 0.0f ;
sampler . compareOp = VK_COMPARE_OP_NEVER ;
sampler . minLod = 0.0f ;
2016-06-04 11:31:22 +02:00
sampler . maxLod = cubeMap . mipLevels ;
2016-02-16 15:07:25 +01:00
sampler . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
2016-09-17 10:31:04 +02:00
sampler . maxAnisotropy = 1.0f ;
if ( vulkanDevice - > features . samplerAnisotropy )
{
sampler . maxAnisotropy = vulkanDevice - > properties . limits . maxSamplerAnisotropy ;
sampler . anisotropyEnable = VK_TRUE ;
}
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkCreateSampler ( device , & sampler , nullptr , & cubeMap . sampler ) ) ;
2016-02-16 15:07:25 +01:00
// Create image view
2017-02-12 11:12:42 +01:00
VkImageViewCreateInfo view = vks : : initializers : : imageViewCreateInfo ( ) ;
2016-05-14 11:46:56 +02:00
// Cube map view type
2016-02-16 15:07:25 +01:00
view . viewType = VK_IMAGE_VIEW_TYPE_CUBE ;
view . format = format ;
view . components = { VK_COMPONENT_SWIZZLE_R , VK_COMPONENT_SWIZZLE_G , VK_COMPONENT_SWIZZLE_B , VK_COMPONENT_SWIZZLE_A } ;
view . subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT , 0 , 1 , 0 , 1 } ;
2016-05-14 11:46:56 +02:00
// 6 array layers (faces)
2016-02-16 15:07:25 +01:00
view . subresourceRange . layerCount = 6 ;
2016-06-04 11:31:22 +02:00
// Set number of mip levels
view . subresourceRange . levelCount = cubeMap . mipLevels ;
2016-02-16 15:07:25 +01:00
view . image = cubeMap . image ;
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkCreateImageView ( device , & view , nullptr , & cubeMap . view ) ) ;
2016-02-16 15:07:25 +01:00
2016-05-14 11:46:56 +02:00
// Clean up staging resources
vkFreeMemory ( device , stagingMemory , nullptr ) ;
vkDestroyBuffer ( device , stagingBuffer , nullptr ) ;
2019-08-03 10:00:29 +02:00
ktxTexture_Destroy ( ktxTexture ) ;
2016-02-16 15:07:25 +01:00
}
void buildCommandBuffers ( )
{
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-02-16 15:07:25 +01:00
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = defaultClearColor ;
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
2017-02-12 11:12:42 +01:00
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
2016-02-16 15:07:25 +01:00
renderPassBeginInfo . renderPass = renderPass ;
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 ;
for ( int32_t i = 0 ; i < drawCmdBuffers . size ( ) ; + + i )
{
// Set target frame buffer
renderPassBeginInfo . framebuffer = frameBuffers [ i ] ;
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
2016-02-16 15:07:25 +01:00
vkCmdBeginRenderPass ( drawCmdBuffers [ i ] , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
2017-02-12 11:12:42 +01:00
VkViewport viewport = vks : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
2016-02-16 15:07:25 +01:00
vkCmdSetViewport ( drawCmdBuffers [ i ] , 0 , 1 , & viewport ) ;
2017-02-12 11:12:42 +01:00
VkRect2D scissor = vks : : initializers : : rect2D ( width , height , 0 , 0 ) ;
2016-02-16 15:07:25 +01:00
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
// Skybox
2016-06-04 11:03:17 +02:00
if ( displaySkybox )
{
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSets . skybox , 0 , NULL ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . skybox ) ;
2020-07-28 20:20:38 +02:00
models . skybox . draw ( drawCmdBuffers [ i ] ) ;
2016-06-04 11:03:17 +02:00
}
2016-02-16 15:07:25 +01:00
// 3D object
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSets . object , 0 , NULL ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . reflect ) ;
2020-07-28 20:20:38 +02:00
models . objects [ models . objectIndex ] . draw ( drawCmdBuffers [ i ] ) ;
2016-02-16 15:07:25 +01:00
2018-08-30 21:08:02 +02:00
drawUI ( drawCmdBuffers [ i ] ) ;
2016-02-16 15:07:25 +01:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
2017-11-01 14:22:10 +01:00
void loadAssets ( )
2016-02-16 15:07:25 +01:00
{
2020-07-28 20:20:38 +02:00
uint32_t glTFLoadingFlags = vkglTF : : FileLoadingFlags : : PreTransformVertices | vkglTF : : FileLoadingFlags : : FlipY ;
2016-06-04 11:03:17 +02:00
// Skybox
2020-07-28 20:20:38 +02:00
models . skybox . loadFromFile ( getAssetPath ( ) + " models/cube.gltf " , vulkanDevice , queue , glTFLoadingFlags ) ;
2016-06-04 11:03:17 +02:00
// Objects
2020-07-28 20:20:38 +02:00
std : : vector < std : : string > filenames = { " sphere.gltf " , " teapot.gltf " , " torusknot.gltf " , " venus.gltf " } ;
2017-11-01 14:22:10 +01:00
objectNames = { " Sphere " , " Teapot " , " Torusknot " , " Venus " } ;
2020-07-28 20:20:38 +02:00
models . objects . resize ( filenames . size ( ) ) ;
for ( size_t i = 0 ; i < filenames . size ( ) ; i + + ) {
models . objects [ i ] . loadFromFile ( getAssetPath ( ) + " models/ " + filenames [ i ] , vulkanDevice , queue , glTFLoadingFlags ) ;
2017-02-11 14:18:24 +01:00
}
2020-07-28 20:20:38 +02:00
// Cubemap texture
const bool forceLinearTiling = false ;
loadCubemap ( getAssetPath ( ) + " textures/cubemap_yokohama_rgba.ktx " , VK_FORMAT_R8G8B8A8_UNORM , forceLinearTiling ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorPool ( )
{
std : : vector < VkDescriptorPoolSize > poolSizes =
{
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 2 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 2 )
2016-02-16 15:07:25 +01:00
} ;
2020-01-10 13:28:56 +01:00
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolCreateInfo (
2016-02-16 15:07:25 +01:00
poolSizes . size ( ) ,
poolSizes . data ( ) ,
2 ) ;
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
2020-01-10 13:28:56 +01:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
2016-02-16 15:07:25 +01:00
{
2020-05-21 15:34:09 +01:00
// Binding 0 : Uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2020-01-10 13:28:56 +01:00
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
2020-05-21 15:34:09 +01:00
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT ,
2016-02-16 15:07:25 +01:00
0 ) ,
// Binding 1 : Fragment shader image sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2020-01-10 13:28:56 +01:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
2016-02-16 15:07:25 +01:00
1 )
} ;
2020-01-10 13:28:56 +01:00
VkDescriptorSetLayoutCreateInfo descriptorLayout =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutCreateInfo (
2016-02-16 15:07:25 +01:00
setLayoutBindings . data ( ) ,
setLayoutBindings . size ( ) ) ;
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-02-16 15:07:25 +01:00
& descriptorSetLayout ,
1 ) ;
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSets ( )
{
// Image descriptor for the cube map texture
2017-01-04 21:49:26 +01:00
VkDescriptorImageInfo textureDescriptor =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorImageInfo (
2016-02-16 15:07:25 +01:00
cubeMap . sampler ,
cubeMap . view ,
2017-01-04 21:49:26 +01:00
cubeMap . imageLayout ) ;
2016-02-16 15:07:25 +01:00
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-02-16 15:07:25 +01:00
descriptorPool ,
& descriptorSetLayout ,
1 ) ;
// 3D object descriptor set
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSets . object ) ) ;
2016-02-16 15:07:25 +01:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets =
{
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2020-01-10 13:28:56 +01:00
descriptorSets . object ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . object . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Fragment shader cubemap sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2020-01-10 13:28:56 +01:00
descriptorSets . object ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
2017-01-04 21:49:26 +01:00
& textureDescriptor )
2016-02-16 15:07:25 +01:00
} ;
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
// Sky box descriptor set
2016-05-14 11:46:56 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSets . skybox ) ) ;
2016-02-16 15:07:25 +01:00
writeDescriptorSets =
{
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-02-16 15:07:25 +01:00
descriptorSets . skybox ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . skybox . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Fragment shader cubemap sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-02-16 15:07:25 +01:00
descriptorSets . skybox ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
2017-01-04 21:49:26 +01:00
& textureDescriptor )
2016-02-16 15:07:25 +01:00
} ;
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
}
void preparePipelines ( )
{
2020-07-28 20:20:38 +02:00
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_BACK_BIT , VK_FRONT_FACE_COUNTER_CLOCKWISE , 0 ) ;
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 , 0 ) ;
VkPipelineMultisampleStateCreateInfo multisampleState = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT , 0 ) ;
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicState = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
2018-02-24 10:37:45 +01:00
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2016-02-16 15:07:25 +01:00
2020-07-28 20:20:38 +02:00
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelineLayout , renderPass , 0 ) ;
pipelineCI . pInputAssemblyState = & inputAssemblyState ;
pipelineCI . pRasterizationState = & rasterizationState ;
pipelineCI . pColorBlendState = & colorBlendState ;
pipelineCI . pMultisampleState = & multisampleState ;
pipelineCI . pViewportState = & viewportState ;
pipelineCI . pDepthStencilState = & depthStencilState ;
pipelineCI . pDynamicState = & dynamicState ;
pipelineCI . stageCount = shaderStages . size ( ) ;
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . pVertexInputState = vkglTF : : Vertex : : getPipelineVertexInputState ( { vkglTF : : VertexComponent : : Position , vkglTF : : VertexComponent : : Normal } ) ;
2016-02-16 15:07:25 +01:00
2018-02-24 10:36:38 +01:00
// Skybox pipeline (background cube)
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " texturecubemap/skybox.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " texturecubemap/skybox.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2020-07-28 20:20:38 +02:00
rasterizationState . cullMode = VK_CULL_MODE_FRONT_BIT ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . skybox ) ) ;
2016-02-16 15:07:25 +01:00
// Cube map reflect pipeline
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " texturecubemap/reflect.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " texturecubemap/reflect.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2016-06-04 11:03:17 +02:00
// Enable depth test and write
2016-02-16 15:07:25 +01:00
depthStencilState . depthWriteEnable = VK_TRUE ;
2016-06-04 11:03:17 +02:00
depthStencilState . depthTestEnable = VK_TRUE ;
2020-07-28 20:20:38 +02:00
rasterizationState . cullMode = VK_CULL_MODE_BACK_BIT ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . reflect ) ) ;
2016-02-16 15:07:25 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
2020-05-21 15:34:09 +01:00
// Object vertex shader uniform buffer
2016-12-24 12:48:01 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-04 11:03:17 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . object ,
sizeof ( uboVS ) ) ) ;
2016-02-16 15:07:25 +01:00
2016-12-24 12:48:01 +01:00
// Skybox vertex shader uniform buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-04 11:03:17 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . skybox ,
sizeof ( uboVS ) ) ) ;
// Map persistent
VK_CHECK_RESULT ( uniformBuffers . object . map ( ) ) ;
VK_CHECK_RESULT ( uniformBuffers . skybox . map ( ) ) ;
2016-06-04 11:03:17 +02:00
updateUniformBuffers ( ) ;
2016-02-16 15:07:25 +01:00
}
void updateUniformBuffers ( )
{
// 3D object
2020-04-22 20:58:24 +02:00
uboVS . projection = camera . matrices . perspective ;
uboVS . modelView = camera . matrices . view ;
2020-05-21 15:34:09 +01:00
uboVS . inverseModelview = glm : : inverse ( camera . matrices . view ) ;
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . object . mapped , & uboVS , sizeof ( uboVS ) ) ;
2016-06-04 11:03:17 +02:00
// Skybox
2020-04-22 20:58:24 +02:00
uboVS . modelView = camera . matrices . view ;
// Cancel out translation
uboVS . modelView [ 3 ] = glm : : vec4 ( 0.0f , 0.0f , 0.0f , 1.0f ) ;
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . skybox . mapped , & uboVS , sizeof ( uboVS ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-06-04 11:03:17 +02:00
void draw ( )
{
VulkanExampleBase : : prepareFrame ( ) ;
submitInfo . commandBufferCount = 1 ;
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
VulkanExampleBase : : submitFrame ( ) ;
}
2016-02-16 15:07:25 +01:00
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2017-11-01 14:22:10 +01:00
loadAssets ( ) ;
2016-02-16 15:07:25 +01:00
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorPool ( ) ;
setupDescriptorSets ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
}
virtual void viewChanged ( )
{
updateUniformBuffers ( ) ;
}
2016-06-04 11:03:17 +02:00
2017-11-01 14:22:10 +01:00
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
2016-06-04 11:03:17 +02:00
{
2017-11-01 14:22:10 +01:00
if ( overlay - > header ( " Settings " ) ) {
if ( overlay - > sliderFloat ( " LOD bias " , & uboVS . lodBias , 0.0f , ( float ) cubeMap . mipLevels ) ) {
updateUniformBuffers ( ) ;
}
if ( overlay - > comboBox ( " Object type " , & models . objectIndex , objectNames ) ) {
buildCommandBuffers ( ) ;
}
if ( overlay - > checkBox ( " Skybox " , & displaySkybox ) ) {
buildCommandBuffers ( ) ;
}
2016-06-04 11:03:17 +02:00
}
}
2016-02-16 15:07:25 +01:00
} ;
2016-12-13 19:25:56 +01:00
VULKAN_EXAMPLE_MAIN ( )