2016-02-16 15:07:25 +01:00
/*
* Vulkan Example - Parallax Mapping
*
* Copyright ( C ) 2016 by Sascha Willems - www . saschawillems . de
*
* 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 ENABLE_VALIDATION false
class VulkanExample : public VulkanExampleBase
{
public :
struct {
2017-02-09 21:55:35 +01:00
vks : : Texture2D colorMap ;
2017-03-24 17:58:25 +01:00
// Normals and height are combined into one texture (height = alpha channel)
2017-02-09 21:55:35 +01:00
vks : : Texture2D normalHeightMap ;
2016-02-16 15:07:25 +01:00
} textures ;
2020-07-28 20:20:38 +02:00
vkglTF : : Model plane ;
2016-02-16 15:07:25 +01:00
struct {
2017-02-12 10:44:51 +01:00
vks : : Buffer vertexShader ;
vks : : Buffer fragmentShader ;
2016-12-24 12:48:01 +01:00
} uniformBuffers ;
2016-02-16 15:07:25 +01:00
struct {
struct {
glm : : mat4 projection ;
2017-03-24 17:58:25 +01:00
glm : : mat4 view ;
2016-02-16 15:07:25 +01:00
glm : : mat4 model ;
2017-03-24 17:58:25 +01:00
glm : : vec4 lightPos = glm : : vec4 ( 0.0f , - 2.0f , 0.0f , 1.0f ) ;
2016-02-16 15:07:25 +01:00
glm : : vec4 cameraPos ;
} vertexShader ;
struct {
2017-03-24 17:58:25 +01:00
float heightScale = 0.1f ;
// Basic parallax mapping needs a bias to look any good (and is hard to tweak)
float parallaxBias = - 0.02f ;
// Number of layers for steep parallax and parallax occlusion (more layer = better result for less performance)
float numLayers = 48.0f ;
// (Parallax) mapping mode to use
int32_t mappingMode = 4 ;
2016-02-16 15:07:25 +01:00
} fragmentShader ;
} ubos ;
VkPipelineLayout pipelineLayout ;
2017-03-24 17:58:25 +01:00
VkPipeline pipeline ;
2016-02-16 15:07:25 +01:00
VkDescriptorSetLayout descriptorSetLayout ;
2017-03-24 17:58:25 +01:00
VkDescriptorSet descriptorSet ;
2016-02-16 15:07:25 +01:00
2017-11-01 14:22:10 +01:00
const std : : vector < std : : string > mappingModes = {
2020-05-29 16:08:53 +01:00
" Color only " ,
" Normal mapping " ,
" Parallax mapping " ,
" Steep parallax mapping " ,
2017-11-01 14:22:10 +01:00
" Parallax occlusion mapping " ,
} ;
2016-02-16 15:07:25 +01:00
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
2017-11-01 14:22:10 +01:00
title = " Parallax Mapping " ;
2017-03-24 17:58:25 +01:00
timerSpeed * = 0.5f ;
camera . type = Camera : : CameraType : : firstperson ;
2020-07-28 20:20:38 +02:00
camera . setPosition ( glm : : vec3 ( 0.0f , 1.25f , - 1.5f ) ) ;
camera . setRotation ( glm : : vec3 ( - 45.0f , 0.0f , 0.0f ) ) ;
2017-03-24 17:58:25 +01:00
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2016-02-16 15:07:25 +01:00
}
~ VulkanExample ( )
{
2017-03-24 17:58:25 +01:00
vkDestroyPipeline ( device , pipeline , nullptr ) ;
2020-05-29 16:08:53 +01:00
2016-02-16 15:07:25 +01:00
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
2016-12-24 12:48:01 +01:00
uniformBuffers . vertexShader . destroy ( ) ;
uniformBuffers . fragmentShader . destroy ( ) ;
2016-02-16 15:07:25 +01:00
2017-02-09 21:55:35 +01:00
textures . colorMap . destroy ( ) ;
textures . normalHeightMap . destroy ( ) ;
2016-02-16 15:07:25 +01:00
}
2017-02-09 21:55:35 +01:00
void loadAssets ( )
2016-02-16 15:07:25 +01:00
{
2020-07-28 20:20:38 +02:00
const uint32_t glTFLoadingFlags = vkglTF : : FileLoadingFlags : : PreTransformVertices | vkglTF : : FileLoadingFlags : : PreMultiplyVertexColors | vkglTF : : FileLoadingFlags : : FlipY ;
plane . loadFromFile ( getAssetPath ( ) + " models/plane.gltf " , vulkanDevice , queue , glTFLoadingFlags ) ;
2019-09-06 19:18:15 +02:00
textures . normalHeightMap . loadFromFile ( getAssetPath ( ) + " textures/rocks_normal_height_rgba.ktx " , VK_FORMAT_R8G8B8A8_UNORM , vulkanDevice , queue ) ;
2020-07-28 20:20:38 +02:00
textures . colorMap . loadFromFile ( getAssetPath ( ) + " textures/rocks_color_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 )
{
// Set target frame buffer
renderPassBeginInfo . framebuffer = frameBuffers [ i ] ;
2016-06-05 20:58:58 +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-03-24 17:58:25 +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 ) ;
2017-03-24 17:58:25 +01:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipeline ) ;
2020-07-28 20:20:38 +02:00
plane . 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-06-05 20:58:58 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-02-16 15:07:25 +01:00
}
}
void setupDescriptorPool ( )
{
// Example uses two ubos and two image sampler
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
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2017-03-24 17:58:25 +01:00
vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , 2 ) ;
2016-02-16 15:07:25 +01:00
2016-06-05 20:58:58 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSetLayout ( )
{
2020-05-29 16:08:53 +01:00
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings = {
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 0 ) , // Binding 0: Vertex shader uniform buffer
2017-03-24 17:58:25 +01:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 1 ) , // Binding 1: Fragment shader color map image sampler
2020-05-29 16:08:53 +01:00
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 2 ) , // Binding 2: Fragment combined normal and heightmap
vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_FRAGMENT_BIT , 3 ) , // Binding 3: Fragment shader uniform buffer
2016-02-16 15:07:25 +01:00
} ;
2020-07-28 20:20:38 +02:00
VkDescriptorSetLayoutCreateInfo descriptorLayout = vks : : initializers : : descriptorSetLayoutCreateInfo ( setLayoutBindings ) ;
2016-06-05 20:58:58 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2016-02-16 15:07:25 +01:00
2020-07-28 20:20:38 +02:00
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = vks : : initializers : : pipelineLayoutCreateInfo ( & descriptorSetLayout , 1 ) ;
2016-06-05 20:58:58 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayout ) ) ;
2016-02-16 15:07:25 +01:00
}
void setupDescriptorSet ( )
{
2020-07-28 20:20:38 +02:00
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayout , 1 ) ;
2016-06-05 20:58:58 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2016-02-16 15:07:25 +01:00
2020-05-29 16:08:53 +01:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets = {
2017-03-24 17:58:25 +01:00
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & uniformBuffers . vertexShader . descriptor ) , // Binding 0: Vertex shader uniform buffer
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 1 , & textures . colorMap . descriptor ) , // Binding 1: Fragment shader image sampler
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 2 , & textures . normalHeightMap . descriptor ) , // Binding 2: Combined normal and heightmap
vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 3 , & uniformBuffers . fragmentShader . descriptor ) , // Binding 3: Fragment shader uniform buffer
2016-02-16 15:07:25 +01:00
} ;
2017-03-24 17:58:25 +01:00
vkUpdateDescriptorSets ( device , static_cast < uint32_t > ( writeDescriptorSets . size ( ) ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
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_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_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 ) ;
std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicState = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables ) ;
2016-02-16 15:07:25 +01:00
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
2020-07-28 20:20:38 +02:00
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 = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
pipelineCI . pStages = shaderStages . data ( ) ;
pipelineCI . pVertexInputState = vkglTF : : Vertex : : getPipelineVertexInputState ( { vkglTF : : VertexComponent : : Position , vkglTF : : VertexComponent : : UV , vkglTF : : VertexComponent : : Normal , vkglTF : : VertexComponent : : Tangent } ) ;
2017-03-24 17:58:25 +01:00
// Parallax mapping modes pipeline
2020-05-29 16:08:53 +01:00
shaderStages [ 0 ] = loadShader ( getShadersPath ( ) + " parallaxmapping/parallax.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getShadersPath ( ) + " parallaxmapping/parallax.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 ( )
{
2016-12-24 12:48:01 +01:00
// 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-05 20:58:58 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . vertexShader ,
sizeof ( ubos . vertexShader ) ) ) ;
// Fragment shader uniform buffer
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-05 20:58:58 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . fragmentShader ,
sizeof ( ubos . fragmentShader ) ) ) ;
// Map persistent
VK_CHECK_RESULT ( uniformBuffers . vertexShader . map ( ) ) ;
VK_CHECK_RESULT ( uniformBuffers . fragmentShader . map ( ) ) ;
2016-02-16 15:07:25 +01:00
updateUniformBuffers ( ) ;
}
void updateUniformBuffers ( )
{
// Vertex shader
2017-03-24 17:58:25 +01:00
ubos . vertexShader . projection = camera . matrices . perspective ;
ubos . vertexShader . view = camera . matrices . view ;
2020-07-28 20:20:38 +02:00
ubos . vertexShader . model = glm : : scale ( glm : : mat4 ( 1.0f ) , glm : : vec3 ( 0.2f ) ) ;
2017-03-24 17:58:25 +01:00
if ( ! paused ) {
ubos . vertexShader . lightPos . x = sin ( glm : : radians ( timer * 360.0f ) ) * 1.5f ;
ubos . vertexShader . lightPos . z = cos ( glm : : radians ( timer * 360.0f ) ) * 1.5f ;
2016-02-16 15:07:25 +01:00
}
2017-03-24 17:58:25 +01:00
ubos . vertexShader . cameraPos = glm : : vec4 ( camera . position , - 1.0f ) * - 1.0f ;
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . vertexShader . mapped , & ubos . vertexShader , sizeof ( ubos . vertexShader ) ) ;
2016-02-16 15:07:25 +01:00
// Fragment shader
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . fragmentShader . mapped , & ubos . fragmentShader , sizeof ( ubos . fragmentShader ) ) ;
2016-02-16 15:07:25 +01:00
}
2016-06-05 20:58:58 +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-09 21:55:35 +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 ( ! paused | | camera . updated )
2016-02-16 15:07:25 +01:00
{
updateUniformBuffers ( ) ;
}
}
2017-11-01 14:22:10 +01:00
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
2016-06-05 20:58:58 +02:00
{
2017-11-01 14:22:10 +01:00
if ( overlay - > header ( " Settings " ) ) {
if ( overlay - > comboBox ( " Mode " , & ubos . fragmentShader . mappingMode , mappingModes ) ) {
updateUniformBuffers ( ) ;
}
2016-06-05 20:58:58 +02:00
}
}
2016-02-16 15:07:25 +01:00
} ;
2016-12-13 19:25:56 +01:00
VULKAN_EXAMPLE_MAIN ( )