2016-02-16 15:07:25 +01:00
/*
2016-03-02 21:15:00 +01:00
* Vulkan Example - Spherical Environment Mapping , using different mat caps
2016-02-16 15:07:25 +01:00
*
2016-03-06 20:15:05 +01:00
* Use + / - / space toggle through different material captures
*
2016-02-16 15:07:25 +01:00
* Based on https : //www.clicktorelease.com/blog/creating-spherical-environment-mapping-shader
*
2023-07-16 15:55:58 +02:00
* Copyright ( C ) 2016 - 2023 by Sascha Willems - www . saschawillems . de
2016-02-16 15:07:25 +01:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
# include "vulkanexamplebase.h"
2020-07-28 20:20:38 +02:00
# include "VulkanglTFModel.h"
2016-02-16 15:07:25 +01:00
# define VERTEX_BUFFER_BIND_ID 0
# define ENABLE_VALIDATION false
class VulkanExample : public VulkanExampleBase
{
public :
2020-07-28 20:20:38 +02:00
vkglTF : : Model model ;
vks : : Texture2DArray matCapTextureArray ;
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 ;
glm : : mat4 model ;
glm : : mat4 normal ;
glm : : mat4 view ;
2016-03-02 21:15:00 +01:00
int32_t texIndex = 0 ;
2016-02-16 15:07:25 +01:00
} uboVS ;
2020-07-28 20:20:38 +02:00
vks : : Buffer uniformBuffer ;
2016-02-16 15:07:25 +01:00
2016-12-24 12:48:01 +01:00
VkPipeline pipeline ;
2016-02-16 15:07:25 +01:00
VkPipelineLayout pipelineLayout ;
VkDescriptorSet descriptorSet ;
VkDescriptorSetLayout descriptorSetLayout ;
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
2017-11-01 14:22:10 +01:00
title = " Spherical Environment Mapping " ;
2020-04-22 20:58:24 +02:00
camera . type = Camera : : CameraType : : lookat ;
2020-07-28 20:20:38 +02:00
camera . setPosition ( glm : : vec3 ( 0.0f , 0.0f , - 3.5f ) ) ;
2020-04-22 20:58:24 +02:00
camera . setRotation ( glm : : vec3 ( - 25.0f , 23.75f , 0.0f ) ) ;
camera . setRotationSpeed ( 0.75f ) ;
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2016-02-16 15:07:25 +01:00
}
~ VulkanExample ( )
{
2020-05-29 16:08:53 +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
2016-12-24 12:48:01 +01:00
vkDestroyPipeline ( device , pipeline , nullptr ) ;
2016-02-16 15:07:25 +01:00
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
2016-12-24 12:48:01 +01:00
uniformBuffer . destroy ( ) ;
2020-07-28 20:20:38 +02:00
matCapTextureArray . destroy ( ) ;
2016-02-16 15:07:25 +01:00
}
2017-02-11 14:18:24 +01:00
void loadAssets ( )
2016-02-16 15:07:25 +01:00
{
2020-07-28 20:20:38 +02:00
model . loadFromFile ( getAssetPath ( ) + " models/chinesedragon.gltf " , vulkanDevice , queue , vkglTF : : FileLoadingFlags : : PreTransformVertices | vkglTF : : FileLoadingFlags : : PreMultiplyVertexColors | vkglTF : : FileLoadingFlags : : FlipY ) ;
2017-02-11 14:18:24 +01:00
// Multiple mat caps are stored in a single texture array so they can easily be switched inside the shader just by updating the index in a uniform buffer
2020-07-28 20:20:38 +02:00
matCapTextureArray . loadFromFile ( getAssetPath ( ) + " textures/matcap_array_rgba.ktx " , VK_FORMAT_R8G8B8A8_UNORM , vulkanDevice , queue ) ;
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 )
{
renderPassBeginInfo . framebuffer = frameBuffers [ i ] ;
2016-05-15 11:20:44 +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 ) ;
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSet , 0 , NULL ) ;
2016-12-24 12:48:01 +01:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
2016-02-16 15:07:25 +01:00
2020-07-28 20:20:38 +02:00
model . 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-15 11:20:44 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
void setupDescriptorPool ( )
{
// Example uses one ubo and one image sampler
std : : vector < VkDescriptorPoolSize > poolSizes =
{
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 )
2016-02-16 15:07:25 +01:00
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2023-07-16 15:55:58 +02:00
vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
2016-02-16 15:07:25 +01:00
2016-05-15 11:20:44 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
{
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
VK_SHADER_STAGE_VERTEX_BIT ,
0 ) ,
// Binding 1 : Fragment shader color map image sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-02-16 15:07:25 +01:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
1 )
} ;
VkDescriptorSetLayoutCreateInfo descriptorLayout =
2023-07-16 15:55:58 +02:00
vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
2016-02-16 15:07:25 +01:00
2016-05-15 11:20:44 +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-15 11:20:44 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSet ( )
{
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-02-16 15:07:25 +01:00
descriptorPool ,
& descriptorSetLayout ,
1 ) ;
2016-05-15 11:20:44 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
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 (
2016-02-16 15:07:25 +01:00
descriptorSet ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-12-24 12:48:01 +01:00
& uniformBuffer . descriptor ) ,
2016-02-16 15:07:25 +01:00
// Binding 1 : Fragment shader image sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-02-16 15:07:25 +01:00
descriptorSet ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
2020-07-28 20:20:38 +02:00
& matCapTextureArray . descriptor )
2016-02-16 15:07:25 +01:00
} ;
2023-07-16 15:55:58 +02:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , nullptr ) ;
2016-02-16 15:07:25 +01:00
}
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_TRUE , VK_TRUE , 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 . data ( ) , dynamicStateEnables . size ( ) , 0 ) ;
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 ;
2023-07-16 15:55:58 +02:00
pipelineCI . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
2020-07-28 20:20:38 +02:00
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . pVertexInputState = vkglTF : : Vertex : : getPipelineVertexInputState ( { vkglTF : : VertexComponent : : Position , vkglTF : : VertexComponent : : Normal , vkglTF : : VertexComponent : : Color } ) ;
2016-02-16 15:07:25 +01:00
// Spherical environment rendering pipeline
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " sphericalenvmapping/sem.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " sphericalenvmapping/sem.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2020-07-28 20:20:38 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipeline ) ) ;
2016-02-16 15:07:25 +01:00
}
void prepareUniformBuffers ( )
{
// Vertex shader uniform buffer block
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-05-20 21:30:17 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffer ,
sizeof ( uboVS ) ) ) ;
// Map persistent
VK_CHECK_RESULT ( uniformBuffer . map ( ) ) ;
2016-02-16 15:07:25 +01:00
updateUniformBuffers ( ) ;
}
void updateUniformBuffers ( )
{
2020-04-22 20:58:24 +02:00
uboVS . projection = camera . matrices . perspective ;
uboVS . view = camera . matrices . view ;
2017-09-24 18:17:07 +02:00
uboVS . model = glm : : mat4 ( 1.0f ) ;
2016-02-16 15:07:25 +01:00
uboVS . normal = glm : : inverseTranspose ( uboVS . view * uboVS . model ) ;
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffer . mapped , & uboVS , sizeof ( uboVS ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-05-20 21:30: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-02-11 14:18:24 +01:00
loadAssets ( ) ;
2016-02-16 15:07:25 +01:00
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorPool ( ) ;
setupDescriptorSet ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
2020-07-28 20:20:38 +02:00
if ( camera . updated ) {
updateUniformBuffers ( ) ;
}
2016-02-16 15:07:25 +01:00
}
2022-06-13 23:04:53 -04:00
virtual void viewChanged ( )
{
updateUniformBuffers ( ) ;
}
2017-11-01 14:22:10 +01:00
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
2016-03-06 20:15:05 +01:00
{
2017-11-01 14:22:10 +01:00
if ( overlay - > header ( " Settings " ) ) {
2020-07-28 20:20:38 +02:00
if ( overlay - > sliderInt ( " Material cap " , & uboVS . texIndex , 0 , matCapTextureArray . layerCount ) ) {
2017-11-01 14:22:10 +01:00
updateUniformBuffers ( ) ;
}
2016-03-06 20:15:05 +01:00
}
}
2016-02-16 15:07:25 +01:00
} ;
2022-06-13 23:04:53 -04:00
VULKAN_EXAMPLE_MAIN ( )