Browse Source

CSM: Directional light without a shadow breaks shaders (#23631)

* Demonstrate issue - directional light without a shadow breaks shaders

* Fix: light not casting shadows need to be processed separately in the CSM shader
Ondřej Španěl 3 years ago
parent
commit
4082a1477f
2 changed files with 55 additions and 35 deletions
  1. 51 35
      examples/jsm/csm/CSMShader.js
  2. 4 0
      examples/webgl_shadowmap_csm.html

+ 51 - 35
examples/jsm/csm/CSMShader.js

@@ -90,19 +90,19 @@ IncidentLight directLight;
 		directionalLight = directionalLights[ i ];
 		getDirectionalLightInfo( directionalLight, geometry, directLight );
 
-		// NOTE: Depth gets larger away from the camera.
-		// cascade.x is closer, cascade.y is further
-		cascade = CSM_cascades[ i ];
-		cascadeCenter = ( cascade.x + cascade.y ) / 2.0;
-		closestEdge = linearDepth < cascadeCenter ? cascade.x : cascade.y;
-		margin = 0.25 * pow( closestEdge, 2.0 );
-		csmx = cascade.x - margin / 2.0;
-		csmy = cascade.y + margin / 2.0;
-		if( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS && linearDepth >= csmx && ( linearDepth < csmy || UNROLLED_LOOP_INDEX == CSM_CASCADES - 1 ) ) {
-
-			float dist = min( linearDepth - csmx, csmy - linearDepth );
-			float ratio = clamp( dist / margin, 0.0, 1.0 );
-			if( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) {
+	  	#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )
+			// NOTE: Depth gets larger away from the camera.
+			// cascade.x is closer, cascade.y is further
+			cascade = CSM_cascades[ i ];
+			cascadeCenter = ( cascade.x + cascade.y ) / 2.0;
+			closestEdge = linearDepth < cascadeCenter ? cascade.x : cascade.y;
+			margin = 0.25 * pow( closestEdge, 2.0 );
+			csmx = cascade.x - margin / 2.0;
+			csmy = cascade.y + margin / 2.0;
+			if( linearDepth >= csmx && ( linearDepth < csmy || UNROLLED_LOOP_INDEX == CSM_CASCADES - 1 ) ) {
+
+				float dist = min( linearDepth - csmx, csmy - linearDepth );
+				float ratio = clamp( dist / margin, 0.0, 1.0 );
 
 				vec3 prevColor = directLight.color;
 				directionalLightShadow = directionalLightShadows[ i ];
@@ -111,42 +111,58 @@ IncidentLight directLight;
 				bool shouldFadeLastCascade = UNROLLED_LOOP_INDEX == CSM_CASCADES - 1 && linearDepth > cascadeCenter;
 				directLight.color = mix( prevColor, directLight.color, shouldFadeLastCascade ? ratio : 1.0 );
 
-			}
-
-			ReflectedLight prevLight = reflectedLight;
-			RE_Direct( directLight, geometry, material, reflectedLight );
+				ReflectedLight prevLight = reflectedLight;
+				RE_Direct( directLight, geometry, material, reflectedLight );
 
-			bool shouldBlend = UNROLLED_LOOP_INDEX != CSM_CASCADES - 1 || UNROLLED_LOOP_INDEX == CSM_CASCADES - 1 && linearDepth < cascadeCenter;
-			float blendRatio = shouldBlend ? ratio : 1.0;
+				bool shouldBlend = UNROLLED_LOOP_INDEX != CSM_CASCADES - 1 || UNROLLED_LOOP_INDEX == CSM_CASCADES - 1 && linearDepth < cascadeCenter;
+				float blendRatio = shouldBlend ? ratio : 1.0;
 
-			reflectedLight.directDiffuse = mix( prevLight.directDiffuse, reflectedLight.directDiffuse, blendRatio );
-			reflectedLight.directSpecular = mix( prevLight.directSpecular, reflectedLight.directSpecular, blendRatio );
-			reflectedLight.indirectDiffuse = mix( prevLight.indirectDiffuse, reflectedLight.indirectDiffuse, blendRatio );
-			reflectedLight.indirectSpecular = mix( prevLight.indirectSpecular, reflectedLight.indirectSpecular, blendRatio );
+				reflectedLight.directDiffuse = mix( prevLight.directDiffuse, reflectedLight.directDiffuse, blendRatio );
+				reflectedLight.directSpecular = mix( prevLight.directSpecular, reflectedLight.directSpecular, blendRatio );
+				reflectedLight.indirectDiffuse = mix( prevLight.indirectDiffuse, reflectedLight.indirectDiffuse, blendRatio );
+				reflectedLight.indirectSpecular = mix( prevLight.indirectSpecular, reflectedLight.indirectSpecular, blendRatio );
 
-		}
+			}
+	  	#endif
 
 	}
 	#pragma unroll_loop_end
 	#else
 
-	#pragma unroll_loop_start
-	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
+		#pragma unroll_loop_start
+		for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
 
-		directionalLight = directionalLights[ i ];
-		getDirectionalLightInfo( directionalLight, geometry, directLight );
+			directionalLight = directionalLights[ i ];
+			getDirectionalLightInfo( directionalLight, geometry, directLight );
 
-		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )
+			#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )
 
-		directionalLightShadow = directionalLightShadows[ i ];
-		if(linearDepth >= CSM_cascades[UNROLLED_LOOP_INDEX].x && linearDepth < CSM_cascades[UNROLLED_LOOP_INDEX].y) directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
+			directionalLightShadow = directionalLightShadows[ i ];
+			if(linearDepth >= CSM_cascades[UNROLLED_LOOP_INDEX].x && linearDepth < CSM_cascades[UNROLLED_LOOP_INDEX].y) directLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
 
-		#endif
+			if(linearDepth >= CSM_cascades[UNROLLED_LOOP_INDEX].x && (linearDepth < CSM_cascades[UNROLLED_LOOP_INDEX].y || UNROLLED_LOOP_INDEX == CSM_CASCADES - 1)) RE_Direct( directLight, geometry, material, reflectedLight );
 
-		if(linearDepth >= CSM_cascades[UNROLLED_LOOP_INDEX].x && (linearDepth < CSM_cascades[UNROLLED_LOOP_INDEX].y || UNROLLED_LOOP_INDEX == CSM_CASCADES - 1)) RE_Direct( directLight, geometry, material, reflectedLight );
+			#endif
 
-	}
-	#pragma unroll_loop_end
+		}
+		#pragma unroll_loop_end
+
+	#endif
+
+	#if ( NUM_DIR_LIGHTS > NUM_DIR_LIGHT_SHADOWS)
+		// compute the lights not casting shadows (if any)
+
+		#pragma unroll_loop_start
+		for ( int i = NUM_DIR_LIGHT_SHADOWS; i < NUM_DIR_LIGHTS; i ++ ) {
+
+			directionalLight = directionalLights[ i ];
+
+			getDirectionalLightInfo( directionalLight, geometry, directLight );
+
+			RE_Direct( directLight, geometry, material, reflectedLight );
+
+		}
+		#pragma unroll_loop_end
 
 	#endif
 

+ 4 - 0
examples/webgl_shadowmap_csm.html

@@ -97,6 +97,10 @@
 				const ambientLight = new THREE.AmbientLight( 0xffffff, 0.5 );
 				scene.add( ambientLight );
 
+				const additionalDirectionalLight = new THREE.DirectionalLight( 0x000020, 0.5 );
+				additionalDirectionalLight.position.set( params.lightX, params.lightY, params.lightZ ).normalize().multiplyScalar( - 200 );
+				scene.add( additionalDirectionalLight );
+
 				csm = new CSM( {
 					maxFar: params.far,
 					cascades: 4,