Преглед изворни кода

Add PCSS/None filter support

Popov72 пре 5 година
родитељ
комит
4aa5d32c32

+ 52 - 31
src/Shaders/ShadersInclude/lightFragment.fx

@@ -127,7 +127,7 @@
     #ifdef SHADOW{X}
         #ifdef SHADOWCSM{X}
             #ifdef SHADOWCSMDEBUG{X}
-                const vec3 vCascadeColorsMultiplier[8] = vec3[8]
+                const vec3 vCascadeColorsMultiplier{X}[8] = vec3[8]
                 (
                     vec3 ( 1.5, 0.0, 0.0 ),
                     vec3 ( 0.0, 1.5, 0.0 ),
@@ -138,56 +138,77 @@
                     vec3 ( 0.0, 1.0, 5.5 ),
                     vec3 ( 0.5, 3.5, 0.75 )
                 );
-                vec3 shadowDebug;
+                vec3 shadowDebug{X};
             #endif
 
-            int index = SHADOWCSMNUM_CASCADES{X} - 1;
+            int index{X} = SHADOWCSMNUM_CASCADES{X} - 1;
 
-            float diff = 0.;
-            float frustrumLenght = 0.;
-            float previousFrustrumMax = 0.;
+            float diff{X} = 0.;
+            float frustrumLength{X} = 0.;
+            float previousFrustrumMax{X} = 0.;
             for (int i = 0; i < SHADOWCSMNUM_CASCADES{X} - 1; i++) {
-                diff = viewFrustumZCSM{X}[i] - vPositionFromCameraCSM{X}.z;
-                frustrumLenght = viewFrustumZCSM{X}[i] - previousFrustrumMax;
-                previousFrustrumMax = viewFrustumZCSM{X}[i];
+                diff{X} = viewFrustumZ{X}[i] - vPositionFromCamera{X}.z;
+                frustrumLength{X} = viewFrustumZ{X}[i] - previousFrustrumMax{X};
+                previousFrustrumMax{X} = viewFrustumZ{X}[i];
 
-                if (diff >= 0.){
-                    index = i;
+                if (diff{X} >= 0.){
+                    index{X} = i;
                     break;
                 }
             }
 
-            #if defined(SHADOWLOWQUALITY{X})
-                shadow = computeShadowWithCSMPCF1(float(index), vPositionFromLightCSM{X}[index], vDepthMetricCSM{X}[index], shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
-            #elif defined(SHADOWMEDIUMQUALITY{X})
-                shadow = computeShadowWithCSMPCF3(float(index), vPositionFromLightCSM{X}[index], vDepthMetricCSM{X}[index], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+            #if defined(SHADOWPCF{X})
+                #if defined(SHADOWLOWQUALITY{X})
+                    shadow = computeShadowWithCSMPCF1(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #elif defined(SHADOWMEDIUMQUALITY{X})
+                    shadow = computeShadowWithCSMPCF3(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #else
+                    shadow = computeShadowWithCSMPCF5(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #endif
+            #elif defined(SHADOWPCSS{X})
+                #if defined(SHADOWLOWQUALITY{X})
+                    shadow = computeShadowWithCSMPCSS16(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #elif defined(SHADOWMEDIUMQUALITY{X})
+                    shadow = computeShadowWithCSMPCSS32(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #else
+                    shadow = computeShadowWithCSMPCSS64(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #endif
             #else
-                shadow = computeShadowWithCSMPCF5(float(index), vPositionFromLightCSM{X}[index], vDepthMetricCSM{X}[index], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                shadow = computeShadowCSM(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
             #endif
 
             #ifdef SHADOWCSMDEBUG{X}
-                shadowDebug = vec3(shadow) * vCascadeColorsMultiplier[index];
+                shadowDebug{X} = vec3(shadow) * vCascadeColorsMultiplier{X}[index{X}];
             #endif
 
-            float diffRatio = clamp(diff / frustrumLenght, 0., 1.) * 4.; // 25 % linear
-            #ifdef SHADOWCSMDEBUG{X}
-                int realIndex = index;
-            #endif
-            if (index < (SHADOWCSMNUM_CASCADES{X} - 1) && diffRatio < 1.)
+            float diffRatio{X} = clamp(diff{X} / frustrumLength{X}, 0., 1.) * splitBlendFactor{X};
+            if (index{X} < (SHADOWCSMNUM_CASCADES{X} - 1) && diffRatio{X} < 1.)
             {
-                index += 1;
+                index{X} += 1;
                 float nextShadow = 0.;
-                #if defined(SHADOWLOWQUALITY{X})
-                    nextShadow = computeShadowWithCSMPCF1(float(index), vPositionFromLightCSM{X}[index], vDepthMetricCSM{X}[index], shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
-                #elif defined(SHADOWMEDIUMQUALITY{X})
-                    nextShadow = computeShadowWithCSMPCF3(float(index), vPositionFromLightCSM{X}[index], vDepthMetricCSM{X}[index], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                #if defined(SHADOWPCF{X})
+                    #if defined(SHADOWLOWQUALITY{X})
+                        nextShadow = computeShadowWithCSMPCF1(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    #elif defined(SHADOWMEDIUMQUALITY{X})
+                        nextShadow = computeShadowWithCSMPCF3(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    #else
+                        nextShadow = computeShadowWithCSMPCF5(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    #endif
+                #elif defined(SHADOWPCSS{X})
+                    #if defined(SHADOWLOWQUALITY{X})
+                        nextShadow = computeShadowWithCSMPCSS16(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    #elif defined(SHADOWMEDIUMQUALITY{X})
+                        nextShadow = computeShadowWithCSMPCSS32(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    #else
+                        nextShadow = computeShadowWithCSMPCSS64(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    #endif
                 #else
-                    nextShadow = computeShadowWithCSMPCF5(float(index), vPositionFromLightCSM{X}[index], vDepthMetricCSM{X}[index], shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+                    nextShadow = computeShadowCSM(float(index{X}), vPositionFromLight{X}[index{X}], vDepthMetric{X}[index{X}], shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
                 #endif
 
-                shadow = mix(nextShadow, shadow, diffRatio);
+                shadow = mix(nextShadow, shadow, diffRatio{X});
                 #ifdef SHADOWCSMDEBUG{X}
-                    shadowDebug = mix(vec3(nextShadow) * vCascadeColorsMultiplier[index], shadowDebug, diffRatio);
+                    shadowDebug{X} = mix(vec3(nextShadow) * vCascadeColorsMultiplier{X}[index{X}], shadowDebug{X}, diffRatio{X});
                 #endif
             }
         #elif SHADOWCLOSEESM{X}
@@ -268,7 +289,7 @@
             #endif
         #else
             #ifdef SHADOWCSMDEBUG{X}
-                diffuseBase += info.diffuse * shadowDebug;
+                diffuseBase += info.diffuse * shadowDebug{X};
             #else        
                 diffuseBase += info.diffuse * shadow;
             #endif

+ 19 - 1
src/Shaders/ShadersInclude/lightFragmentDeclaration.fx

@@ -8,7 +8,25 @@
 		vec4 vLightSpecular{X} = vec4(0.);
 	#endif
 	#ifdef SHADOW{X}
-		#if defined(SHADOWCUBE{X})
+        #ifdef SHADOWCSM{X}
+            uniform mat4 lightMatrix{X}[SHADOWCSMNUM_CASCADES{X}];
+            uniform mat4 camViewMatCSM{X};
+            uniform float viewFrustumZ{X}[SHADOWCSMNUM_CASCADES{X}];
+            uniform float splitBlendFactor{X};
+
+            varying vec4 vPositionFromLight{X}[SHADOWCSMNUM_CASCADES{X}];
+            varying float vDepthMetric{X}[SHADOWCSMNUM_CASCADES{X}];
+            varying vec4 vPositionFromCamera{X};
+
+            #if defined(SHADOWPCSS{X})
+                uniform highp sampler2DArrayShadow shadowSampler{X};
+                uniform highp sampler2DArray depthSampler{X};
+            #elif defined(SHADOWPCF{X})
+                uniform highp sampler2DArrayShadow shadowSampler{X};
+            #else
+                uniform highp sampler2DArray shadowSampler{X};
+            #endif
+        #elif defined(SHADOWCUBE{X})
 			uniform samplerCube shadowSampler{X};
 		#else
 			varying vec4 vPositionFromLight{X};

+ 10 - 12
src/Shaders/ShadersInclude/lightUboDeclaration.fx

@@ -22,24 +22,22 @@
 #endif
 #ifdef SHADOW{X}
 	#ifdef SHADOWCSM{X}
-		uniform mat4 lightMatrixCSM{X}[SHADOWCSMNUM_CASCADES{X}];
-		uniform mat4 camViewMatCSM{X};
-		uniform float viewFrustumZCSM{X}[SHADOWCSMNUM_CASCADES{X}];
-		varying vec4 vPositionFromLightCSM{X}[SHADOWCSMNUM_CASCADES{X}];
-		varying float vDepthMetricCSM{X}[SHADOWCSMNUM_CASCADES{X}];
-		varying vec4 vPositionFromCameraCSM{X};
+		uniform mat4 lightMatrix{X}[SHADOWCSMNUM_CASCADES{X}];
+		uniform float viewFrustumZ{X}[SHADOWCSMNUM_CASCADES{X}];
+        uniform float splitBlendFactor{X};
+
+		varying vec4 vPositionFromLight{X}[SHADOWCSMNUM_CASCADES{X}];
+		varying float vDepthMetric{X}[SHADOWCSMNUM_CASCADES{X}];
+		varying vec4 vPositionFromCamera{X};
 
 		#if defined(SHADOWPCSS{X})
 			uniform highp sampler2DArrayShadow shadowSampler{X};
 			uniform highp sampler2DArray depthSampler{X};
-		#else
+		#elif defined(SHADOWPCF{X})
 			uniform highp sampler2DArrayShadow shadowSampler{X};
+		#else
+			uniform highp sampler2DArray shadowSampler{X};
 		#endif
-
-		//uniform sampler2D shadowSamplerArrayCSM{X}[NUM_CASCADESP{X}];
-		// varying vec4 vPositionFromLight{X};
-		// varying float vDepthMetric{X};
-		// uniform mat4 lightMatrix{X};
 	#elif defined(SHADOWCUBE{X})
 		uniform samplerCube shadowSampler{X};		
 	#else

+ 102 - 0
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -113,6 +113,32 @@
         return esm;
     }
 
+    float computeShadowCSM(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray shadowSampler, float darkness, float frustumEdgeFalloff)
+    {
+        vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+        vec2 uv = 0.5 * clipSpace.xy + vec2(0.5);
+        vec3 uvLayer = vec3(uv.x, uv.y, layer);
+
+        if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+        {
+            return 1.0;
+        }
+
+        float shadowPixelDepth = clamp(depthMetric, 0., 1.0);
+
+        #ifndef SHADOWFLOAT
+            float shadow = unpack(texture2D(shadowSampler, uvLayer));
+        #else
+            float shadow = texture2D(shadowSampler, uvLayer).x;
+        #endif
+
+        if (shadowPixelDepth > shadow)
+        {
+            return computeFallOff(darkness, clipSpace.xy, frustumEdgeFalloff);
+        }
+        return 1.;
+    }
+
     float computeShadow(vec4 vPositionFromLight, float depthMetric, sampler2D shadowSampler, float darkness, float frustumEdgeFalloff)
     {
         vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
@@ -555,6 +581,67 @@
         // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
         // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
         // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
+        float computeShadowWithCSMPCSS(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers)
+        {
+            if (depthMetric > 1.0 || depthMetric < 0.0) {
+                return 1.0;
+            }
+
+            vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+            vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
+            vec4 uvDepthLayer = vec4(uvDepth.x, uvDepth.y, layer, uvDepth.z);
+
+            float blockerDepth = 0.0;
+            float sumBlockerDepth = 0.0;
+            float numBlocker = 0.0;
+            for (int i = 0; i < searchTapCount; i ++) {
+                blockerDepth = texture(depthSampler, vec3(uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PoissonSamplers32[i].xy), layer)).r;
+                if (blockerDepth < depthMetric) {
+                    sumBlockerDepth += blockerDepth;
+                    numBlocker++;
+                }
+            }
+
+            if (numBlocker < 1.0) {
+                return 1.0;
+            }
+            float avgBlockerDepth = sumBlockerDepth / numBlocker;
+
+            // Offset preventing aliasing on contact.
+            float AAOffset = shadowMapSizeInverse * 10.;
+            // Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
+            // float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
+            float penumbraRatio = ((depthMetric - avgBlockerDepth) + AAOffset);
+            float filterRadius = penumbraRatio * lightSizeUV * shadowMapSizeInverse;
+
+            float random = getRand(vPositionFromLight.xy);
+            float rotationAngle = random * 3.1415926;
+            vec2 rotationVector = vec2(cos(rotationAngle), sin(rotationAngle));
+
+            float shadow = 0.;
+            for (int i = 0; i < pcfTapCount; i++) {
+                vec4 offset = vec4(poissonSamplers[i], 0.);
+                // Rotated offset.
+                offset = vec4(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0., 0.);
+                shadow += texture2D(shadowSampler, uvDepthLayer + offset * filterRadius);
+            }
+            shadow /= float(pcfTapCount);
+
+            // Blocker distance falloff
+            shadow = mix(shadow, 1., depthMetric - avgBlockerDepth);
+
+            // Apply darkness
+            shadow = mix(darkness, 1., shadow);
+
+            // Apply light frustrum fallof
+            return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
+        }
+
+        // PCSS
+        // This helps to achieve a contact hardening effect on the shadow
+        // It uses 16 Taps for search and a 32 PCF taps in a randomly rotating poisson sampling disc.
+        // This is heavily inspired from http://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
+        // and http://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
         float computeShadowWithPCSS(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff, int searchTapCount, int pcfTapCount, vec3[64] poissonSamplers)
         {
             if (depthMetric > 1.0 || depthMetric < 0.0) {
@@ -624,5 +711,20 @@
         {
             return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
         }
+
+        float computeShadowWithCSMPCSS16(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+        {
+            return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32);
+        }
+
+        float computeShadowWithCSMPCSS32(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+        {
+            return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32);
+        }
+
+        float computeShadowWithCSMPCSS64(float layer, vec4 vPositionFromLight, float depthMetric, highp sampler2DArray depthSampler, highp sampler2DArrayShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+        {
+            return computeShadowWithCSMPCSS(layer, vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
+        }
     #endif
 #endif