Texture tree and terrain scene, refactoring and cleanup

This commit is contained in:
saschawillems 2017-12-21 21:28:31 +01:00
parent 34942b08c5
commit 75b2a72957
13 changed files with 200 additions and 97 deletions

View file

@ -3,15 +3,12 @@
layout (binding = 1) uniform sampler2DArray shadowMap; layout (binding = 1) uniform sampler2DArray shadowMap;
layout (location = 0) in vec2 inUV; layout (location = 0) in vec2 inUV;
layout (location = 1) flat in uint inCascadeIndex;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
layout(push_constant) uniform PushConsts {
uint cascadeIndex;
} pushConsts;
void main() void main()
{ {
float depth = texture(shadowMap, vec3(inUV, float(pushConsts.cascadeIndex))).r; float depth = texture(shadowMap, vec3(inUV, float(inCascadeIndex))).r;
outFragColor = vec4(vec3((depth)), 1.0); outFragColor = vec4(vec3((depth)), 1.0);
} }

View file

@ -1,14 +1,20 @@
#version 450 #version 450
layout(push_constant) uniform PushConsts {
vec4 position;
uint cascadeIndex;
} pushConsts;
layout (location = 0) out vec2 outUV; layout (location = 0) out vec2 outUV;
layout (location = 1) out uint outCascadeIndex;
out gl_PerVertex { out gl_PerVertex {
vec4 gl_Position; vec4 gl_Position;
}; };
void main() void main()
{ {
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
outCascadeIndex = pushConsts.cascadeIndex;
gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f);
} }

View file

@ -1,5 +1,13 @@
#version 450 #version 450
layout (set = 1, binding = 0) uniform sampler2D colorMap;
layout (location = 0) in vec2 inUV;
void main() void main()
{ {
float alpha = texture(colorMap, inUV).a;
if (alpha < 0.5) {
discard;
}
} }

View file

@ -1,11 +1,13 @@
#version 450 #version 450
layout (location = 0) in vec3 inPos; layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;
// todo: pass via specialization constant // todo: pass via specialization constant
#define SHADOW_MAP_CASCADE_COUNT 4 #define SHADOW_MAP_CASCADE_COUNT 4
layout(push_constant) uniform PushConsts { layout(push_constant) uniform PushConsts {
vec4 position;
uint cascadeIndex; uint cascadeIndex;
} pushConsts; } pushConsts;
@ -13,11 +15,15 @@ layout (binding = 0) uniform UBO {
mat4[SHADOW_MAP_CASCADE_COUNT] cascadeViewProjMat; mat4[SHADOW_MAP_CASCADE_COUNT] cascadeViewProjMat;
} ubo; } ubo;
layout (location = 0) out vec2 outUV;
out gl_PerVertex { out gl_PerVertex {
vec4 gl_Position; vec4 gl_Position;
}; };
void main() void main()
{ {
gl_Position = ubo.cascadeViewProjMat[pushConsts.cascadeIndex] * vec4(inPos, 1.0); outUV = inUV;
vec3 pos = inPos + pushConsts.position.xyz;
gl_Position = ubo.cascadeViewProjMat[pushConsts.cascadeIndex] * vec4(pos, 1.0);
} }

View file

@ -2,20 +2,22 @@
#define SHADOW_MAP_CASCADE_COUNT 4 #define SHADOW_MAP_CASCADE_COUNT 4
layout (binding = 1) uniform sampler2DArray shadowMap; layout (set = 0, binding = 1) uniform sampler2DArray shadowMap;
layout (set = 1, binding = 0) uniform sampler2D colorMap;
layout (location = 0) in vec3 inNormal; layout (location = 0) in vec3 inNormal;
layout (location = 1) in vec3 inColor; layout (location = 1) in vec3 inColor;
layout (location = 2) in vec3 inViewPos; layout (location = 2) in vec3 inViewPos;
layout (location = 3) in vec3 inPos; layout (location = 3) in vec3 inPos;
layout (location = 4) in vec2 inUV;
layout (constant_id = 0) const int enablePCF = 0; layout (constant_id = 0) const int enablePCF = 0;
layout (location = 0) out vec4 outFragColor; layout (location = 0) out vec4 outFragColor;
#define ambient 0.1 #define ambient 0.3
layout (binding = 2) uniform UBO { layout (set = 0, binding = 2) uniform UBO {
vec4 cascadeSplits; vec4 cascadeSplits;
mat4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT]; mat4 cascadeViewProjMat[SHADOW_MAP_CASCADE_COUNT];
mat4 inverseViewMat; mat4 inverseViewMat;
@ -69,6 +71,11 @@ float filterPCF(vec4 sc, uint cascadeIndex)
void main() void main()
{ {
vec4 color = texture(colorMap, inUV);
if (color.a < 0.5) {
discard;
}
// Get cascade index for the current fragment's view position // Get cascade index for the current fragment's view position
uint cascadeIndex = 0; uint cascadeIndex = 0;
for(uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i) { for(uint i = 0; i < SHADOW_MAP_CASCADE_COUNT - 1; ++i) {
@ -91,10 +98,11 @@ void main()
vec3 N = normalize(inNormal); vec3 N = normalize(inNormal);
vec3 L = normalize(-ubo.lightDir); vec3 L = normalize(-ubo.lightDir);
vec3 H = normalize(L + inViewPos); vec3 H = normalize(L + inViewPos);
float diffuse = max(dot(N, L), 0.0); float diffuse = max(dot(N, L), ambient);
vec3 lightColor = vec3(1.0); vec3 lightColor = vec3(1.0);
outFragColor.rgb = max(lightColor * (diffuse * inColor), vec3(0.0)); outFragColor.rgb = max(lightColor * (diffuse * color.rgb), vec3(0.0));
outFragColor.rgb *= shadow; outFragColor.rgb *= shadow;
outFragColor.a = color.a;
// Color cascades (if enabled) // Color cascades (if enabled)
if (ubo.colorCascades == 1) { if (ubo.colorCascades == 1) {

View file

@ -15,6 +15,12 @@ layout (location = 0) out vec3 outNormal;
layout (location = 1) out vec3 outColor; layout (location = 1) out vec3 outColor;
layout (location = 2) out vec3 outViewPos; layout (location = 2) out vec3 outViewPos;
layout (location = 3) out vec3 outPos; layout (location = 3) out vec3 outPos;
layout (location = 4) out vec2 outUV;
layout(push_constant) uniform PushConsts {
vec4 position;
uint cascadeIndex;
} pushConsts;
out gl_PerVertex { out gl_PerVertex {
vec4 gl_Position; vec4 gl_Position;
@ -24,8 +30,10 @@ void main()
{ {
outColor = inColor; outColor = inColor;
outNormal = inNormal; outNormal = inNormal;
outPos = inPos; outUV = inUV;
outViewPos = (ubo.view * vec4(inPos.xyz, 1.0)).xyz; vec3 pos = inPos + pushConsts.position.xyz;
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(inPos.xyz, 1.0); outPos = pos;
outViewPos = (ubo.view * vec4(pos.xyz, 1.0)).xyz;
gl_Position = ubo.projection * ubo.view * ubo.model * vec4(pos.xyz, 1.0);
} }

View file

@ -21,6 +21,7 @@
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
#include "VulkanBuffer.hpp" #include "VulkanBuffer.hpp"
#include "VulkanTexture.hpp"
#include "VulkanModel.hpp" #include "VulkanModel.hpp"
#define ENABLE_VALIDATION false #define ENABLE_VALIDATION false
@ -28,7 +29,7 @@
#if defined(__ANDROID__) #if defined(__ANDROID__)
#define SHADOWMAP_DIM 1024 #define SHADOWMAP_DIM 1024
#else #else
#define SHADOWMAP_DIM 2048 #define SHADOWMAP_DIM 4096
#endif #endif
#define SHADOW_MAP_CASCADE_COUNT 4 #define SHADOW_MAP_CASCADE_COUNT 4
@ -41,7 +42,7 @@ public:
bool colorCascades = false; bool colorCascades = false;
bool filterPCF = false; bool filterPCF = false;
float cascadeSplitLambda = 1.0f; float cascadeSplitLambda = 0.95f;
float zNear = 0.5f; float zNear = 0.5f;
float zFar = 48.0f; float zFar = 48.0f;
@ -56,23 +57,27 @@ public:
vks::VERTEX_COMPONENT_NORMAL, vks::VERTEX_COMPONENT_NORMAL,
}); });
std::vector<vks::Model> scenes; std::vector<vks::Model> models;
std::vector<std::string> sceneNames;
int32_t sceneIndex = 0;
struct { struct Material {
vks::Texture2D texture;
VkDescriptorSet descriptorSet;
};
std::vector<Material> materials;
struct uniformBuffers {
vks::Buffer VS; vks::Buffer VS;
vks::Buffer FS; vks::Buffer FS;
} uniformBuffers; } uniformBuffers;
struct { struct UBOVS {
glm::mat4 projection; glm::mat4 projection;
glm::mat4 view; glm::mat4 view;
glm::mat4 model; glm::mat4 model;
glm::vec3 lightDir; glm::vec3 lightDir;
} uboVS; } uboVS;
struct { struct UBOFS {
float cascadeSplits[4]; float cascadeSplits[4];
glm::mat4 cascadeViewProjMat[4]; glm::mat4 cascadeViewProjMat[4];
glm::mat4 inverseViewMat; glm::mat4 inverseViewMat;
@ -81,15 +86,24 @@ public:
int32_t colorCascades; int32_t colorCascades;
} uboFS; } uboFS;
struct { VkPipelineLayout pipelineLayout;
struct Pipelines {
VkPipeline debugShadowMap; VkPipeline debugShadowMap;
VkPipeline sceneShadow; VkPipeline sceneShadow;
VkPipeline sceneShadowPCF; VkPipeline sceneShadowPCF;
} pipelines; } pipelines;
VkPipelineLayout pipelineLayout; struct DescriptorSetLayouts {
VkDescriptorSetLayout base;
VkDescriptorSetLayout material;
} descriptorSetLayouts;
VkDescriptorSet descriptorSet; VkDescriptorSet descriptorSet;
VkDescriptorSetLayout descriptorSetLayout;
// For simplicity all pipelines use the same push constant block layout
struct PushConstBlock {
glm::vec4 position;
uint32_t cascadeIndex;
};
// Resources of the depth map generation pass // Resources of the depth map generation pass
struct DepthPass { struct DepthPass {
@ -139,15 +153,18 @@ public:
VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION)
{ {
title = "Cascaded shadow mapping"; title = "Cascaded shadow mapping";
timerSpeed *= 0.05f; timerSpeed *= 0.025f;
camera.type = Camera::CameraType::firstperson; camera.type = Camera::CameraType::firstperson;
camera.movementSpeed = 2.5f; camera.movementSpeed = 2.5f;
camera.setPerspective(45.0f, (float)width / (float)height, zNear, zFar); camera.setPerspective(45.0f, (float)width / (float)height, zNear, zFar);
camera.setPosition(glm::vec3(2.0f, 0.375f, -1.25f)); camera.setPosition(glm::vec3(0.0f, 0.62f, -2.4f));
camera.setRotation(glm::vec3(-19.0f, 42.0f, 0.0f)); camera.setRotation(glm::vec3(0.0f, -13.0f, 0.0f));
camera.setPosition(glm::vec3(-0.12f, 1.14f, -2.25f));
camera.setRotation(glm::vec3(-17.0f, 7.0f, 0.0f));
settings.overlay = true; settings.overlay = true;
timer = 0.317028880f; timer = 0.2f;
paused = true;
} }
~VulkanExample() ~VulkanExample()
@ -167,10 +184,14 @@ public:
vkDestroyPipelineLayout(device, pipelineLayout, nullptr); vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
vkDestroyPipelineLayout(device, depthPass.pipelineLayout, nullptr); vkDestroyPipelineLayout(device, depthPass.pipelineLayout, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr); vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.base, nullptr);
vkDestroyDescriptorSetLayout(device, descriptorSetLayouts.material, nullptr);
for (auto scene : scenes) { for (auto model : models) {
scene.destroy(); model.destroy();
}
for (auto material : materials) {
material.texture.destroy();
} }
depthPass.uniformBuffer.destroy(); depthPass.uniformBuffer.destroy();
@ -183,6 +204,7 @@ public:
virtual void getEnabledFeatures() virtual void getEnabledFeatures()
{ {
enabledFeatures.samplerAnisotropy = deviceFeatures.samplerAnisotropy;
// Depth clamp to avoid near plane clipping // Depth clamp to avoid near plane clipping
enabledFeatures.depthClamp = deviceFeatures.depthClamp; enabledFeatures.depthClamp = deviceFeatures.depthClamp;
} }
@ -194,7 +216,7 @@ public:
vks::tools::getSupportedDepthFormat(physicalDevice, &depthFormat); vks::tools::getSupportedDepthFormat(physicalDevice, &depthFormat);
depthPass.commandBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false); depthPass.commandBuffer = VulkanExampleBase::createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, false);
// Create a semaphore used to synchronize offscreen rendering and usage // Create a semaphore used to synchronize depth map generation and use
VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo(); VkSemaphoreCreateInfo semaphoreCreateInfo = vks::initializers::semaphoreCreateInfo();
VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &depthPass.semaphore)); VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &depthPass.semaphore));
@ -328,6 +350,48 @@ public:
VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &depth.sampler)); VK_CHECK_RESULT(vkCreateSampler(device, &sampler, nullptr, &depth.sampler));
} }
void renderScene(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VkDescriptorSet descriptorSet, uint32_t cascadeIndex = 0) {
const VkDeviceSize offsets[1] = { 0 };
PushConstBlock pushConstBlock = { glm::vec4(0.0f), cascadeIndex };
std::array<VkDescriptorSet,2> sets;
sets[0] = descriptorSet;
// Floor
sets[1] = materials[0].descriptorSet;
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 2, sets.data(), 0, NULL);
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &models[0].vertices.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, models[0].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffer, models[0].indexCount, 1, 0, 0, 0);
// Trees
const std::vector<glm::vec3> positions = {
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(1.25f, 0.25f, 1.25f),
glm::vec3(-1.25f, -0.2f, 1.25f),
glm::vec3(1.25f, 0.1f, -1.25f),
glm::vec3(-1.25f, -0.25f, -1.25f),
};
for (auto position : positions) {
pushConstBlock.position = glm::vec4(position, 0.0f);
vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
sets[1] = materials[1].descriptorSet;
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 2, sets.data(), 0, NULL);
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &models[1].vertices.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, models[1].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffer, models[1].indexCount, 1, 0, 0, 0);
sets[1] = materials[2].descriptorSet;
vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 2, sets.data(), 0, NULL);
vkCmdBindVertexBuffers(commandBuffer, 0, 1, &models[2].vertices.buffer, offsets);
vkCmdBindIndexBuffer(commandBuffer, models[2].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(commandBuffer, models[2].indexCount, 1, 0, 0, 0);
}
}
void buildOffscreenCommandBuffer() void buildOffscreenCommandBuffer()
{ {
VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo(); VkCommandBufferBeginInfo cmdBufInfo = vks::initializers::commandBufferBeginInfo();
@ -358,12 +422,9 @@ public:
renderPassBeginInfo.framebuffer = cascades[i].frameBuffer; renderPassBeginInfo.framebuffer = cascades[i].frameBuffer;
vkCmdBeginRenderPass(depthPass.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); vkCmdBeginRenderPass(depthPass.commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
vkCmdBindPipeline(depthPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, depthPass.pipeline); vkCmdBindPipeline(depthPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, depthPass.pipeline);
vkCmdPushConstants(depthPass.commandBuffer, depthPass.pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(uint32_t), &i);
VkDeviceSize offsets[1] = { 0 }; VkDeviceSize offsets[1] = { 0 };
vkCmdBindDescriptorSets(depthPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, depthPass.pipelineLayout, 0, 1, &cascades[i].descriptorSet, 0, NULL); vkCmdBindDescriptorSets(depthPass.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, depthPass.pipelineLayout, 0, 1, &cascades[i].descriptorSet, 0, NULL);
vkCmdBindVertexBuffers(depthPass.commandBuffer, 0, 1, &scenes[sceneIndex].vertices.buffer, offsets); renderScene(depthPass.commandBuffer, depthPass.pipelineLayout, cascades[i].descriptorSet, i);
vkCmdBindIndexBuffer(depthPass.commandBuffer, scenes[sceneIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(depthPass.commandBuffer, scenes[sceneIndex].indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(depthPass.commandBuffer); vkCmdEndRenderPass(depthPass.commandBuffer);
} }
@ -407,16 +468,15 @@ public:
if (displayDepthMap) { if (displayDepthMap) {
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL); vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.debugShadowMap); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelines.debugShadowMap);
vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uint32_t), &displayDepthMapCascadeIndex); PushConstBlock pushConstBlock = {};
pushConstBlock.cascadeIndex = displayDepthMapCascadeIndex;
vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstBlock), &pushConstBlock);
vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0); vkCmdDraw(drawCmdBuffers[i], 3, 1, 0, 0);
} }
// Render shadowed scene // Render shadowed scene
vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, (filterPCF) ? pipelines.sceneShadowPCF : pipelines.sceneShadow); vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, (filterPCF) ? pipelines.sceneShadowPCF : pipelines.sceneShadow);
vkCmdBindVertexBuffers(drawCmdBuffers[i], 0, 1, &scenes[sceneIndex].vertices.buffer, offsets); renderScene(drawCmdBuffers[i], pipelineLayout, descriptorSet);
vkCmdBindIndexBuffer(drawCmdBuffers[i], scenes[sceneIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32);
vkCmdDrawIndexed(drawCmdBuffers[i], scenes[sceneIndex].indexCount, 1, 0, 0, 0);
vkCmdEndRenderPass(drawCmdBuffers[i]); vkCmdEndRenderPass(drawCmdBuffers[i]);
@ -426,80 +486,65 @@ public:
void loadAssets() void loadAssets()
{ {
scenes.resize(2); materials.resize(3);
scenes[0].loadFromFile(getAssetPath() + "models/trees.dae", vertexLayout, 1.0f, vulkanDevice, queue); materials[0].texture.loadFromFile(getAssetPath() + "textures/gridlines.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
scenes[1].loadFromFile(getAssetPath() + "models/samplescene.dae", vertexLayout, 0.25f, vulkanDevice, queue); materials[1].texture.loadFromFile(getAssetPath() + "textures/oak_bark.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
sceneNames = { "Trees", "Teapots and pillars" }; materials[2].texture.loadFromFile(getAssetPath() + "textures/oak_leafs.ktx", VK_FORMAT_R8G8B8A8_UNORM, vulkanDevice, queue);
} models.resize(3);
models[0].loadFromFile(getAssetPath() + "models/terrain_simple.dae", vertexLayout, 1.0f, vulkanDevice, queue);
void setupDescriptorPool() models[1].loadFromFile(getAssetPath() + "models/oak_trunk.dae", vertexLayout, 2.0f, vulkanDevice, queue);
{ models[2].loadFromFile(getAssetPath() + "models/oak_leafs.dae", vertexLayout, 2.0f, vulkanDevice, queue);
std::vector<VkDescriptorPoolSize> poolSizes = {
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 12),
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 32)
};
VkDescriptorPoolCreateInfo descriptorPoolInfo =
vks::initializers::descriptorPoolCreateInfo(static_cast<uint32_t>(poolSizes.size()), poolSizes.data(), 3 + SHADOW_MAP_CASCADE_COUNT);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
} }
void setupLayoutsAndDescriptors() void setupLayoutsAndDescriptors()
{ {
/* /*
Layouts Descriptor pool
*/
std::vector<VkDescriptorPoolSize> poolSizes = {
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 32),
vks::initializers::descriptorPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 32)
};
VkDescriptorPoolCreateInfo descriptorPoolInfo =
vks::initializers::descriptorPoolCreateInfo(static_cast<uint32_t>(poolSizes.size()), poolSizes.data(), 4 + SHADOW_MAP_CASCADE_COUNT);
VK_CHECK_RESULT(vkCreateDescriptorPool(device, &descriptorPoolInfo, nullptr, &descriptorPool));
/*
Descriptor set layouts
*/ */
// Shared matrices and samplers
std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = { std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0), vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0),
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1), vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 1),
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 2), vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_FRAGMENT_BIT, 2),
vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 3),
}; };
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayout =
vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings); vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayouts.base));
// Shared pipeline layout // Material texture
{ setLayoutBindings = {
// Pass cascade index as push constant vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, 0),
VkPushConstantRange pushConstantRange = };
vks::initializers::pushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(uint32_t), 0); descriptorLayout = vks::initializers::descriptorSetLayoutCreateInfo(setLayoutBindings);
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayouts.material));
vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
}
// Offscreen pipeline layout
{
// Pass cascade matrix as push constant
VkPushConstantRange pushConstantRange =
vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(glm::mat4), 0);
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo =
vks::initializers::pipelineLayoutCreateInfo(&descriptorSetLayout, 1);
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &depthPass.pipelineLayout));
}
/* /*
Dscriptor sets Descriptor sets
*/ */
std::vector<VkWriteDescriptorSet> writeDescriptorSets; std::vector<VkWriteDescriptorSet> writeDescriptorSets;
VkDescriptorSetAllocateInfo allocInfo =
vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayout, 1);
// Scene rendering / debug display
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
VkDescriptorImageInfo depthMapDescriptor = VkDescriptorImageInfo depthMapDescriptor =
vks::initializers::descriptorImageInfo(depth.sampler, depth.view, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); vks::initializers::descriptorImageInfo(depth.sampler, depth.view, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL);
VkDescriptorSetAllocateInfo allocInfo =
vks::initializers::descriptorSetAllocateInfo(descriptorPool, &descriptorSetLayouts.base, 1);
// Scene rendering / debug display
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet));
writeDescriptorSets = { writeDescriptorSets = {
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.VS.descriptor), vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 0, &uniformBuffers.VS.descriptor),
vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &depthMapDescriptor), vks::initializers::writeDescriptorSet(descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, &depthMapDescriptor),
@ -507,7 +552,7 @@ public:
}; };
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
// Per-cascade descriptor set // Per-cascade descriptor sets
// Each descriptor set represents a single layer of the array texture // Each descriptor set represents a single layer of the array texture
for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++) { for (uint32_t i = 0; i < SHADOW_MAP_CASCADE_COUNT; i++) {
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &cascades[i].descriptorSet)); VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &cascades[i].descriptorSet));
@ -518,6 +563,38 @@ public:
}; };
vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
} }
// Per-material descriptor sets
allocInfo.pSetLayouts = &descriptorSetLayouts.material;
for (auto& material : materials) {
VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &allocInfo, &material.descriptorSet));
VkWriteDescriptorSet writeDescriptorSet = vks::initializers::writeDescriptorSet(material.descriptorSet, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 0, &material.texture.descriptor);
vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr);
}
/*
Pipeline layouts
*/
// Shared pipeline layout (scene and depth map debug display)
{
VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstBlock), 0);
std::array<VkDescriptorSetLayout, 2> setLayouts = { descriptorSetLayouts.base, descriptorSetLayouts.material };
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast<uint32_t>(setLayouts.size()));
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
}
// Depth pass pipeline layout
{
VkPushConstantRange pushConstantRange = vks::initializers::pushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, sizeof(PushConstBlock), 0);
std::array<VkDescriptorSetLayout, 2> setLayouts = { descriptorSetLayouts.base, descriptorSetLayouts.material };
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = vks::initializers::pipelineLayoutCreateInfo(setLayouts.data(), static_cast<uint32_t>(setLayouts.size()));
pipelineLayoutCreateInfo.pushConstantRangeCount = 1;
pipelineLayoutCreateInfo.pPushConstantRanges = &pushConstantRange;
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &depthPass.pipelineLayout));
}
} }
void preparePipelines() void preparePipelines()
@ -597,7 +674,7 @@ public:
/* /*
Shadow mapped scene rendering Shadow mapped scene rendering
*/ */
rasterizationState.cullMode = VK_CULL_MODE_BACK_BIT; rasterizationState.cullMode = VK_CULL_MODE_NONE;
shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmappingcascade/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT); shaderStages[0] = loadShader(getAssetPath() + "shaders/shadowmappingcascade/scene.vert.spv", VK_SHADER_STAGE_VERTEX_BIT);
shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmappingcascade/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT); shaderStages[1] = loadShader(getAssetPath() + "shaders/shadowmappingcascade/scene.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT);
// Use specialization constants to select between horizontal and vertical blur // Use specialization constants to select between horizontal and vertical blur
@ -605,9 +682,7 @@ public:
VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t)); VkSpecializationMapEntry specializationMapEntry = vks::initializers::specializationMapEntry(0, 0, sizeof(uint32_t));
VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(uint32_t), &enablePCF); VkSpecializationInfo specializationInfo = vks::initializers::specializationInfo(1, &specializationMapEntry, sizeof(uint32_t), &enablePCF);
shaderStages[1].pSpecializationInfo = &specializationInfo; shaderStages[1].pSpecializationInfo = &specializationInfo;
// No filtering
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.sceneShadow)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.sceneShadow));
// PCF filtering
enablePCF = 1; enablePCF = 1;
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.sceneShadowPCF)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.sceneShadowPCF));
@ -816,7 +891,6 @@ public:
updateCascades(); updateCascades();
prepareShadowMaps(); prepareShadowMaps();
prepareUniformBuffers(); prepareUniformBuffers();
setupDescriptorPool();
setupLayoutsAndDescriptors(); setupLayoutsAndDescriptors();
preparePipelines(); preparePipelines();
buildCommandBuffers(); buildCommandBuffers();
@ -845,10 +919,6 @@ public:
virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay) virtual void OnUpdateUIOverlay(vks::UIOverlay *overlay)
{ {
if (overlay->header("Settings")) { if (overlay->header("Settings")) {
if (overlay->comboBox("Scenes", &sceneIndex, sceneNames)) {
buildCommandBuffers();
buildOffscreenCommandBuffer();
}
if (overlay->sliderFloat("Split lambda", &cascadeSplitLambda, 0.1f, 1.0f)) { if (overlay->sliderFloat("Split lambda", &cascadeSplitLambda, 0.1f, 1.0f)) {
updateCascades(); updateCascades();
updateUniformBuffers(); updateUniformBuffers();