2016-03-08 21:52:40 +01:00
/*
2016-06-05 15:44:04 +02:00
* Vulkan Example - Shadow mapping for directional light sources
2016-03-08 21:52:40 +01:00
*
* 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
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
# include <glm/glm.hpp>
# include <glm/gtc/matrix_transform.hpp>
# include <vulkan/vulkan.h>
# include "vulkanexamplebase.h"
2017-02-12 10:44:51 +01:00
# include "VulkanBuffer.hpp"
2017-02-11 14:23:28 +01:00
# include "VulkanModel.hpp"
2016-03-08 21:52:40 +01:00
# define VERTEX_BUFFER_BIND_ID 0
# define ENABLE_VALIDATION false
// 16 bits of depth is enough for such a small scene
# define DEPTH_FORMAT VK_FORMAT_D16_UNORM
2016-06-05 15:44:04 +02:00
// Shadowmap properties
# if defined(__ANDROID__)
# define SHADOWMAP_DIM 1024
# else
# define SHADOWMAP_DIM 2048
# endif
# define SHADOWMAP_FILTER VK_FILTER_LINEAR
2016-03-08 21:52:40 +01:00
// Offscreen frame buffer properties
# define FB_COLOR_FORMAT VK_FORMAT_R8G8B8A8_UNORM
class VulkanExample : public VulkanExampleBase
{
public :
2016-03-25 15:29:38 +01:00
bool displayShadowMap = false ;
2017-01-07 20:20:40 +01:00
bool filterPCF = true ;
2016-03-08 21:52:40 +01:00
// Keep depth range as small as possible
// for better shadow map precision
float zNear = 1.0f ;
float zFar = 96.0f ;
2016-06-05 15:44:04 +02:00
// Depth bias (and slope) are used to avoid shadowing artefacts
2016-03-08 21:52:40 +01:00
// Constant depth bias factor (always applied)
float depthBiasConstant = 1.25f ;
// Slope depth bias factor, applied depending on polygon's slope
float depthBiasSlope = 1.75f ;
glm : : vec3 lightPos = glm : : vec3 ( ) ;
float lightFOV = 45.0f ;
2017-02-11 14:18:24 +01:00
// Vertex layout for the models
vks : : VertexLayout vertexLayout = vks : : VertexLayout ( {
vks : : VERTEX_COMPONENT_POSITION ,
vks : : VERTEX_COMPONENT_UV ,
vks : : VERTEX_COMPONENT_COLOR ,
vks : : VERTEX_COMPONENT_NORMAL ,
} ) ;
2016-03-08 21:52:40 +01:00
struct {
2017-02-11 14:18:24 +01:00
vks : : Model quad ;
} models ;
2016-03-08 21:52:40 +01:00
2017-11-04 21:23:37 +01:00
std : : vector < vks : : Model > scenes ;
std : : vector < std : : string > sceneNames ;
int32_t sceneIndex = 0 ;
2016-03-08 21:52:40 +01:00
struct {
VkPipelineVertexInputStateCreateInfo inputState ;
std : : vector < VkVertexInputBindingDescription > bindingDescriptions ;
std : : vector < VkVertexInputAttributeDescription > attributeDescriptions ;
} vertices ;
struct {
2017-02-12 10:44:51 +01:00
vks : : Buffer scene ;
vks : : Buffer offscreen ;
vks : : Buffer debug ;
2016-12-24 12:48:01 +01:00
} uniformBuffers ;
2016-03-08 21:52:40 +01:00
struct {
glm : : mat4 projection ;
glm : : mat4 model ;
} uboVSquad ;
struct {
glm : : mat4 projection ;
glm : : mat4 view ;
glm : : mat4 model ;
glm : : mat4 depthBiasMVP ;
glm : : vec3 lightPos ;
} uboVSscene ;
struct {
glm : : mat4 depthMVP ;
} uboOffscreenVS ;
struct {
VkPipeline quad ;
VkPipeline offscreen ;
2017-01-07 20:20:40 +01:00
VkPipeline sceneShadow ;
VkPipeline sceneShadowPCF ;
2016-03-08 21:52:40 +01:00
} pipelines ;
struct {
VkPipelineLayout quad ;
VkPipelineLayout offscreen ;
} pipelineLayouts ;
struct {
VkDescriptorSet offscreen ;
VkDescriptorSet scene ;
} descriptorSets ;
VkDescriptorSet descriptorSet ;
VkDescriptorSetLayout descriptorSetLayout ;
// Framebuffer for offscreen rendering
struct FrameBufferAttachment {
VkImage image ;
VkDeviceMemory mem ;
VkImageView view ;
} ;
2016-08-13 19:31:41 +02:00
struct OffscreenPass {
2016-03-08 21:52:40 +01:00
int32_t width , height ;
VkFramebuffer frameBuffer ;
2016-08-13 19:53:37 +02:00
FrameBufferAttachment depth ;
2016-03-10 21:17:48 +01:00
VkRenderPass renderPass ;
2016-06-05 15:44:04 +02:00
VkSampler depthSampler ;
2016-08-13 19:31:41 +02:00
VkDescriptorImageInfo descriptor ;
VkCommandBuffer commandBuffer = VK_NULL_HANDLE ;
// Semaphore used to synchronize between offscreen and final scene render pass
VkSemaphore semaphore = VK_NULL_HANDLE ;
} offscreenPass ;
2016-03-08 21:52:40 +01:00
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
zoom = - 20.0f ;
rotation = { - 15.0f , - 390.0f , 0.0f } ;
2017-11-01 14:22:10 +01:00
title = " Projected shadow mapping " ;
2016-03-08 21:52:40 +01:00
timerSpeed * = 0.5f ;
2017-11-01 14:22:10 +01:00
settings . overlay = true ;
2016-03-08 21:52:40 +01:00
}
~ VulkanExample ( )
{
// Clean up used Vulkan resources
// Note : Inherited destructor cleans up resources stored in base class
// Frame buffer
2016-08-13 19:31:41 +02:00
vkDestroySampler ( device , offscreenPass . depthSampler , nullptr ) ;
2016-03-08 21:52:40 +01:00
// Depth attachment
2016-08-13 19:31:41 +02:00
vkDestroyImageView ( device , offscreenPass . depth . view , nullptr ) ;
vkDestroyImage ( device , offscreenPass . depth . image , nullptr ) ;
vkFreeMemory ( device , offscreenPass . depth . mem , nullptr ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
vkDestroyFramebuffer ( device , offscreenPass . frameBuffer , nullptr ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
vkDestroyRenderPass ( device , offscreenPass . renderPass , nullptr ) ;
2016-03-13 16:04:39 +01:00
2016-03-08 21:52:40 +01:00
vkDestroyPipeline ( device , pipelines . quad , nullptr ) ;
vkDestroyPipeline ( device , pipelines . offscreen , nullptr ) ;
2017-01-07 20:20:40 +01:00
vkDestroyPipeline ( device , pipelines . sceneShadow , nullptr ) ;
vkDestroyPipeline ( device , pipelines . sceneShadowPCF , nullptr ) ;
2016-03-08 21:52:40 +01:00
vkDestroyPipelineLayout ( device , pipelineLayouts . quad , nullptr ) ;
vkDestroyPipelineLayout ( device , pipelineLayouts . offscreen , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayout , nullptr ) ;
// Meshes
2017-11-04 21:23:37 +01:00
for ( auto scene : scenes ) {
scene . destroy ( ) ;
}
2017-02-11 14:18:24 +01:00
models . quad . destroy ( ) ;
2016-03-08 21:52:40 +01:00
// Uniform buffers
2016-12-24 12:48:01 +01:00
uniformBuffers . offscreen . destroy ( ) ;
uniformBuffers . scene . destroy ( ) ;
uniformBuffers . debug . destroy ( ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
vkFreeCommandBuffers ( device , cmdPool , 1 , & offscreenPass . commandBuffer ) ;
vkDestroySemaphore ( device , offscreenPass . semaphore , nullptr ) ;
2016-03-08 21:52:40 +01:00
}
2016-03-10 21:17:48 +01:00
// Set up a separate render pass for the offscreen frame buffer
2016-08-13 19:31:41 +02:00
// This is necessary as the offscreen frame buffer attachments use formats different to those from the example render pass
2016-06-05 15:44:04 +02:00
void prepareOffscreenRenderpass ( )
2016-03-10 21:17:48 +01:00
{
2016-12-29 23:16:29 +01:00
VkAttachmentDescription attachmentDescription { } ;
attachmentDescription . format = DEPTH_FORMAT ;
attachmentDescription . samples = VK_SAMPLE_COUNT_1_BIT ;
attachmentDescription . loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR ; // Clear depth at beginning of the render pass
attachmentDescription . storeOp = VK_ATTACHMENT_STORE_OP_STORE ; // We will read from depth, so it's important to store the depth attachment results
attachmentDescription . stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE ;
attachmentDescription . stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE ;
attachmentDescription . initialLayout = VK_IMAGE_LAYOUT_UNDEFINED ; // We don't care about initial layout of the attachment
attachmentDescription . finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ; // Attachment will be transitioned to shader read at render pass end
2016-03-10 21:17:48 +01:00
VkAttachmentReference depthReference = { } ;
2016-08-13 19:53:37 +02:00
depthReference . attachment = 0 ;
2016-12-29 23:16:29 +01:00
depthReference . layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ; // Attachment will be used as depth/stencil during render pass
2016-03-10 21:17:48 +01:00
VkSubpassDescription subpass = { } ;
subpass . pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS ;
2016-12-29 23:16:29 +01:00
subpass . colorAttachmentCount = 0 ; // No color attachments
subpass . pDepthStencilAttachment = & depthReference ; // Reference to our depth attachment
2016-03-10 21:17:48 +01:00
2016-08-13 19:31:41 +02:00
// 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 ;
2016-12-31 11:28:08 +01:00
dependencies [ 0 ] . dstStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ;
2018-06-30 19:41:53 +02:00
dependencies [ 0 ] . srcAccessMask = 0 ;
2016-08-13 19:53:37 +02:00
dependencies [ 0 ] . dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT ;
2016-08-13 19:31:41 +02:00
dependencies [ 0 ] . dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT ;
dependencies [ 1 ] . srcSubpass = 0 ;
dependencies [ 1 ] . dstSubpass = VK_SUBPASS_EXTERNAL ;
2016-12-31 11:28:08 +01:00
dependencies [ 1 ] . srcStageMask = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT ;
2017-06-01 22:13:38 +02:00
dependencies [ 1 ] . dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT ;
2016-08-13 19:53:37 +02:00
dependencies [ 1 ] . srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT ;
2017-06-01 22:13:38 +02:00
dependencies [ 1 ] . dstAccessMask = VK_ACCESS_SHADER_READ_BIT ;
2016-08-13 19:31:41 +02:00
dependencies [ 1 ] . dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT ;
2017-02-12 11:12:42 +01:00
VkRenderPassCreateInfo renderPassCreateInfo = vks : : initializers : : renderPassCreateInfo ( ) ;
2016-08-13 19:53:37 +02:00
renderPassCreateInfo . attachmentCount = 1 ;
2016-12-29 23:16:29 +01:00
renderPassCreateInfo . pAttachments = & attachmentDescription ;
2016-03-10 21:17:48 +01:00
renderPassCreateInfo . subpassCount = 1 ;
renderPassCreateInfo . pSubpasses = & subpass ;
2016-08-13 19:31:41 +02:00
renderPassCreateInfo . dependencyCount = static_cast < uint32_t > ( dependencies . size ( ) ) ;
renderPassCreateInfo . pDependencies = dependencies . data ( ) ;
2016-03-10 21:17:48 +01:00
2016-08-13 19:31:41 +02:00
VK_CHECK_RESULT ( vkCreateRenderPass ( device , & renderPassCreateInfo , nullptr , & offscreenPass . renderPass ) ) ;
2016-03-10 21:17:48 +01:00
}
2016-08-13 19:31:41 +02:00
// Setup the offscreen framebuffer for rendering the scene from light's point-of-view to
// The depth attachment of this framebuffer will then be used to sample from in the fragment shader of the shadowing pass
2016-03-08 21:52:40 +01:00
void prepareOffscreenFramebuffer ( )
{
2016-08-13 19:31:41 +02:00
offscreenPass . width = SHADOWMAP_DIM ;
offscreenPass . height = SHADOWMAP_DIM ;
2016-03-08 21:52:40 +01:00
VkFormat fbColorFormat = FB_COLOR_FORMAT ;
2016-08-13 19:53:37 +02:00
// For shadow mapping we only need a depth attachment
2017-02-12 11:12:42 +01:00
VkImageCreateInfo image = vks : : initializers : : imageCreateInfo ( ) ;
2016-03-08 21:52:40 +01:00
image . imageType = VK_IMAGE_TYPE_2D ;
2016-08-13 19:31:41 +02:00
image . extent . width = offscreenPass . width ;
image . extent . height = offscreenPass . height ;
2016-06-05 15:44:04 +02:00
image . extent . depth = 1 ;
2016-03-08 21:52:40 +01:00
image . mipLevels = 1 ;
image . arrayLayers = 1 ;
image . samples = VK_SAMPLE_COUNT_1_BIT ;
image . tiling = VK_IMAGE_TILING_OPTIMAL ;
2016-08-13 19:53:37 +02:00
image . format = DEPTH_FORMAT ; // Depth stencil attachment
image . usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ; // We will sample directly from the depth attachment for the shadow mapping
VK_CHECK_RESULT ( vkCreateImage ( device , & image , nullptr , & offscreenPass . depth . image ) ) ;
2016-03-08 21:52:40 +01:00
2017-02-12 11:12:42 +01:00
VkMemoryAllocateInfo memAlloc = vks : : initializers : : memoryAllocateInfo ( ) ;
2016-05-14 19:27:23 +02:00
VkMemoryRequirements memReqs ;
2016-08-13 19:53:37 +02:00
vkGetImageMemoryRequirements ( device , offscreenPass . depth . image , & memReqs ) ;
2016-03-08 21:52:40 +01:00
memAlloc . allocationSize = memReqs . size ;
2016-07-23 20:42:03 +02:00
memAlloc . memoryTypeIndex = vulkanDevice - > getMemoryType ( memReqs . memoryTypeBits , VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) ;
2016-08-13 19:53:37 +02:00
VK_CHECK_RESULT ( vkAllocateMemory ( device , & memAlloc , nullptr , & offscreenPass . depth . mem ) ) ;
VK_CHECK_RESULT ( vkBindImageMemory ( device , offscreenPass . depth . image , offscreenPass . depth . mem , 0 ) ) ;
2016-03-08 21:52:40 +01:00
2017-02-12 11:12:42 +01:00
VkImageViewCreateInfo depthStencilView = vks : : initializers : : imageViewCreateInfo ( ) ;
2016-03-08 21:52:40 +01:00
depthStencilView . viewType = VK_IMAGE_VIEW_TYPE_2D ;
depthStencilView . format = DEPTH_FORMAT ;
depthStencilView . subresourceRange = { } ;
depthStencilView . subresourceRange . aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT ;
depthStencilView . subresourceRange . baseMipLevel = 0 ;
depthStencilView . subresourceRange . levelCount = 1 ;
depthStencilView . subresourceRange . baseArrayLayer = 0 ;
depthStencilView . subresourceRange . layerCount = 1 ;
2016-08-13 19:31:41 +02:00
depthStencilView . image = offscreenPass . depth . image ;
VK_CHECK_RESULT ( vkCreateImageView ( device , & depthStencilView , nullptr , & offscreenPass . depth . view ) ) ;
2016-03-08 21:52:40 +01:00
2016-06-05 16:42:27 +02:00
// Create sampler to sample from to depth attachment
// Used to sample in the fragment shader for shadowed rendering
2017-02-12 11:12:42 +01:00
VkSamplerCreateInfo sampler = vks : : initializers : : samplerCreateInfo ( ) ;
2016-06-05 15:44:04 +02:00
sampler . magFilter = SHADOWMAP_FILTER ;
sampler . minFilter = SHADOWMAP_FILTER ;
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 ;
2017-06-01 22:32:39 +02:00
sampler . maxAnisotropy = 1.0f ;
2016-06-05 15:44:04 +02:00
sampler . minLod = 0.0f ;
sampler . maxLod = 1.0f ;
sampler . borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE ;
2016-08-13 19:31:41 +02:00
VK_CHECK_RESULT ( vkCreateSampler ( device , & sampler , nullptr , & offscreenPass . depthSampler ) ) ;
2016-06-05 15:44:04 +02:00
prepareOffscreenRenderpass ( ) ;
2016-03-10 21:17:48 +01:00
// Create frame buffer
2017-02-12 11:12:42 +01:00
VkFramebufferCreateInfo fbufCreateInfo = vks : : initializers : : framebufferCreateInfo ( ) ;
2016-08-13 19:31:41 +02:00
fbufCreateInfo . renderPass = offscreenPass . renderPass ;
2016-08-13 19:53:37 +02:00
fbufCreateInfo . attachmentCount = 1 ;
fbufCreateInfo . pAttachments = & offscreenPass . depth . view ;
2016-08-13 19:31:41 +02:00
fbufCreateInfo . width = offscreenPass . width ;
fbufCreateInfo . height = offscreenPass . height ;
2016-03-08 21:52:40 +01:00
fbufCreateInfo . layers = 1 ;
2016-08-13 19:31:41 +02:00
VK_CHECK_RESULT ( vkCreateFramebuffer ( device , & fbufCreateInfo , nullptr , & offscreenPass . frameBuffer ) ) ;
2016-03-08 21:52:40 +01:00
}
void buildOffscreenCommandBuffer ( )
{
2016-08-13 19:31:41 +02:00
if ( offscreenPass . commandBuffer = = VK_NULL_HANDLE )
2016-03-08 21:52:40 +01:00
{
2016-08-13 19:31:41 +02:00
offscreenPass . commandBuffer = VulkanExampleBase : : createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , false ) ;
}
if ( offscreenPass . semaphore = = VK_NULL_HANDLE )
{
// Create a semaphore used to synchronize offscreen rendering and usage
2017-02-12 11:12:42 +01:00
VkSemaphoreCreateInfo semaphoreCreateInfo = vks : : initializers : : semaphoreCreateInfo ( ) ;
2016-08-13 19:31:41 +02:00
VK_CHECK_RESULT ( vkCreateSemaphore ( device , & semaphoreCreateInfo , nullptr , & offscreenPass . semaphore ) ) ;
2016-03-08 21:52:40 +01:00
}
2016-05-14 19:12:10 +02:00
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:53:37 +02:00
VkClearValue clearValues [ 1 ] ;
clearValues [ 0 ] . depthStencil = { 1.0f , 0 } ;
2016-03-08 21:52:40 +01:00
2017-02-12 11:12:42 +01:00
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
2016-08-13 19:31:41 +02:00
renderPassBeginInfo . renderPass = offscreenPass . renderPass ;
renderPassBeginInfo . framebuffer = offscreenPass . frameBuffer ;
2016-03-08 21:52:40 +01:00
renderPassBeginInfo . renderArea . offset . x = 0 ;
renderPassBeginInfo . renderArea . offset . y = 0 ;
2016-08-13 19:31:41 +02:00
renderPassBeginInfo . renderArea . extent . width = offscreenPass . width ;
renderPassBeginInfo . renderArea . extent . height = offscreenPass . height ;
2016-03-08 21:52:40 +01:00
renderPassBeginInfo . clearValueCount = 2 ;
renderPassBeginInfo . pClearValues = clearValues ;
2016-08-13 19:31:41 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( offscreenPass . commandBuffer , & cmdBufInfo ) ) ;
2016-06-05 15:44:04 +02:00
2017-02-12 11:12:42 +01:00
VkViewport viewport = vks : : initializers : : viewport ( ( float ) offscreenPass . width , ( float ) offscreenPass . height , 0.0f , 1.0f ) ;
2016-08-13 19:31:41 +02:00
vkCmdSetViewport ( offscreenPass . commandBuffer , 0 , 1 , & viewport ) ;
2016-03-08 21:52:40 +01:00
2017-02-12 11:12:42 +01:00
VkRect2D scissor = vks : : initializers : : rect2D ( offscreenPass . width , offscreenPass . height , 0 , 0 ) ;
2016-08-13 19:31:41 +02:00
vkCmdSetScissor ( offscreenPass . commandBuffer , 0 , 1 , & scissor ) ;
2016-03-08 21:52:40 +01:00
// Set depth bias (aka "Polygon offset")
2016-06-05 15:44:04 +02:00
// Required to avoid shadow mapping artefacts
2016-03-08 21:52:40 +01:00
vkCmdSetDepthBias (
2016-08-13 19:31:41 +02:00
offscreenPass . commandBuffer ,
2016-03-08 21:52:40 +01:00
depthBiasConstant ,
0.0f ,
depthBiasSlope ) ;
2016-08-13 19:31:41 +02:00
vkCmdBeginRenderPass ( offscreenPass . commandBuffer , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
vkCmdBindPipeline ( offscreenPass . commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . offscreen ) ;
vkCmdBindDescriptorSets ( offscreenPass . commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayouts . offscreen , 0 , 1 , & descriptorSets . offscreen , 0 , NULL ) ;
2016-03-08 21:52:40 +01:00
VkDeviceSize offsets [ 1 ] = { 0 } ;
2017-11-04 21:27:02 +01:00
vkCmdBindVertexBuffers ( offscreenPass . commandBuffer , VERTEX_BUFFER_BIND_ID , 1 , & scenes [ sceneIndex ] . vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( offscreenPass . commandBuffer , scenes [ sceneIndex ] . indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
vkCmdDrawIndexed ( offscreenPass . commandBuffer , scenes [ sceneIndex ] . indexCount , 1 , 0 , 0 , 0 ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
vkCmdEndRenderPass ( offscreenPass . commandBuffer ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( offscreenPass . commandBuffer ) ) ;
2016-03-08 21:52:40 +01:00
}
void buildCommandBuffers ( )
{
2017-02-12 11:12:42 +01:00
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
2016-03-08 21:52:40 +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-03-08 21:52:40 +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 19:27:23 +02:00
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
2016-03-08 21:52:40 +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-03-08 21:52:40 +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-03-08 21:52:40 +01:00
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
VkDeviceSize offsets [ 1 ] = { 0 } ;
// Visualize shadow map
2017-11-01 14:22:10 +01:00
if ( displayShadowMap ) {
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayouts . quad , 0 , 1 , & descriptorSet , 0 , NULL ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelines . quad ) ;
2017-02-11 14:18:24 +01:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , VERTEX_BUFFER_BIND_ID , 1 , & models . quad . vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , models . quad . indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , models . quad . indexCount , 1 , 0 , 0 , 0 ) ;
2016-03-08 21:52:40 +01:00
}
// 3D scene
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayouts . quad , 0 , 1 , & descriptorSets . scene , 0 , NULL ) ;
2017-01-07 20:20:40 +01:00
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , ( filterPCF ) ? pipelines . sceneShadowPCF : pipelines . sceneShadow ) ;
2016-03-08 21:52:40 +01:00
2017-11-04 21:27:02 +01:00
vkCmdBindVertexBuffers ( drawCmdBuffers [ i ] , VERTEX_BUFFER_BIND_ID , 1 , & scenes [ sceneIndex ] . vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( drawCmdBuffers [ i ] , scenes [ sceneIndex ] . indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
vkCmdDrawIndexed ( drawCmdBuffers [ i ] , scenes [ sceneIndex ] . indexCount , 1 , 0 , 0 , 0 ) ;
2016-03-08 21:52:40 +01:00
2018-08-30 21:08:02 +02:00
drawUI ( drawCmdBuffers [ i ] ) ;
2016-03-08 21:52:40 +01:00
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2016-03-08 21:52:40 +01:00
}
}
2016-08-13 20:35:22 +02:00
void loadAssets ( )
2016-03-08 21:52:40 +01:00
{
2017-11-04 21:23:37 +01:00
scenes . resize ( 2 ) ;
scenes [ 0 ] . loadFromFile ( getAssetPath ( ) + " models/vulkanscene_shadow.dae " , vertexLayout , 4.0f , vulkanDevice , queue ) ;
scenes [ 1 ] . loadFromFile ( getAssetPath ( ) + " models/samplescene.dae " , vertexLayout , 0.25f , vulkanDevice , queue ) ;
sceneNames = { " Vulkan scene " , " Teapots and pillars " } ;
2016-03-08 21:52:40 +01:00
}
void generateQuad ( )
{
// Setup vertices for a single uv-mapped quad
struct Vertex {
float pos [ 3 ] ;
float uv [ 2 ] ;
float col [ 3 ] ;
float normal [ 3 ] ;
} ;
# define QUAD_COLOR_NORMAL { 1.0f, 1.0f, 1.0f }, { 0.0f, 0.0f, 1.0f }
std : : vector < Vertex > vertexBuffer =
{
{ { 1.0f , 1.0f , 0.0f } , { 1.0f , 1.0f } , QUAD_COLOR_NORMAL } ,
{ { 0.0f , 1.0f , 0.0f } , { 0.0f , 1.0f } , QUAD_COLOR_NORMAL } ,
{ { 0.0f , 0.0f , 0.0f } , { 0.0f , 0.0f } , QUAD_COLOR_NORMAL } ,
{ { 1.0f , 0.0f , 0.0f } , { 1.0f , 0.0f } , QUAD_COLOR_NORMAL }
} ;
# undef QUAD_COLOR_NORMAL
2017-01-07 20:20:40 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-03-08 21:52:40 +01:00
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT ,
2017-01-07 20:20:40 +01:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-03-08 21:52:40 +01:00
vertexBuffer . size ( ) * sizeof ( Vertex ) ,
2017-02-11 14:18:24 +01:00
& models . quad . vertices . buffer ,
& models . quad . vertices . memory ,
2017-01-07 20:20:40 +01:00
vertexBuffer . data ( ) ) ) ;
2016-03-08 21:52:40 +01:00
// Setup indices
std : : vector < uint32_t > indexBuffer = { 0 , 1 , 2 , 2 , 3 , 0 } ;
2017-02-11 14:18:24 +01:00
models . quad . indexCount = indexBuffer . size ( ) ;
2016-03-08 21:52:40 +01:00
2017-01-07 20:20:40 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-03-08 21:52:40 +01:00
VK_BUFFER_USAGE_INDEX_BUFFER_BIT ,
2017-01-07 20:20:40 +01:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-03-08 21:52:40 +01:00
indexBuffer . size ( ) * sizeof ( uint32_t ) ,
2017-02-11 14:18:24 +01:00
& models . quad . indices . buffer ,
& models . quad . indices . memory ,
2017-01-07 20:20:40 +01:00
indexBuffer . data ( ) ) ) ;
2017-02-11 14:18:24 +01:00
models . quad . device = device ;
2016-03-08 21:52:40 +01:00
}
void setupVertexDescriptions ( )
{
// Binding description
vertices . bindingDescriptions . resize ( 1 ) ;
vertices . bindingDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputBindingDescription (
2016-03-08 21:52:40 +01:00
VERTEX_BUFFER_BIND_ID ,
2017-02-11 14:18:24 +01:00
vertexLayout . stride ( ) ,
2016-03-08 21:52:40 +01:00
VK_VERTEX_INPUT_RATE_VERTEX ) ;
// Attribute descriptions
vertices . attributeDescriptions . resize ( 4 ) ;
// Location 0 : Position
vertices . attributeDescriptions [ 0 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-03-08 21:52:40 +01:00
VERTEX_BUFFER_BIND_ID ,
0 ,
VK_FORMAT_R32G32B32_SFLOAT ,
0 ) ;
// Location 1 : Texture coordinates
vertices . attributeDescriptions [ 1 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-03-08 21:52:40 +01:00
VERTEX_BUFFER_BIND_ID ,
1 ,
VK_FORMAT_R32G32_SFLOAT ,
sizeof ( float ) * 3 ) ;
// Location 2 : Color
vertices . attributeDescriptions [ 2 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-03-08 21:52:40 +01:00
VERTEX_BUFFER_BIND_ID ,
2 ,
VK_FORMAT_R32G32B32_SFLOAT ,
sizeof ( float ) * 5 ) ;
// Location 3 : Normal
vertices . attributeDescriptions [ 3 ] =
2017-02-12 11:12:42 +01:00
vks : : initializers : : vertexInputAttributeDescription (
2016-03-08 21:52:40 +01:00
VERTEX_BUFFER_BIND_ID ,
3 ,
VK_FORMAT_R32G32B32_SFLOAT ,
sizeof ( float ) * 8 ) ;
2017-02-12 11:12:42 +01:00
vertices . inputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
2016-03-08 21:52:40 +01:00
vertices . inputState . vertexBindingDescriptionCount = vertices . bindingDescriptions . size ( ) ;
vertices . inputState . pVertexBindingDescriptions = vertices . bindingDescriptions . data ( ) ;
vertices . inputState . vertexAttributeDescriptionCount = vertices . attributeDescriptions . size ( ) ;
vertices . inputState . pVertexAttributeDescriptions = vertices . attributeDescriptions . data ( ) ;
}
void setupDescriptorPool ( )
{
// Example uses three ubos and two image samplers
std : : vector < VkDescriptorPoolSize > poolSizes =
{
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 6 ) ,
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 4 )
2016-03-08 21:52:40 +01:00
} ;
VkDescriptorPoolCreateInfo descriptorPoolInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolCreateInfo (
2016-03-08 21:52:40 +01:00
poolSizes . size ( ) ,
poolSizes . data ( ) ,
3 ) ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-03-08 21:52:40 +01:00
}
void setupDescriptorSetLayout ( )
{
// Textured quad pipeline layout
std : : vector < VkDescriptorSetLayoutBinding > setLayoutBindings =
{
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-03-08 21:52:40 +01:00
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
VK_SHADER_STAGE_VERTEX_BIT ,
0 ) ,
// Binding 1 : Fragment shader image sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutBinding (
2016-03-08 21:52:40 +01:00
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
VK_SHADER_STAGE_FRAGMENT_BIT ,
1 )
} ;
VkDescriptorSetLayoutCreateInfo descriptorLayout =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetLayoutCreateInfo (
2016-03-08 21:52:40 +01:00
setLayoutBindings . data ( ) ,
setLayoutBindings . size ( ) ) ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorLayout , nullptr , & descriptorSetLayout ) ) ;
2016-03-08 21:52:40 +01:00
VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineLayoutCreateInfo (
2016-03-08 21:52:40 +01:00
& descriptorSetLayout ,
1 ) ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayouts . quad ) ) ;
2016-03-08 21:52:40 +01:00
// Offscreen pipeline layout
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pPipelineLayoutCreateInfo , nullptr , & pipelineLayouts . offscreen ) ) ;
2016-03-08 21:52:40 +01:00
}
void setupDescriptorSets ( )
{
2016-12-24 12:48:01 +01:00
std : : vector < VkWriteDescriptorSet > writeDescriptorSets ;
2016-03-08 21:52:40 +01:00
// Textured quad descriptor set
VkDescriptorSetAllocateInfo allocInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorSetAllocateInfo (
2016-03-08 21:52:40 +01:00
descriptorPool ,
& descriptorSetLayout ,
1 ) ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Image descriptor for the shadow map attachment
2016-03-08 21:52:40 +01:00
VkDescriptorImageInfo texDescriptor =
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorImageInfo (
2016-08-13 19:31:41 +02:00
offscreenPass . depthSampler ,
offscreenPass . depth . view ,
2016-12-29 23:16:29 +01:00
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL ) ;
2016-03-08 21:52:40 +01:00
2016-12-24 12:48:01 +01:00
writeDescriptorSets = {
2016-03-08 21:52:40 +01:00
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-03-08 21:52:40 +01:00
descriptorSet ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . debug . descriptor ) ,
2016-03-08 21:52:40 +01:00
// Binding 1 : Fragment shader texture sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-03-08 21:52:40 +01:00
descriptorSet ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
& texDescriptor )
} ;
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
// Offscreen
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSets . offscreen ) ) ;
2016-03-08 21:52:40 +01:00
2016-12-24 12:48:01 +01:00
writeDescriptorSets = {
2016-03-08 21:52:40 +01:00
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-03-08 21:52:40 +01:00
descriptorSets . offscreen ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . offscreen . descriptor ) ,
2016-03-08 21:52:40 +01:00
} ;
2016-12-24 12:48:01 +01:00
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
2016-03-08 21:52:40 +01:00
// 3D scene
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSets . scene ) ) ;
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Image descriptor for the shadow map attachment
2016-08-13 19:31:41 +02:00
texDescriptor . sampler = offscreenPass . depthSampler ;
texDescriptor . imageView = offscreenPass . depth . view ;
2016-03-08 21:52:40 +01:00
2016-12-24 12:48:01 +01:00
writeDescriptorSets = {
2016-03-08 21:52:40 +01:00
// Binding 0 : Vertex shader uniform buffer
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-03-08 21:52:40 +01:00
descriptorSets . scene ,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ,
0 ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . scene . descriptor ) ,
2016-03-08 21:52:40 +01:00
// Binding 1 : Fragment shader shadow sampler
2017-02-12 11:12:42 +01:00
vks : : initializers : : writeDescriptorSet (
2016-03-08 21:52:40 +01:00
descriptorSets . scene ,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER ,
1 ,
& texDescriptor )
} ;
2016-12-24 12:48:01 +01:00
vkUpdateDescriptorSets ( device , writeDescriptorSets . size ( ) , writeDescriptorSets . data ( ) , 0 , NULL ) ;
2016-03-08 21:52:40 +01:00
}
void preparePipelines ( )
{
VkPipelineInputAssemblyStateCreateInfo inputAssemblyState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineInputAssemblyStateCreateInfo (
2016-03-08 21:52:40 +01:00
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST ,
0 ,
VK_FALSE ) ;
VkPipelineRasterizationStateCreateInfo rasterizationState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineRasterizationStateCreateInfo (
2016-03-08 21:52:40 +01:00
VK_POLYGON_MODE_FILL ,
2017-01-07 20:20:40 +01:00
VK_CULL_MODE_BACK_BIT ,
2016-03-08 21:52:40 +01:00
VK_FRONT_FACE_CLOCKWISE ,
0 ) ;
VkPipelineColorBlendAttachmentState blendAttachmentState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineColorBlendAttachmentState (
2016-03-08 21:52:40 +01:00
0xf ,
VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineColorBlendStateCreateInfo (
2016-03-08 21:52:40 +01:00
1 ,
& blendAttachmentState ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineDepthStencilStateCreateInfo (
2016-03-08 21:52:40 +01:00
VK_TRUE ,
VK_TRUE ,
VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
2016-03-08 21:52:40 +01:00
VkPipelineMultisampleStateCreateInfo multisampleState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineMultisampleStateCreateInfo (
2016-03-08 21:52:40 +01:00
VK_SAMPLE_COUNT_1_BIT ,
0 ) ;
std : : vector < VkDynamicState > dynamicStateEnables = {
VK_DYNAMIC_STATE_VIEWPORT ,
VK_DYNAMIC_STATE_SCISSOR
} ;
VkPipelineDynamicStateCreateInfo dynamicState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineDynamicStateCreateInfo (
2016-03-08 21:52:40 +01:00
dynamicStateEnables . data ( ) ,
dynamicStateEnables . size ( ) ,
0 ) ;
std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages ;
VkGraphicsPipelineCreateInfo pipelineCreateInfo =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineCreateInfo (
2016-03-08 21:52:40 +01:00
pipelineLayouts . quad ,
renderPass ,
0 ) ;
pipelineCreateInfo . pInputAssemblyState = & inputAssemblyState ;
pipelineCreateInfo . pRasterizationState = & rasterizationState ;
pipelineCreateInfo . pColorBlendState = & colorBlendState ;
pipelineCreateInfo . pMultisampleState = & multisampleState ;
pipelineCreateInfo . pViewportState = & viewportState ;
pipelineCreateInfo . pDepthStencilState = & depthStencilState ;
pipelineCreateInfo . pDynamicState = & dynamicState ;
pipelineCreateInfo . stageCount = shaderStages . size ( ) ;
pipelineCreateInfo . pStages = shaderStages . data ( ) ;
2017-11-01 14:22:10 +01:00
// Shadow mapping debug quad display
rasterizationState . cullMode = VK_CULL_MODE_NONE ;
shaderStages [ 0 ] = loadShader ( getAssetPath ( ) + " shaders/shadowmapping/quad.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getAssetPath ( ) + " shaders/shadowmapping/quad.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2017-11-12 19:32:09 +01:00
// Empty vertex input state
VkPipelineVertexInputStateCreateInfo emptyInputState = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
pipelineCreateInfo . pVertexInputState = & emptyInputState ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . quad ) ) ;
2016-03-08 21:52:40 +01:00
2017-11-12 19:32:09 +01:00
pipelineCreateInfo . pVertexInputState = & vertices . inputState ;
2017-01-07 20:20:40 +01:00
// Scene rendering with shadows applied
2017-11-01 14:22:10 +01:00
rasterizationState . cullMode = VK_CULL_MODE_BACK_BIT ;
2016-03-25 15:29:38 +01:00
shaderStages [ 0 ] = loadShader ( getAssetPath ( ) + " shaders/shadowmapping/scene.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
shaderStages [ 1 ] = loadShader ( getAssetPath ( ) + " shaders/shadowmapping/scene.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT ) ;
2017-01-07 20:20:40 +01:00
// Use specialization constants to select between horizontal and vertical blur
uint32_t enablePCF = 0 ;
2017-02-12 11:12:42 +01:00
VkSpecializationMapEntry specializationMapEntry = vks : : initializers : : specializationMapEntry ( 0 , 0 , sizeof ( uint32_t ) ) ;
VkSpecializationInfo specializationInfo = vks : : initializers : : specializationInfo ( 1 , & specializationMapEntry , sizeof ( uint32_t ) , & enablePCF ) ;
2017-01-07 20:20:40 +01:00
shaderStages [ 1 ] . pSpecializationInfo = & specializationInfo ;
// No filtering
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . sceneShadow ) ) ;
// PCF filtering
enablePCF = 1 ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . sceneShadowPCF ) ) ;
2016-03-08 21:52:40 +01:00
2018-05-21 16:45:19 -07:00
// Offscreen pipeline (vertex shader only)
2016-03-25 15:29:38 +01:00
shaderStages [ 0 ] = loadShader ( getAssetPath ( ) + " shaders/shadowmapping/offscreen.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ;
2018-05-21 16:45:19 -07:00
pipelineCreateInfo . stageCount = 1 ;
2016-08-13 19:53:37 +02:00
// No blend attachment states (no color attachments used)
colorBlendState . attachmentCount = 0 ;
2016-03-08 21:52:40 +01:00
// Cull front faces
depthStencilState . depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL ;
// Enable depth bias
rasterizationState . depthBiasEnable = VK_TRUE ;
// Add depth bias to dynamic state, so we can change it at runtime
dynamicStateEnables . push_back ( VK_DYNAMIC_STATE_DEPTH_BIAS ) ;
dynamicState =
2017-02-12 11:12:42 +01:00
vks : : initializers : : pipelineDynamicStateCreateInfo (
2016-03-08 21:52:40 +01:00
dynamicStateEnables . data ( ) ,
dynamicStateEnables . size ( ) ,
0 ) ;
2016-06-05 15:44:04 +02:00
pipelineCreateInfo . layout = pipelineLayouts . offscreen ;
2016-08-13 19:31:41 +02:00
pipelineCreateInfo . renderPass = offscreenPass . renderPass ;
2016-05-14 19:27:23 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCreateInfo , nullptr , & pipelines . offscreen ) ) ;
2016-03-08 21:52:40 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
// Debug quad vertex shader uniform buffer block
2016-12-24 12:48:01 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-03-08 21:52:40 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-05 15:44:04 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . debug ,
sizeof ( uboVSscene ) ) ) ;
2016-03-08 21:52:40 +01:00
2016-08-13 19:31:41 +02:00
// Offscreen vertex shader uniform buffer block
2016-12-24 12:48:01 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-03-08 21:52:40 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-05 15:44:04 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . offscreen ,
sizeof ( uboOffscreenVS ) ) ) ;
2016-03-08 21:52:40 +01:00
// Scene vertex shader uniform buffer block
2016-12-24 12:48:01 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-03-08 21:52:40 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-05 15:44:04 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2016-12-24 12:48:01 +01:00
& uniformBuffers . scene ,
sizeof ( uboVSscene ) ) ) ;
// Map persistent
VK_CHECK_RESULT ( uniformBuffers . debug . map ( ) ) ;
VK_CHECK_RESULT ( uniformBuffers . offscreen . map ( ) ) ;
VK_CHECK_RESULT ( uniformBuffers . scene . map ( ) ) ;
2016-03-08 21:52:40 +01:00
updateLight ( ) ;
updateUniformBufferOffscreen ( ) ;
updateUniformBuffers ( ) ;
}
void updateLight ( )
{
// Animate the light source
lightPos . x = cos ( glm : : radians ( timer * 360.0f ) ) * 40.0f ;
lightPos . y = - 50.0f + sin ( glm : : radians ( timer * 360.0f ) ) * 20.0f ;
lightPos . z = 25.0f + sin ( glm : : radians ( timer * 360.0f ) ) * 5.0f ;
}
void updateUniformBuffers ( )
{
// Shadow map debug quad
float AR = ( float ) height / ( float ) width ;
2016-06-05 15:44:04 +02:00
uboVSquad . projection = glm : : ortho ( 2.5f / AR , 0.0f , 0.0f , 2.5f , - 1.0f , 1.0f ) ;
2017-09-24 18:17:07 +02:00
uboVSquad . model = glm : : mat4 ( 1.0f ) ;
2016-03-08 21:52:40 +01:00
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . debug . mapped , & uboVSquad , sizeof ( uboVSquad ) ) ;
2016-03-08 21:52:40 +01:00
// 3D scene
uboVSscene . projection = glm : : perspective ( glm : : radians ( 45.0f ) , ( float ) width / ( float ) height , zNear , zFar ) ;
2017-09-24 18:17:07 +02:00
uboVSscene . view = glm : : translate ( glm : : mat4 ( 1.0f ) , glm : : vec3 ( 0.0f , 0.0f , zoom ) ) ;
2016-03-08 21:52:40 +01:00
uboVSscene . view = glm : : rotate ( uboVSscene . view , glm : : radians ( rotation . x ) , glm : : vec3 ( 1.0f , 0.0f , 0.0f ) ) ;
uboVSscene . view = glm : : rotate ( uboVSscene . view , glm : : radians ( rotation . y ) , glm : : vec3 ( 0.0f , 1.0f , 0.0f ) ) ;
uboVSscene . view = glm : : rotate ( uboVSscene . view , glm : : radians ( rotation . z ) , glm : : vec3 ( 0.0f , 0.0f , 1.0f ) ) ;
2017-09-24 18:17:07 +02:00
uboVSscene . model = glm : : mat4 ( 1.0f ) ;
2016-03-08 21:52:40 +01:00
uboVSscene . lightPos = lightPos ;
uboVSscene . depthBiasMVP = uboOffscreenVS . depthMVP ;
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . scene . mapped , & uboVSscene , sizeof ( uboVSscene ) ) ;
2016-03-08 21:52:40 +01:00
}
void updateUniformBufferOffscreen ( )
{
// Matrix from light's point of view
glm : : mat4 depthProjectionMatrix = glm : : perspective ( glm : : radians ( lightFOV ) , 1.0f , zNear , zFar ) ;
2016-06-05 15:44:04 +02:00
glm : : mat4 depthViewMatrix = glm : : lookAt ( lightPos , glm : : vec3 ( 0.0f ) , glm : : vec3 ( 0 , 1 , 0 ) ) ;
2017-09-24 18:17:07 +02:00
glm : : mat4 depthModelMatrix = glm : : mat4 ( 1.0f ) ;
2016-03-08 21:52:40 +01:00
uboOffscreenVS . depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix ;
2016-12-24 12:48:01 +01:00
memcpy ( uniformBuffers . offscreen . mapped , & uboOffscreenVS , sizeof ( uboOffscreenVS ) ) ;
2016-03-08 21:52:40 +01:00
}
2016-06-05 15:44:04 +02:00
void draw ( )
2016-03-08 21:52:40 +01:00
{
2016-06-05 15:44:04 +02:00
VulkanExampleBase : : prepareFrame ( ) ;
2016-08-13 19:31:41 +02:00
// The scene render command buffer has to wait for the offscreen rendering (and transfer) to be finished before using the shadow map
// Therefore we synchronize using an additional semaphore
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Offscreen rendering
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Wait for swap chain presentation to finish
submitInfo . pWaitSemaphores = & semaphores . presentComplete ;
// Signal ready with offscreen semaphore
2016-08-13 19:31:41 +02:00
submitInfo . pSignalSemaphores = & offscreenPass . semaphore ;
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Submit work
submitInfo . commandBufferCount = 1 ;
2016-08-13 19:31:41 +02:00
submitInfo . pCommandBuffers = & offscreenPass . commandBuffer ;
2016-06-05 15:44:04 +02:00
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Scene rendering
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Wait for offscreen semaphore
2016-08-13 19:31:41 +02:00
submitInfo . pWaitSemaphores = & offscreenPass . semaphore ; ;
2016-06-05 15:44:04 +02:00
// Signal ready with render complete semaphpre
submitInfo . pSignalSemaphores = & semaphores . renderComplete ;
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
// Submit work
submitInfo . pCommandBuffers = & drawCmdBuffers [ currentBuffer ] ;
VK_CHECK_RESULT ( vkQueueSubmit ( queue , 1 , & submitInfo , VK_NULL_HANDLE ) ) ;
2016-03-08 21:52:40 +01:00
2016-06-05 15:44:04 +02:00
VulkanExampleBase : : submitFrame ( ) ;
2016-03-08 21:52:40 +01:00
}
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2016-08-13 20:35:22 +02:00
loadAssets ( ) ;
2016-03-08 21:52:40 +01:00
generateQuad ( ) ;
2016-06-05 15:44:04 +02:00
prepareOffscreenFramebuffer ( ) ;
2016-03-08 21:52:40 +01:00
setupVertexDescriptions ( ) ;
prepareUniformBuffers ( ) ;
setupDescriptorSetLayout ( ) ;
preparePipelines ( ) ;
setupDescriptorPool ( ) ;
setupDescriptorSets ( ) ;
buildCommandBuffers ( ) ;
buildOffscreenCommandBuffer ( ) ;
prepared = true ;
}
virtual void render ( )
{
if ( ! prepared )
return ;
draw ( ) ;
if ( ! paused )
{
updateLight ( ) ;
updateUniformBufferOffscreen ( ) ;
updateUniformBuffers ( ) ;
}
}
virtual void viewChanged ( )
{
updateUniformBufferOffscreen ( ) ;
updateUniformBuffers ( ) ;
}
2017-11-01 14:22:10 +01:00
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
2016-06-05 15:44:04 +02:00
{
2017-11-01 14:22:10 +01:00
if ( overlay - > header ( " Settings " ) ) {
2017-11-04 21:23:37 +01:00
if ( overlay - > comboBox ( " Scenes " , & sceneIndex , sceneNames ) ) {
buildCommandBuffers ( ) ;
buildOffscreenCommandBuffer ( ) ;
}
2017-11-04 21:29:11 +01:00
if ( overlay - > checkBox ( " Display shadow render target " , & displayShadowMap ) ) {
2017-11-01 14:22:10 +01:00
buildCommandBuffers ( ) ;
}
if ( overlay - > checkBox ( " PCF filtering " , & filterPCF ) ) {
buildCommandBuffers ( ) ;
}
2016-06-05 15:44:04 +02:00
}
}
2016-03-08 21:52:40 +01:00
} ;
2016-08-13 19:31:41 +02:00
VULKAN_EXAMPLE_MAIN ( )