Bläddra i källkod

Expose PCF Quality

Sebastien Vandenberghe 7 år sedan
förälder
incheckning
f86bae0935

+ 4 - 0
materialsLibrary/src/gradient/babylon.gradientMaterial.ts

@@ -45,6 +45,10 @@ module BABYLON {
         public SHADOWPCF1 = false;
         public SHADOWPCF2 = false;
         public SHADOWPCF3 = false;
+        public SHADOWPCSS0 = false;
+        public SHADOWPCSS1 = false;
+        public SHADOWPCSS2 = false;
+        public SHADOWPCSS3 = false;
         public NORMAL = false;
         public UV1 = false;
         public UV2 = false;

+ 4 - 0
materialsLibrary/src/lava/babylon.lavaMaterial.ts

@@ -45,6 +45,10 @@ module BABYLON {
         public SHADOWPCF1 = false;
         public SHADOWPCF2 = false;
         public SHADOWPCF3 = false;
+        public SHADOWPCSS0 = false;
+        public SHADOWPCSS1 = false;
+        public SHADOWPCSS2 = false;
+        public SHADOWPCSS3 = false;
         public NORMAL = false;
         public UV1 = false;
         public UV2 = false;

+ 4 - 0
materialsLibrary/src/normal/babylon.normalMaterial.ts

@@ -45,6 +45,10 @@ module BABYLON {
         public SHADOWPCF1 = false;
         public SHADOWPCF2 = false;
         public SHADOWPCF3 = false;
+        public SHADOWPCSS0 = false;
+        public SHADOWPCSS1 = false;
+        public SHADOWPCSS2 = false;
+        public SHADOWPCSS3 = false;
         public NORMAL = false;
         public UV1 = false;
         public UV2 = false;

+ 39 - 17
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -122,17 +122,32 @@
         public static readonly FILTER_PCSS = 7;
 
         /**
+         * Reserved for PCF and PCSS
+         * Highest Quality.
+         * 
          * Execute PCF on a 5*5 kernel improving a lot the shadow aliasing artifacts.
+         * 
+         * Execute PCSS with 32 taps blocker search and 64 taps PCF.
          */
-        public static readonly PCF_HIGH_QUALITY = 0;
+        public static readonly QUALITY_HIGH = 0;
         /**
-         * Execute PCF on a 3*3 kernel being a good tradeoff for quality/perf cross devices.
+         * Reserved for PCF and PCSS
+         * Good tradeoff for quality/perf cross devices
+         * 
+         * Execute PCF on a 3*3 kernel.
+         * 
+         * Execute PCSS with 16 taps blocker search and 32 taps PCF.
          */
-        public static readonly PCF_MEDIUM_QUALITY = 1;
+        public static readonly QUALITY_MEDIUM = 1;
         /**
-         * Execute PCF on a 1*1 kernel being a the lowest quality but the fastest.
+         * Reserved for PCF and PCSS
+         * The lowest quality but the fastest.
+         * 
+         * Execute PCF on a 1*1 kernel.
+         * 
+         * Execute PCSS with 16 taps blocker search and 16 taps PCF.
          */
-        public static readonly PCF_LOW_QUALITY = 2;
+        public static readonly QUALITY_LOW = 2;
 
         private _bias = 0.00005;
         /**
@@ -430,20 +445,20 @@
             this.filter = (value ? ShadowGenerator.FILTER_PCF : ShadowGenerator.FILTER_NONE);
         }
 
-        private _percentageCloserFilteringQuality = ShadowGenerator.PCF_HIGH_QUALITY;
+        private _filteringQuality = ShadowGenerator.QUALITY_HIGH;
         /**
-         * Gets the PCF Quality.
-         * Only valid if usePercentageCloserFiltering is true.
+         * Gets the PCF or PCSS Quality.
+         * Only valid if usePercentageCloserFiltering or usePercentageCloserFiltering is true.
          */
-        public get percentageCloserFilteringQuality(): number {
-            return this._percentageCloserFilteringQuality;
+        public get filteringQuality(): number {
+            return this._filteringQuality;
         }
         /**
-         * Sets the PCF Quality.
-         * Only valid if usePercentageCloserFiltering is true.
+         * Sets the PCF or PCSS Quality.
+         * Only valid if usePercentageCloserFiltering or usePercentageCloserFiltering is true.
          */
-        public set percentageCloserFilteringQuality(percentageCloserFilteringQuality: number) {
-            this._percentageCloserFilteringQuality = percentageCloserFilteringQuality;
+        public set filteringQuality(filteringQuality: number) {
+            this._filteringQuality = filteringQuality;
         }
 
         /**
@@ -1075,16 +1090,23 @@
 
             if (this.useContactHardeningShadow) {
                 defines["SHADOWPCSS" + lightIndex] = true;
+                if (this._filteringQuality === ShadowGenerator.QUALITY_LOW) {
+                    defines["SHADOWLOWQUALITY" + lightIndex] = true;
+                }
+                else if (this._filteringQuality === ShadowGenerator.QUALITY_MEDIUM) {
+                    defines["SHADOWMEDIUMQUALITY" + lightIndex] = true;
+                }
+                // else default to high.
             }
             if (this.usePercentageCloserFiltering) {
                 defines["SHADOWPCF" + lightIndex] = true;
-                if (this._percentageCloserFilteringQuality === ShadowGenerator.PCF_LOW_QUALITY) {
+                if (this._filteringQuality === ShadowGenerator.QUALITY_LOW) {
                     defines["SHADOWLOWQUALITY" + lightIndex] = true;
                 }
-                else if (this._percentageCloserFilteringQuality === ShadowGenerator.PCF_MEDIUM_QUALITY) {
+                else if (this._filteringQuality === ShadowGenerator.QUALITY_MEDIUM) {
                     defines["SHADOWMEDIUMQUALITY" + lightIndex] = true;
                 }
-                // else default to low.
+                // else default to high.
             }
             else if (this.usePoissonSampling) {
                 defines["SHADOWPOISSON" + lightIndex] = true;

+ 4 - 0
src/Materials/babylon.materialHelper.ts

@@ -393,6 +393,10 @@ module BABYLON {
                         fallbacks.addFallback(rank, "SHADOWPCF" + lightIndex);
                     }
 
+                    if (defines["SHADOWPCSS" + lightIndex]) {
+                        fallbacks.addFallback(rank, "SHADOWPCSS" + lightIndex);
+                    }
+
                     if (defines["SHADOWPOISSON" + lightIndex]) {
                         fallbacks.addFallback(rank, "SHADOWPOISSON" + lightIndex);
                     }

+ 10 - 4
src/Shaders/ShadersInclude/lightFragment.fx

@@ -48,14 +48,20 @@
 			#endif
 		#elif defined(SHADOWPCF{X})
 			#if defined(SHADOWLOWQUALITY{X})
-				shadow = computeShadowWithPCF1(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+				shadow = computeShadowWithPCF1(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
 			#elif defined(SHADOWMEDIUMQUALITY{X})
-				shadow = computeShadowWithPCF3(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+				shadow = computeShadowWithPCF3(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
 			#else
-				shadow = computeShadowWithPCF5(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+				shadow = computeShadowWithPCF5(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
 			#endif
 		#elif defined(SHADOWPCSS{X})
-			shadow = computeShadowWithPCSS(vPositionFromLight{X}, vDepthMetric{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+			#if defined(SHADOWLOWQUALITY{X})
+				shadow = computeShadowWithPCSS16(vPositionFromLight{X}, vDepthMetric{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 = computeShadowWithPCSS32(vPositionFromLight{X}, vDepthMetric{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+			#else
+				shadow = computeShadowWithPCSS64(vPositionFromLight{X}, vDepthMetric{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.z, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+			#endif
 		#else
 			#if defined(SHADOWCUBE{X})
 				shadow = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);

+ 181 - 47
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -215,44 +215,13 @@
 	}
 
 	#ifdef WEBGL2
-		const vec3 PCFSamplers[32] = vec3[32](
-			vec3(0.06407013, 0.05409927, 0.),
-			vec3(0.7366577, 0.5789394, 0.),
-			vec3(-0.6270542, -0.5320278, 0.),
-			vec3(-0.4096107, 0.8411095, 0.),
-			vec3(0.6849564, -0.4990818, 0.),
-			vec3(-0.874181, -0.04579735, 0.),
-			vec3(0.9989998, 0.0009880066, 0.),
-			vec3(-0.004920578, -0.9151649, 0.),
-			vec3(0.1805763, 0.9747483, 0.),
-			vec3(-0.2138451, 0.2635818, 0.),
-			vec3(0.109845, 0.3884785, 0.),
-			vec3(0.06876755, -0.3581074, 0.),
-			vec3(0.374073, -0.7661266, 0.),
-			vec3(0.3079132, -0.1216763, 0.),
-			vec3(-0.3794335, -0.8271583, 0.),
-			vec3(-0.203878, -0.07715034, 0.),
-			vec3(0.5912697, 0.1469799, 0.),
-			vec3(-0.88069, 0.3031784, 0.),
-			vec3(0.5040108, 0.8283722, 0.),
-			vec3(-0.5844124, 0.5494877, 0.),
-			vec3(0.6017799, -0.1726654, 0.),
-			vec3(-0.5554981, 0.1559997, 0.),
-			vec3(-0.3016369, -0.3900928, 0.),
-			vec3(-0.5550632, -0.1723762, 0.),
-			vec3(0.925029, 0.2995041, 0.),
-			vec3(-0.2473137, 0.5538505, 0.),
-			vec3(0.9183037, -0.2862392, 0.),
-			vec3(0.2469421, 0.6718712, 0.),
-			vec3(0.3916397, -0.4328209, 0.),
-			vec3(-0.03576927, -0.6220032, 0.),
-			vec3(-0.04661255, 0.7995201, 0.),
-			vec3(0.4402924, 0.3640312, 0.)
-		);
-
 		// Shadow PCF kernel size 1 with a single tap (lowest quality)
-		float computeShadowWithPCF1(vec4 vPositionFromLight, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
+		float computeShadowWithPCF1(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, float darkness, float frustumEdgeFalloff)
 		{
+			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));
 
@@ -264,8 +233,12 @@
 		// Shadow PCF kernel 3*3 in only 4 taps (medium quality)
 		// This uses a well distributed taps to allow a gaussian distribution covering a 3*3 kernel
 		// https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
-		float computeShadowWithPCF3(vec4 vPositionFromLight, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
+		float computeShadowWithPCF3(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
 		{
+			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));
 
@@ -298,8 +271,12 @@
 		// Shadow PCF kernel 5*5 in only 9 taps (high quality)
 		// This uses a well distributed taps to allow a gaussian distribution covering a 5*5 kernel
 		// https://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
-		float computeShadowWithPCF5(vec4 vPositionFromLight, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
+		float computeShadowWithPCF5(vec4 vPositionFromLight, float depthMetric, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
 		{
+			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));
 
@@ -334,12 +311,147 @@
 			return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
 		}
 
+		const vec3 PoissonSamplers32[64] = vec3[64](
+			vec3(0.06407013, 0.05409927, 0.),
+			vec3(0.7366577, 0.5789394, 0.),
+			vec3(-0.6270542, -0.5320278, 0.),
+			vec3(-0.4096107, 0.8411095, 0.),
+			vec3(0.6849564, -0.4990818, 0.),
+			vec3(-0.874181, -0.04579735, 0.),
+			vec3(0.9989998, 0.0009880066, 0.),
+			vec3(-0.004920578, -0.9151649, 0.),
+			vec3(0.1805763, 0.9747483, 0.),
+			vec3(-0.2138451, 0.2635818, 0.),
+			vec3(0.109845, 0.3884785, 0.),
+			vec3(0.06876755, -0.3581074, 0.),
+			vec3(0.374073, -0.7661266, 0.),
+			vec3(0.3079132, -0.1216763, 0.),
+			vec3(-0.3794335, -0.8271583, 0.),
+			vec3(-0.203878, -0.07715034, 0.),
+			vec3(0.5912697, 0.1469799, 0.),
+			vec3(-0.88069, 0.3031784, 0.),
+			vec3(0.5040108, 0.8283722, 0.),
+			vec3(-0.5844124, 0.5494877, 0.),
+			vec3(0.6017799, -0.1726654, 0.),
+			vec3(-0.5554981, 0.1559997, 0.),
+			vec3(-0.3016369, -0.3900928, 0.),
+			vec3(-0.5550632, -0.1723762, 0.),
+			vec3(0.925029, 0.2995041, 0.),
+			vec3(-0.2473137, 0.5538505, 0.),
+			vec3(0.9183037, -0.2862392, 0.),
+			vec3(0.2469421, 0.6718712, 0.),
+			vec3(0.3916397, -0.4328209, 0.),
+			vec3(-0.03576927, -0.6220032, 0.),
+			vec3(-0.04661255, 0.7995201, 0.),
+			vec3(0.4402924, 0.3640312, 0.),
+
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.),
+			vec3(0., 0., 0.)
+		);
+
+		const vec3 PoissonSamplers64[64] = vec3[64](
+			vec3(-0.613392, 0.617481, 0.),
+			vec3(0.170019, -0.040254, 0.),
+			vec3(-0.299417, 0.791925, 0.),
+			vec3(0.645680, 0.493210, 0.),
+			vec3(-0.651784, 0.717887, 0.),
+			vec3(0.421003, 0.027070, 0.),
+			vec3(-0.817194, -0.271096, 0.),
+			vec3(-0.705374, -0.668203, 0.),
+			vec3(0.977050, -0.108615, 0.),
+			vec3(0.063326, 0.142369, 0.),
+			vec3(0.203528, 0.214331, 0.),
+			vec3(-0.667531, 0.326090, 0.),
+			vec3(-0.098422, -0.295755, 0.),
+			vec3(-0.885922, 0.215369, 0.),
+			vec3(0.566637, 0.605213, 0.),
+			vec3(0.039766, -0.396100, 0.),
+			vec3(0.751946, 0.453352, 0.),
+			vec3(0.078707, -0.715323, 0.),
+			vec3(-0.075838, -0.529344, 0.),
+			vec3(0.724479, -0.580798, 0.),
+			vec3(0.222999, -0.215125, 0.),
+			vec3(-0.467574, -0.405438, 0.),
+			vec3(-0.248268, -0.814753, 0.),
+			vec3(0.354411, -0.887570, 0.),
+			vec3(0.175817, 0.382366, 0.),
+			vec3(0.487472, -0.063082, 0.),
+			vec3(-0.084078, 0.898312, 0.),
+			vec3(0.488876, -0.783441, 0.),
+			vec3(0.470016, 0.217933, 0.),
+			vec3(-0.696890, -0.549791, 0.),
+			vec3(-0.149693, 0.605762, 0.),
+			vec3(0.034211, 0.979980, 0.),
+			vec3(0.503098, -0.308878, 0.),
+			vec3(-0.016205, -0.872921, 0.),
+			vec3(0.385784, -0.393902, 0.),
+			vec3(-0.146886, -0.859249, 0.),
+			vec3(0.643361, 0.164098, 0.),
+			vec3(0.634388, -0.049471, 0.),
+			vec3(-0.688894, 0.007843, 0.),
+			vec3(0.464034, -0.188818, 0.),
+			vec3(-0.440840, 0.137486, 0.),
+			vec3(0.364483, 0.511704, 0.),
+			vec3(0.034028, 0.325968, 0.),
+			vec3(0.099094, -0.308023, 0.),
+			vec3(0.693960, -0.366253, 0.),
+			vec3(0.678884, -0.204688, 0.),
+			vec3(0.001801, 0.780328, 0.),
+			vec3(0.145177, -0.898984, 0.),
+			vec3(0.062655, -0.611866, 0.),
+			vec3(0.315226, -0.604297, 0.),
+			vec3(-0.780145, 0.486251, 0.),
+			vec3(-0.371868, 0.882138, 0.),
+			vec3(0.200476, 0.494430, 0.),
+			vec3(-0.494552, -0.711051, 0.),
+			vec3(0.612476, 0.705252, 0.),
+			vec3(-0.578845, -0.768792, 0.),
+			vec3(-0.772454, -0.090976, 0.),
+			vec3(0.504440, 0.372295, 0.),
+			vec3(0.155736, 0.065157, 0.),
+			vec3(0.391522, 0.849605, 0.),
+			vec3(-0.620106, -0.328104, 0.),
+			vec3(0.789239, -0.419965, 0.),
+			vec3(-0.545396, 0.538133, 0.),
+			vec3(-0.178564, -0.596057, 0.)
+		);
+
 		// 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)
+		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) {
 				return 1.0;
@@ -351,8 +463,8 @@
 			float blockerDepth = 0.0;
 			float sumBlockerDepth = 0.0;
 			float numBlocker = 0.0;
-			for (int i = 0; i < 16; i++) {
-                blockerDepth = texture(depthSampler, uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PCFSamplers[i].xy)).r;
+			for (int i = 0; i < searchTapCount; i ++) {
+                blockerDepth = texture(depthSampler, uvDepth.xy + (lightSizeUV * shadowMapSizeInverse * PoissonSamplers32[i].xy)).r;
                 if (blockerDepth < depthMetric) {
                     sumBlockerDepth += blockerDepth;
                     numBlocker++;
@@ -364,27 +476,49 @@
 			}
 			float avgBlockerDepth = sumBlockerDepth / numBlocker;
 
-			// float penumbraRatio = (depthMetric - avgBlockerDepth) / avgBlockerDepth;
-			// Do not dividing by z despite being physically incorrect looks better due to the limited kernel size.
+			// 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(gl_FragCoord.xy);
+			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 < 32; i++) {
-				vec3 offset = PCFSamplers[i];
+			for (int i = 0; i < pcfTapCount; i++) {
+				vec3 offset = poissonSamplers[i];
 				// Rotated offset.
 				offset = vec3(offset.x * rotationVector.x - offset.y * rotationVector.y, offset.y * rotationVector.x + offset.x * rotationVector.y, 0.);
 				shadow += texture2D(shadowSampler, uvDepth + offset * filterRadius);
 			}
-			shadow /= 32.;
+			shadow /= float(pcfTapCount);
 
+			// Blocker distance falloff
+			shadow = mix(shadow, 1., depthMetric - avgBlockerDepth);
+
+			// Apply darkness
 			shadow = shadow * (1. - darkness) + darkness;
+
+			// Apply light frustrum fallof
 			return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
 		}
+
+		float computeShadowWithPCSS16(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+		{
+			return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 16, PoissonSamplers32);
+		}
+
+		float computeShadowWithPCSS32(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+		{
+			return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 16, 32, PoissonSamplers32);
+		}
+
+		float computeShadowWithPCSS64(vec4 vPositionFromLight, float depthMetric, sampler2D depthSampler, sampler2DShadow shadowSampler, float shadowMapSizeInverse, float lightSizeUV, float darkness, float frustumEdgeFalloff)
+		{
+			return computeShadowWithPCSS(vPositionFromLight, depthMetric, depthSampler, shadowSampler, shadowMapSizeInverse, lightSizeUV, darkness, frustumEdgeFalloff, 32, 64, PoissonSamplers64);
+		}
 	#endif
 #endif