Sebastien Vandenberghe 7 سال پیش
والد
کامیت
9da0f39017

+ 33 - 7
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -119,6 +119,8 @@
          */
         public static readonly FILTER_PCF = 6;
 
+        public static readonly FILTER_PCSS = 7;
+
         /**
          * Execute PCF on a 5*5 kernel improving a lot the shadow aliasing artifacts.
          */
@@ -269,14 +271,14 @@
                     return;
                 }
                 // PCF on cubemap would also be expensive
-                else if (value === ShadowGenerator.FILTER_PCF) {
+                else if (value === ShadowGenerator.FILTER_PCF || value === ShadowGenerator.FILTER_PCSS) {
                     this.usePoissonSampling = true;
                     return;
                 }
             }
 
             // Weblg1 fallback for PCF.
-            if (value === ShadowGenerator.FILTER_PCF) {
+            if (value === ShadowGenerator.FILTER_PCF || value === ShadowGenerator.FILTER_PCSS) {
                 if (this._scene.getEngine().webGLVersion === 1) {
                     this.usePoissonSampling = true;
                     return;
@@ -432,6 +434,22 @@
             this.filter = (value ? ShadowGenerator.FILTER_PCF : ShadowGenerator.FILTER_NONE);
         }
 
+        /**
+         * Gets if the current filter is set to "PCSS" (contact hardening).
+         */
+        public get useContactHardeningShadow(): boolean {
+            return this.filter === ShadowGenerator.FILTER_PCSS;
+        }
+        /**
+         * Sets the current filter to "PCF" (contact hardening).
+         */
+        public set useContactHardeningShadow(value: boolean) {
+            if (!value && this.filter !== ShadowGenerator.FILTER_PCSS) {
+                return;
+            }
+            this.filter = (value ? ShadowGenerator.FILTER_PCSS : ShadowGenerator.FILTER_NONE);
+        }
+
         private _percentageCloserFilteringQuality = ShadowGenerator.PCF_HIGH_QUALITY;
         /**
          * Gets the PCF Quality.
@@ -669,7 +687,7 @@
             this._shadowMap.onBeforeRenderObservable.add((faceIndex: number) => {
                 this._currentFaceIndex = faceIndex;
                 if (this._useDepthStencilTexture) {
-                    engine.setColorWrite(false);
+                    //engine.setColorWrite(false);
                 }
             });
 
@@ -697,7 +715,7 @@
             // Clear according to the chosen filter.
             this._shadowMap.onClearObservable.add((engine: Engine) => {
                 if (this._useDepthStencilTexture) {
-                    engine.clear(clearOne, false, true, false);
+                    engine.clear(clearOne, true, true, true);
                 }
                 else if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
                     engine.clear(clearZero, true, true, false);
@@ -850,7 +868,7 @@
                 return;
             }
 
-            if (this.filter === ShadowGenerator.FILTER_NONE) {
+            if (this.filter === ShadowGenerator.FILTER_NONE || this.filter === ShadowGenerator.FILTER_PCSS) {
                 this._shadowMap.updateSamplingMode(Texture.NEAREST_SAMPLINGMODE);
             } else {
                 this._shadowMap.updateSamplingMode(Texture.BILINEAR_SAMPLINGMODE);
@@ -946,8 +964,8 @@
             if (this.useExponentialShadowMap || this.useBlurExponentialShadowMap) {
                 defines.push("#define ESM");
             }
-            else if (this.usePercentageCloserFiltering) {
-                defines.push("#define PCF");
+            else if (this.usePercentageCloserFiltering || this.useContactHardeningShadow) {
+                defines.push("#define DEPTHTEXTURE");
             }
 
             var attribs = [VertexBuffer.PositionKind];
@@ -1044,6 +1062,9 @@
 
             defines["SHADOW" + lightIndex] = true;
 
+            if (this.useContactHardeningShadow) {
+                defines["SHADOWPCSS" + lightIndex] = true;
+            }
             if (this.usePercentageCloserFiltering) {
                 defines["SHADOWPCF" + lightIndex] = true;
                 if (this._percentageCloserFilteringQuality === ShadowGenerator.PCF_LOW_QUALITY) {
@@ -1108,6 +1129,11 @@
                 light._uniformBuffer.updateFloat4("shadowsInfo", this.getDarkness(), this.blurScale / shadowMap.getSize().width, this.depthScale, this.frustumEdgeFalloff, lightIndex);
             }
 
+            if (this._filter === ShadowGenerator.FILTER_PCSS) {
+                effect.setDepthStencilTexture("shadowSampler" + lightIndex, this.getShadowMapForRendering());
+                effect.setTexture("depthSampler" + lightIndex, this.getShadowMapForRendering());
+            }
+
             light._uniformBuffer.updateFloat2("depthValues", this.getLight().getDepthMinZ(camera), this.getLight().getDepthMinZ(camera) + this.getLight().getDepthMaxZ(camera), lightIndex);
         }
 

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

@@ -239,6 +239,7 @@ module BABYLON {
                     // Shadows
                     defines["SHADOW" + lightIndex] = false;
                     defines["SHADOWPCF" + lightIndex] = false;
+                    defines["SHADOWPCSS" + lightIndex] = false;
                     defines["SHADOWPOISSON" + lightIndex] = false;
                     defines["SHADOWESM" + lightIndex] = false;
                     defines["SHADOWCUBE" + lightIndex] = false;
@@ -348,6 +349,8 @@ module BABYLON {
                 }
 
                 samplersList.push("shadowSampler" + lightIndex);
+                samplersList.push("depthSampler" + lightIndex);
+
                 if (defines["PROJECTEDLIGHTTEXTURE" + lightIndex]){
                     samplersList.push("projectionLightSampler" + lightIndex,);
                     uniformsList.push(

+ 26 - 30
src/Shaders/ShadersInclude/lightFragment.fx

@@ -34,37 +34,33 @@
 			#else
 				shadow = computeShadowWithCloseESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
 			#endif
+		#elif defined(SHADOWESM{X})
+			#if defined(SHADOWCUBE{X})
+				shadow = computeShadowWithESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues);
+			#else
+				shadow = computeShadowWithESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
+			#endif
+		#elif defined(SHADOWPOISSON{X})
+			#if defined(SHADOWCUBE{X})
+				shadow = computeShadowWithPoissonSamplingCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.depthValues);
+			#else
+				shadow = computeShadowWithPoissonSampling(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+			#endif
+		#elif defined(SHADOWPCF{X})
+			#if defined(SHADOWLOWQUALITY{X})
+				shadow = computeShadowWithPCF1(vPositionFromLight{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);
+			#else
+				shadow = computeShadowWithPCF5(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
+			#endif
+		#elif defined(SHADOWPCSS{X})
+			shadow = computeShadowWithPCSS(vPositionFromLight{X}, depthSampler{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
 		#else
-			#ifdef SHADOWESM{X}
-				#if defined(SHADOWCUBE{X})
-					shadow = computeShadowWithESMCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.depthValues);
-				#else
-					shadow = computeShadowWithESM(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.z, light{X}.shadowsInfo.w);
-				#endif
-			#else	
-				#ifdef SHADOWPOISSON{X}
-					#if defined(SHADOWCUBE{X})
-						shadow = computeShadowWithPoissonSamplingCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.depthValues);
-					#else
-						shadow = computeShadowWithPoissonSampling(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.y, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
-					#endif
-				#else
-					#if defined(SHADOWPCF{X})
-						#if defined(SHADOWLOWQUALITY{X})
-							shadow = computeShadowWithPCF1(vPositionFromLight{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);
-						#else
-							shadow = computeShadowWithPCF5(vPositionFromLight{X}, shadowSampler{X}, light{X}.shadowsInfo.yz, 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);
-						#else
-							shadow = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
-						#endif
-					#endif
-				#endif
+			#if defined(SHADOWCUBE{X})
+				shadow = computeShadowCube(light{X}.vLightData.xyz, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.depthValues);
+			#else
+				shadow = computeShadow(vPositionFromLight{X}, vDepthMetric{X}, shadowSampler{X}, light{X}.shadowsInfo.x, light{X}.shadowsInfo.w);
 			#endif
 		#endif
 

+ 5 - 6
src/Shaders/ShadersInclude/lightFragmentDeclaration.fx

@@ -8,16 +8,15 @@
 	#endif
 	#ifdef SHADOW{X}
 		#if defined(SHADOWCUBE{X})
-			#if defined(SHADOWPCF{X})
-				uniform highp samplerCubeShadow shadowSampler{X};
-			#else
-				uniform samplerCube shadowSampler{X};
-			#endif
+			uniform samplerCube shadowSampler{X};
 		#else
 			varying vec4 vPositionFromLight{X};
 			varying float vDepthMetric{X};
 
-			#if defined(SHADOWPCF{X})
+			#if defined(SHADOWPCSS{X})
+				uniform highp sampler2DShadow shadowSampler{X};
+				uniform highp sampler2D depthSampler{X};
+			#elif defined(SHADOWPCF{X})
 				uniform highp sampler2DShadow shadowSampler{X};
 			#else
 				uniform sampler2D shadowSampler{X};

+ 5 - 6
src/Shaders/ShadersInclude/lightUboDeclaration.fx

@@ -19,16 +19,15 @@
 #endif
 #ifdef SHADOW{X}
 	#if defined(SHADOWCUBE{X})
-		#if defined(SHADOWPCF{X})
-			uniform highp samplerCubeShadow shadowSampler{X};
-		#else
-			uniform samplerCube shadowSampler{X};
-		#endif
+		uniform samplerCube shadowSampler{X};		
 	#else
 		varying vec4 vPositionFromLight{X};
 		varying float vDepthMetric{X};
 
-		#if defined(SHADOWPCF{X})
+		#if defined(SHADOWPCSS{X})
+				uniform highp sampler2DShadow shadowSampler{X};
+				uniform highp sampler2D depthSampler{X};
+		#elif defined(SHADOWPCF{X})
 			uniform highp sampler2DShadow shadowSampler{X};
 		#else
 			uniform sampler2D shadowSampler{X};

+ 80 - 18
src/Shaders/ShadersInclude/shadowsFragmentFunctions.fx

@@ -215,23 +215,39 @@
 	}
 
 	#ifdef WEBGL2
-		const vec3 PCFSamplers[16] = vec3[16](
-			vec3( -0.94201624, -0.39906216, 0.),
-			vec3( 0.94558609, -0.76890725, 0.),
-			vec3( -0.094184101, -0.92938870, 0.),
-			vec3( 0.34495938, 0.29387760, 0.),
-			vec3( -0.91588581, 0.45771432, 0.),
-			vec3( -0.81544232, -0.87912464, 0.),
-			vec3( -0.38277543, 0.27676845, 0.),
-			vec3( 0.97484398, 0.75648379, 0.),
-			vec3( 0.44323325, -0.97511554, 0.),
-			vec3( 0.53742981, -0.47373420, 0.),
-			vec3( -0.26496911, -0.41893023, 0.),
-			vec3( 0.79197514, 0.19090188, 0.),
-			vec3( -0.24188840, 0.99706507, 0.),
-			vec3( -0.81409955, 0.91437590, 0.),
-			vec3( 0.19984126, 0.78641367, 0.),
-			vec3( 0.14383161, -0.14100790, 0.)
+		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)
@@ -316,7 +332,53 @@
 
 			shadow = shadow * (1. - darkness) + darkness;
 			return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
-			
+		}
+
+		float computeShadowWithPCSS(vec4 vPositionFromLight, sampler2D depthSampler, sampler2DShadow shadowSampler, vec2 shadowMapSizeAndInverse, float darkness, float frustumEdgeFalloff)
+		{
+			vec3 clipSpace = vPositionFromLight.xyz / vPositionFromLight.w;
+			vec3 uvDepth = vec3(0.5 * clipSpace.xyz + vec3(0.5));
+
+			float softness = 50.;
+
+			float searchSize = softness * clamp(uvDepth.z - .02, 0., 1.) / uvDepth.z;
+
+			float blockerDepth = 0.0;
+			float sumBlockerDepth = 0.0;
+			float numBlocker = 0.0;
+			for (int i = 0; i < 16; i++) {
+                blockerDepth = texture(depthSampler, uvDepth.xy + (searchSize * shadowMapSizeAndInverse.y * PCFSamplers[i].xy)).r;
+                if (blockerDepth < uvDepth.z) {
+                    sumBlockerDepth += blockerDepth;
+                    numBlocker++;
+                }
+            }
+
+			if (numBlocker < 1.0) {
+				return 1.0;
+			}
+
+			float avgBlockerDepth = sumBlockerDepth / numBlocker;
+			float penumbra = uvDepth.z - avgBlockerDepth;
+			float filterRadiusUV = penumbra * softness;
+
+			float shadow = 0.;
+
+			float random = getRand(gl_FragCoord.xy / 1024.);
+			float rotationAngle = random * 3.1415926;
+			vec2 rotationTrig = vec2(cos(rotationAngle), sin(rotationAngle));
+
+			for (int i = 0; i < 32; i++) {
+				vec3 offset = PCFSamplers[i];
+
+				offset = vec3(offset.x * rotationTrig.x - offset.y * rotationTrig.y, offset.y * rotationTrig.x + offset.x * rotationTrig.y, 0.);
+
+				shadow += texture2D(shadowSampler, uvDepth + offset * filterRadiusUV * shadowMapSizeAndInverse.y);
+			}
+			shadow /= 32.;
+
+			shadow = shadow * (1. - darkness) + darkness;
+			return computeFallOff(shadow, clipSpace.xy, frustumEdgeFalloff);
 		}
 	#endif
 #endif

+ 2 - 1
src/Shaders/shadowMap.vertex.fx

@@ -31,8 +31,9 @@ void main(void)
 vec4 worldPos = finalWorld * vec4(position, 1.0);
 gl_Position = viewProjection * worldPos;
 
-#ifdef PCF
+#ifdef DEPTHTEXTURE
 	gl_Position.z += biasAndScale.x;
+	vDepthMetric = ((gl_Position.z + depthValues.x) / (depthValues.y)) + biasAndScale.x;
 #else
 	vDepthMetric = ((gl_Position.z + depthValues.x) / (depthValues.y)) + biasAndScale.x;
 #endif