From 423bc642a118a7d9c58dac2068d9aa0e4a94de7a Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Tue, 22 Jun 2021 21:03:46 +0200
Subject: [PATCH] [#82] Exponential shadow mapping prototype

---
 .../resources/shaders/lightInfo.inc           |  8 ++++-
 .../resources/shaders/shadow.frag             | 14 +++++++-
 .../resources/shaders/shadow.vert             |  7 ++++
 .../resources/shaders/shadowMapping.inc       | 14 +++++---
 projects/voxelization/src/ShadowMapping.cpp   | 33 +++++++++++++------
 projects/voxelization/src/ShadowMapping.hpp   |  6 +++-
 projects/voxelization/src/main.cpp            | 11 ++++---
 7 files changed, 72 insertions(+), 21 deletions(-)

diff --git a/projects/voxelization/resources/shaders/lightInfo.inc b/projects/voxelization/resources/shaders/lightInfo.inc
index 4345d4f1..ed7f8d8b 100644
--- a/projects/voxelization/resources/shaders/lightInfo.inc
+++ b/projects/voxelization/resources/shaders/lightInfo.inc
@@ -1,6 +1,12 @@
+#ifndef LIGHT_INFO_INC
+#define LIGHT_INFO_INC
+
 struct LightInfo{
     vec3 L;             float padding;
     vec3 sunColor;      
     float sunStrength;
     mat4 lightMatrix;
-};
\ No newline at end of file
+    float exponentialWarp;
+};
+
+#endif // #ifndef LIGHT_INFO_INC
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/shadow.frag b/projects/voxelization/resources/shaders/shadow.frag
index 848f853f..a0bc121d 100644
--- a/projects/voxelization/resources/shaders/shadow.frag
+++ b/projects/voxelization/resources/shaders/shadow.frag
@@ -1,6 +1,18 @@
 #version 450
 #extension GL_ARB_separate_shader_objects : enable
+#extension GL_GOOGLE_include_directive : enable
 
-void main()	{
+#include "shadowMapping.inc"
+
+layout(set=0, binding=0) uniform LightInfoBuffer {
+    LightInfo lightInfo;
+};
+
+layout(location = 0) out float outExponentialDepth;
 
+layout(location = 0) in vec4 passPos;
+
+void main()	{
+    float z = passPos.z / passPos.w;
+    outExponentialDepth = exp(z * lightInfo.exponentialWarp);
 }
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/shadow.vert b/projects/voxelization/resources/shaders/shadow.vert
index e0f41d42..f6b99c39 100644
--- a/projects/voxelization/resources/shaders/shadow.vert
+++ b/projects/voxelization/resources/shaders/shadow.vert
@@ -1,12 +1,19 @@
 #version 450
 #extension GL_ARB_separate_shader_objects : enable
 
+#extension GL_GOOGLE_include_directive : enable
+
+#include "lightInfo.inc"
+
 layout(location = 0) in vec3 inPosition;
 
 layout( push_constant ) uniform constants{
     mat4 mvp;
 };
 
+layout(location = 0) out vec4 passPos;
+
 void main()	{
 	gl_Position = mvp * vec4(inPosition, 1.0);
+    passPos = gl_Position;
 }
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/shadowMapping.inc b/projects/voxelization/resources/shaders/shadowMapping.inc
index 1fa34a38..e0a218d5 100644
--- a/projects/voxelization/resources/shaders/shadowMapping.inc
+++ b/projects/voxelization/resources/shaders/shadowMapping.inc
@@ -1,3 +1,8 @@
+#ifndef SHADOW_MAPPING_INC
+#define SHADOW_MAPPING_INC
+
+#include "lightInfo.inc"
+
 float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sampler shadowMapSampler){
     vec4 lightPos = lightInfo.lightMatrix * vec4(worldPos, 1);
     lightPos /= lightPos.w;
@@ -9,8 +14,9 @@ float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sample
     
     lightPos.z = clamp(lightPos.z, 0, 1);
     
+    // using exponential shadow mapping
     float shadowMapSample = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy).r;
-    float bias = 0.01f;
-    shadowMapSample += bias;
-    return shadowMapSample < lightPos.z ? 0 : 1;
-}
\ No newline at end of file
+    return clamp(exp(-lightInfo.exponentialWarp * lightPos.z) * shadowMapSample, 0, 1);
+}
+
+#endif // #ifndef SHADOW_MAPPING_INC
\ No newline at end of file
diff --git a/projects/voxelization/src/ShadowMapping.cpp b/projects/voxelization/src/ShadowMapping.cpp
index 938aae1f..456ef2cd 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -103,37 +103,48 @@ glm::mat4 computeShadowViewProjectionMatrix(
 	return vulkanCorrectionMatrix * crop * view;
 }
 
-const vk::Format    shadowMapFormat     = vk::Format::eD16Unorm;
-const uint32_t      shadowMapResolution = 2048;
+const vk::Format    shadowMapFormat      = vk::Format::eR32Sfloat;
+const vk::Format    shadowMapDepthFormat = vk::Format::eD16Unorm;
+const uint32_t      shadowMapResolution  = 2048;
 
 ShadowMapping::ShadowMapping(vkcv::Core* corePtr, const vkcv::VertexLayout& vertexLayout) : 
 	m_corePtr(corePtr),
-	m_shadowMap(corePtr->createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution)),
+	m_shadowMap(corePtr->createImage(shadowMapFormat, shadowMapResolution, shadowMapResolution, 1, false, false, true)),
+	m_shadowMapDepth(corePtr->createImage(shadowMapDepthFormat, shadowMapResolution, shadowMapResolution)),
 	m_lightInfoBuffer(corePtr->createBuffer<LightInfo>(vkcv::BufferType::UNIFORM, sizeof(glm::vec3))){
 
 	vkcv::ShaderProgram shadowShader = loadShadowShader();
 
+	// descriptor set
+	m_shadowDescriptorSet = corePtr->createDescriptorSet(shadowShader.getReflectedDescriptors()[0]);
+	vkcv::DescriptorWrites shadowDescriptorWrites;
+	shadowDescriptorWrites.uniformBufferWrites = { vkcv::UniformBufferDescriptorWrite(0, m_lightInfoBuffer.getHandle()) };
+	corePtr->writeDescriptorSet(m_shadowDescriptorSet, shadowDescriptorWrites);
+
+	// pass
 	const std::vector<vkcv::AttachmentDescription> shadowAttachments = {
-		vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat)
+		vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapFormat),
+		vkcv::AttachmentDescription(vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, shadowMapDepthFormat)
 	};
 	const vkcv::PassConfig shadowPassConfig(shadowAttachments);
 	m_shadowMapPass = corePtr->createPass(shadowPassConfig);
+
+	// pipeline
 	vkcv::PipelineConfig shadowPipeConfig{
 		shadowShader,
 		shadowMapResolution,
 		shadowMapResolution,
 		m_shadowMapPass,
 		vertexLayout,
-		{},
+		{ corePtr->getDescriptorSet(m_shadowDescriptorSet).layout },
 		false
 	};
 	shadowPipeConfig.m_EnableDepthClamping = true;
 	m_shadowMapPipe = corePtr->createGraphicsPipeline(shadowPipeConfig);
 
-	// shadow map
 	m_shadowSampler = corePtr->createSampler(
-		vkcv::SamplerFilterType::NEAREST,
-		vkcv::SamplerFilterType::NEAREST,
+		vkcv::SamplerFilterType::LINEAR,
+		vkcv::SamplerFilterType::LINEAR,
 		vkcv::SamplerMipmapMode::NEAREST,
 		vkcv::SamplerAddressMode::CLAMP_TO_EDGE
 	);
@@ -145,6 +156,7 @@ void ShadowMapping::recordShadowMapRendering(
 	const glm::vec3&                    lightColor,
 	float                               lightStrength,
 	float                               maxShadowDistance,
+	float                               exponentialWarp,
 	const std::vector<vkcv::Mesh>&      meshes,
 	const std::vector<glm::mat4>&       modelMatrices,
 	const vkcv::camera::Camera&         camera,
@@ -158,6 +170,7 @@ void ShadowMapping::recordShadowMapRendering(
 		std::cos(lightAngleRadian.x) * std::cos(lightAngleRadian.y),
 		std::sin(lightAngleRadian.x),
 		std::cos(lightAngleRadian.x) * std::sin(lightAngleRadian.y)));
+	lightInfo.exponentialWarp = exponentialWarp;
 
 	lightInfo.lightMatrix = computeShadowViewProjectionMatrix(
 		lightInfo.direction,
@@ -175,7 +188,7 @@ void ShadowMapping::recordShadowMapRendering(
 
 	std::vector<vkcv::DrawcallInfo> drawcalls;
 	for (const auto& mesh : meshes) {
-		drawcalls.push_back(vkcv::DrawcallInfo(mesh, {}));
+		drawcalls.push_back(vkcv::DrawcallInfo(mesh, { vkcv::DescriptorSetUsage(0, m_corePtr->getDescriptorSet(m_shadowDescriptorSet).vulkanHandle) }));
 	}
 
 	m_corePtr->recordDrawcallsToCmdStream(
@@ -184,7 +197,7 @@ void ShadowMapping::recordShadowMapRendering(
 		m_shadowMapPipe,
 		shadowPushConstantData,
 		drawcalls,
-		{ m_shadowMap.getHandle() });
+		{ m_shadowMap.getHandle(), m_shadowMapDepth.getHandle() });
 	m_corePtr->prepareImageForSampling(cmdStream, m_shadowMap.getHandle());
 }
 
diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp
index 6bbceff9..d72ca06c 100644
--- a/projects/voxelization/src/ShadowMapping.hpp
+++ b/projects/voxelization/src/ShadowMapping.hpp
@@ -13,6 +13,7 @@ struct LightInfo {
 	glm::vec3   sunColor;
 	float       sunStrength;
 	glm::mat4   lightMatrix;
+    float       exponentialWarp;
 };
 
 class ShadowMapping {
@@ -23,8 +24,9 @@ public:
 		const vkcv::CommandStreamHandle&    cmdStream,
 		const glm::vec2&                    lightAngleRadian,
 		const glm::vec3&                    lightColor,
-		const float                         lightStrength,
+		float                               lightStrength,
 		float                               maxShadowDistance,
+		float                               exponentialWarp,
 		const std::vector<vkcv::Mesh>&      meshes,
 		const std::vector<glm::mat4>&       modelMatrices,
 		const vkcv::camera::Camera&         camera,
@@ -39,8 +41,10 @@ private:
 	vkcv::Core* m_corePtr;
 
 	vkcv::Image             m_shadowMap;
+	vkcv::Image             m_shadowMapDepth;
 	vkcv::SamplerHandle     m_shadowSampler;
 	vkcv::Buffer<LightInfo> m_lightInfoBuffer;
+	vkcv::DescriptorSetHandle m_shadowDescriptorSet;
 
 	vkcv::PassHandle        m_shadowMapPass;
 	vkcv::PipelineHandle    m_shadowMapPipe;
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index 36b6f9d1..a56113d0 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -325,10 +325,11 @@ int main(int argc, const char** argv) {
 
 	vkcv::gui::GUI gui(core, window);
 
-	glm::vec2   lightAnglesDegree   = glm::vec2(90.f, 0.f);
-	glm::vec3   lightColor          = glm::vec3(1);
-	float       lightStrength       = 25.f;
-    float       maxShadowDistance   = 30.f;
+	glm::vec2   lightAnglesDegree       = glm::vec2(90.f, 0.f);
+	glm::vec3   lightColor              = glm::vec3(1);
+	float       lightStrength           = 25.f;
+	float       maxShadowDistance       = 30.f;
+	float       shadowExponentialWarp   = 60.f;
 
 	int     voxelVisualisationMip   = 0;
 	float   voxelizationExtent      = 30.f;
@@ -377,6 +378,7 @@ int main(int argc, const char** argv) {
 			lightColor,
 			lightStrength,
 			maxShadowDistance,
+			shadowExponentialWarp,
 			meshes,
 			modelMatrices,
 			cameraManager.getActiveCamera(),
@@ -444,6 +446,7 @@ int main(int argc, const char** argv) {
 		ImGui::DragFloat("Sun strength",            &lightStrength);
 		ImGui::DragFloat("Max shadow distance",     &maxShadowDistance);
 		maxShadowDistance = std::max(maxShadowDistance, 1.f);
+		ImGui::DragFloat("Shadow exponential warp", &shadowExponentialWarp);
 
 		ImGui::Checkbox("Draw voxel visualisation", &renderVoxelVis);
 		ImGui::SliderInt("Visualisation mip",       &voxelVisualisationMip, 0, 7);
-- 
GitLab