From 07f23c39a5ec7143f559cdba4a56920dc4bc7def Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Wed, 23 Jun 2021 10:31:07 +0200
Subject: [PATCH] [#82] EVSM prototype

---
 .../resources/shaders/lightInfo.inc           |  2 +-
 .../resources/shaders/shadow.frag             |  7 ++--
 .../resources/shaders/shadowMapping.inc       | 41 +++++++++++++++++--
 projects/voxelization/src/ShadowMapping.cpp   |  8 ++--
 projects/voxelization/src/ShadowMapping.hpp   |  4 +-
 projects/voxelization/src/main.cpp            | 17 ++++----
 6 files changed, 60 insertions(+), 19 deletions(-)

diff --git a/projects/voxelization/resources/shaders/lightInfo.inc b/projects/voxelization/resources/shaders/lightInfo.inc
index ed7f8d8b..c0df6551 100644
--- a/projects/voxelization/resources/shaders/lightInfo.inc
+++ b/projects/voxelization/resources/shaders/lightInfo.inc
@@ -6,7 +6,7 @@ struct LightInfo{
     vec3 sunColor;      
     float sunStrength;
     mat4 lightMatrix;
-    float exponentialWarp;
+    vec2 warps;
 };
 
 #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 a0bc121d..83500f94 100644
--- a/projects/voxelization/resources/shaders/shadow.frag
+++ b/projects/voxelization/resources/shaders/shadow.frag
@@ -8,11 +8,12 @@ layout(set=0, binding=0) uniform LightInfoBuffer {
     LightInfo lightInfo;
 };
 
-layout(location = 0) out float outExponentialDepth;
+layout(location = 0) out vec4 outMoments;
 
 layout(location = 0) in vec4 passPos;
 
 void main()	{
-    float z = passPos.z / passPos.w;
-    outExponentialDepth = exp(z * lightInfo.exponentialWarp);
+    float z         = passPos.z / passPos.w;
+    vec2  zWarped   = applyDepthWarp(z,     lightInfo.warps);
+    outMoments      = vec4(zWarped, zWarped*zWarped);
 }
\ No newline at end of file
diff --git a/projects/voxelization/resources/shaders/shadowMapping.inc b/projects/voxelization/resources/shaders/shadowMapping.inc
index e0a218d5..91461c91 100644
--- a/projects/voxelization/resources/shaders/shadowMapping.inc
+++ b/projects/voxelization/resources/shaders/shadowMapping.inc
@@ -3,6 +3,32 @@
 
 #include "lightInfo.inc"
 
+vec2 applyDepthWarp(float z, vec2 warp){
+    z               = 2 * z - 1;
+    float positive  =  exp( z * warp.x);
+    float negative  = -exp(-z * warp.y);
+    return vec2(positive, negative);
+}
+
+float rescale(float a, float b, float v)
+{
+    return clamp((v - a) / (b - a), 0, 1);
+}
+
+float reduceVSMBleeding(float shadowValue, float newMin)
+{
+   return rescale(newMin, 1.0f, shadowValue);
+}
+
+float chebyshevInequality(float mean, float meanSquare, float sampleIn){
+    float variance  = meanSquare -  mean * mean;
+    float d         = sampleIn - mean;
+    float pMax      = clamp(variance / (variance + d*d), 0, 1);
+    pMax            = reduceVSMBleeding(pMax, 0.1);
+    
+    return pMax;
+}
+
 float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sampler shadowMapSampler){
     vec4 lightPos = lightInfo.lightMatrix * vec4(worldPos, 1);
     lightPos /= lightPos.w;
@@ -12,11 +38,18 @@ float shadowTest(vec3 worldPos, LightInfo lightInfo, texture2D shadowMap, sample
         return 1;
     }
     
-    lightPos.z = clamp(lightPos.z, 0, 1);
+    lightPos.z          = clamp(lightPos.z, 0, 1);
+    vec2 warpedSample   = applyDepthWarp(lightPos.z, lightInfo.warps);
     
-    // using exponential shadow mapping
-    float shadowMapSample = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy).r;
-    return clamp(exp(-lightInfo.exponentialWarp * lightPos.z) * shadowMapSample, 0, 1);
+    // using exponential variance shadow mapping
+    vec4 shadowMapSample    = texture(sampler2D(shadowMap, shadowMapSampler), lightPos.xy);
+    vec2 positiveMoments    = shadowMapSample.rb;
+    vec2 negativeMoments    = shadowMapSample.ga;
+
+    float s1                = chebyshevInequality(positiveMoments.r, positiveMoments.g, warpedSample.x);
+    float s2                = chebyshevInequality(negativeMoments.r, negativeMoments.g, warpedSample.y);
+
+    return min(s1, s2);
 }
 
 #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 456ef2cd..83ce118a 100644
--- a/projects/voxelization/src/ShadowMapping.cpp
+++ b/projects/voxelization/src/ShadowMapping.cpp
@@ -103,7 +103,7 @@ glm::mat4 computeShadowViewProjectionMatrix(
 	return vulkanCorrectionMatrix * crop * view;
 }
 
-const vk::Format    shadowMapFormat      = vk::Format::eR32Sfloat;
+const vk::Format    shadowMapFormat      = vk::Format::eR32G32B32A32Sfloat;
 const vk::Format    shadowMapDepthFormat = vk::Format::eD16Unorm;
 const uint32_t      shadowMapResolution  = 2048;
 
@@ -156,7 +156,8 @@ void ShadowMapping::recordShadowMapRendering(
 	const glm::vec3&                    lightColor,
 	float                               lightStrength,
 	float                               maxShadowDistance,
-	float                               exponentialWarp,
+	float                               exponentialWarpPositive,
+	float                               exponentialWarpNegative,
 	const std::vector<vkcv::Mesh>&      meshes,
 	const std::vector<glm::mat4>&       modelMatrices,
 	const vkcv::camera::Camera&         camera,
@@ -170,7 +171,8 @@ 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.exponentialWarpPositive = exponentialWarpPositive;
+	lightInfo.exponentialWarpNegative = exponentialWarpNegative;
 
 	lightInfo.lightMatrix = computeShadowViewProjectionMatrix(
 		lightInfo.direction,
diff --git a/projects/voxelization/src/ShadowMapping.hpp b/projects/voxelization/src/ShadowMapping.hpp
index d72ca06c..541ad383 100644
--- a/projects/voxelization/src/ShadowMapping.hpp
+++ b/projects/voxelization/src/ShadowMapping.hpp
@@ -13,7 +13,8 @@ struct LightInfo {
 	glm::vec3   sunColor;
 	float       sunStrength;
 	glm::mat4   lightMatrix;
-    float       exponentialWarp;
+	float       exponentialWarpPositive;
+	float       exponentialWarpNegative;
 };
 
 class ShadowMapping {
@@ -27,6 +28,7 @@ public:
 		float                               lightStrength,
 		float                               maxShadowDistance,
 		float                               exponentialWarp,
+		float                               exponentialWarpNegative,
 		const std::vector<vkcv::Mesh>&      meshes,
 		const std::vector<glm::mat4>&       modelMatrices,
 		const vkcv::camera::Camera&         camera,
diff --git a/projects/voxelization/src/main.cpp b/projects/voxelization/src/main.cpp
index a56113d0..b488426d 100644
--- a/projects/voxelization/src/main.cpp
+++ b/projects/voxelization/src/main.cpp
@@ -325,11 +325,12 @@ 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;
-	float       shadowExponentialWarp   = 60.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       shadowExponentialWarpPositive   = 60.f;
+	float       shadowExponentialWarpNegative   = 60.f;
 
 	int     voxelVisualisationMip   = 0;
 	float   voxelizationExtent      = 30.f;
@@ -378,7 +379,8 @@ int main(int argc, const char** argv) {
 			lightColor,
 			lightStrength,
 			maxShadowDistance,
-			shadowExponentialWarp,
+			shadowExponentialWarpPositive,
+			shadowExponentialWarpNegative,
 			meshes,
 			modelMatrices,
 			cameraManager.getActiveCamera(),
@@ -446,7 +448,8 @@ 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::DragFloat("Shadow exponential warp positive", &shadowExponentialWarpPositive);
+		ImGui::DragFloat("Shadow exponential warp negative", &shadowExponentialWarpNegative);
 
 		ImGui::Checkbox("Draw voxel visualisation", &renderVoxelVis);
 		ImGui::SliderInt("Visualisation mip",       &voxelVisualisationMip, 0, 7);
-- 
GitLab