Browse Source

Conserve shadow map slots reserved for lights

Only shadow casting lights now get entries in the shadow maps arrays in shaders. Lights are sorted so that shadow casting lights come first, so the index of the light in the shadow maps array still matches the index in the normal light data array.

This conserves texture slots, enabling to use more lights in scenes where shadow maps are enabled. Uniform update performance and shader execution performance should also be a bit better when there's a mix of shadow casting and non-shadowed lights.
Olli Etuaho 6 years ago
parent
commit
541fea9494

+ 3 - 3
src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js

@@ -33,7 +33,7 @@ IncidentLight directLight;
 
 
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 
 
-		#ifdef USE_SHADOWMAP
+		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )
 		directLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 		directLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 		#endif
 		#endif
 
 
@@ -54,7 +54,7 @@ IncidentLight directLight;
 
 
 		getSpotDirectLightIrradiance( spotLight, geometry, directLight );
 		getSpotDirectLightIrradiance( spotLight, geometry, directLight );
 
 
-		#ifdef USE_SHADOWMAP
+		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )
 		directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
 		directLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
 		#endif
 		#endif
 
 
@@ -75,7 +75,7 @@ IncidentLight directLight;
 
 
 		getDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );
 		getDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );
 
 
-		#ifdef USE_SHADOWMAP
+		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )
 		directLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
 		directLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
 		#endif
 		#endif
 
 

+ 9 - 9
src/renderers/shaders/ShaderChunk/shadowmap_pars_fragment.glsl.js

@@ -1,24 +1,24 @@
 export default /* glsl */`
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 #ifdef USE_SHADOWMAP
 
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 
-		uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];
-		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
+		uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];
+		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 
 
 	#endif
 	#endif
 
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
 
-		uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];
-		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];
+		uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];
+		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 
 
 	#endif
 	#endif
 
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 
-		uniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];
-		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];
+		uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];
+		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 
 
 	#endif
 	#endif
 
 

+ 9 - 9
src/renderers/shaders/ShaderChunk/shadowmap_pars_vertex.glsl.js

@@ -1,24 +1,24 @@
 export default /* glsl */`
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 #ifdef USE_SHADOWMAP
 
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 
-		uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];
-		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];
+		uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];
+		varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];
 
 
 	#endif
 	#endif
 
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
 
-		uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];
-		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];
+		uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];
+		varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];
 
 
 	#endif
 	#endif
 
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 
-		uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];
-		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];
+		uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];
+		varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];
 
 
 	#endif
 	#endif
 
 

+ 6 - 6
src/renderers/shaders/ShaderChunk/shadowmap_vertex.glsl.js

@@ -1,10 +1,10 @@
 export default /* glsl */`
 export default /* glsl */`
 #ifdef USE_SHADOWMAP
 #ifdef USE_SHADOWMAP
 
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {
 
 
 		vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;
 		vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;
 
 
@@ -12,10 +12,10 @@ export default /* glsl */`
 
 
 	#endif
 	#endif
 
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
 
 
 		vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;
 		vSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;
 
 
@@ -23,10 +23,10 @@ export default /* glsl */`
 
 
 	#endif
 	#endif
 
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 
 
 		vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;
 		vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;
 
 

+ 6 - 6
src/renderers/shaders/ShaderChunk/shadowmask_pars_fragment.glsl.js

@@ -5,12 +5,12 @@ float getShadowMask() {
 
 
 	#ifdef USE_SHADOWMAP
 	#ifdef USE_SHADOWMAP
 
 
-	#if NUM_DIR_LIGHTS > 0
+	#if NUM_DIR_LIGHT_SHADOWS > 0
 
 
 	DirectionalLight directionalLight;
 	DirectionalLight directionalLight;
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {
 
 
 		directionalLight = directionalLights[ i ];
 		directionalLight = directionalLights[ i ];
 		shadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
 		shadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
@@ -19,12 +19,12 @@ float getShadowMask() {
 
 
 	#endif
 	#endif
 
 
-	#if NUM_SPOT_LIGHTS > 0
+	#if NUM_SPOT_LIGHT_SHADOWS > 0
 
 
 	SpotLight spotLight;
 	SpotLight spotLight;
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {
 
 
 		spotLight = spotLights[ i ];
 		spotLight = spotLights[ i ];
 		shadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
 		shadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
@@ -33,12 +33,12 @@ float getShadowMask() {
 
 
 	#endif
 	#endif
 
 
-	#if NUM_POINT_LIGHTS > 0
+	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 
 	PointLight pointLight;
 	PointLight pointLight;
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
-	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
+	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 
 
 		pointLight = pointLights[ i ];
 		pointLight = pointLights[ i ];
 		shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 		shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;

+ 50 - 10
src/renderers/webgl/WebGLLights.js

@@ -102,6 +102,12 @@ function UniformsCache() {
 
 
 var nextVersion = 0;
 var nextVersion = 0;
 
 
+var shadowCastingLightsFirst = function( lightA, lightB ) {
+
+	return ( lightB.castShadow ? 1 : 0 ) - ( lightA.castShadow ? 1 : 0 );
+
+};
+
 function WebGLLights() {
 function WebGLLights() {
 
 
 	var cache = new UniformsCache();
 	var cache = new UniformsCache();
@@ -116,7 +122,10 @@ function WebGLLights() {
 			spotLength: - 1,
 			spotLength: - 1,
 			rectAreaLength: - 1,
 			rectAreaLength: - 1,
 			hemiLength: - 1,
 			hemiLength: - 1,
-			shadowsLength: - 1,
+
+			numDirectionalShadows: -1,
+			numPointShadows: -1,
+			numSpotShadows: -1,
 		},
 		},
 
 
 		ambient: [ 0, 0, 0 ],
 		ambient: [ 0, 0, 0 ],
@@ -131,7 +140,11 @@ function WebGLLights() {
 		point: [],
 		point: [],
 		pointShadowMap: [],
 		pointShadowMap: [],
 		pointShadowMatrix: [],
 		pointShadowMatrix: [],
-		hemi: []
+		hemi: [],
+
+		numDirectionalShadows: -1,
+		numPointShadows: -1,
+		numSpotShadows: -1
 
 
 	};
 	};
 
 
@@ -153,8 +166,14 @@ function WebGLLights() {
 		var rectAreaLength = 0;
 		var rectAreaLength = 0;
 		var hemiLength = 0;
 		var hemiLength = 0;
 
 
+		var numDirectionalShadows = 0;
+		var numPointShadows = 0;
+		var numSpotShadows = 0;
+
 		var viewMatrix = camera.matrixWorldInverse;
 		var viewMatrix = camera.matrixWorldInverse;
 
 
+		lights.sort( shadowCastingLightsFirst );
+
 		for ( var i = 0, l = lights.length; i < l; i ++ ) {
 		for ( var i = 0, l = lights.length; i < l; i ++ ) {
 
 
 			var light = lights[ i ];
 			var light = lights[ i ];
@@ -199,10 +218,13 @@ function WebGLLights() {
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowMapSize = shadow.mapSize;
 					uniforms.shadowMapSize = shadow.mapSize;
 
 
+					state.directionalShadowMap[ directionalLength ] = shadowMap;
+					state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
+
+					++ numDirectionalShadows;
+
 				}
 				}
 
 
-				state.directionalShadowMap[ directionalLength ] = shadowMap;
-				state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;
 				state.directional[ directionalLength ] = uniforms;
 				state.directional[ directionalLength ] = uniforms;
 
 
 				directionalLength ++;
 				directionalLength ++;
@@ -236,10 +258,13 @@ function WebGLLights() {
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowRadius = shadow.radius;
 					uniforms.shadowMapSize = shadow.mapSize;
 					uniforms.shadowMapSize = shadow.mapSize;
 
 
+					state.spotShadowMap[ spotLength ] = shadowMap;
+					state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
+
+					++ numSpotShadows;
+
 				}
 				}
 
 
-				state.spotShadowMap[ spotLength ] = shadowMap;
-				state.spotShadowMatrix[ spotLength ] = light.shadow.matrix;
 				state.spot[ spotLength ] = uniforms;
 				state.spot[ spotLength ] = uniforms;
 
 
 				spotLength ++;
 				spotLength ++;
@@ -299,10 +324,13 @@ function WebGLLights() {
 					uniforms.shadowCameraNear = shadow.camera.near;
 					uniforms.shadowCameraNear = shadow.camera.near;
 					uniforms.shadowCameraFar = shadow.camera.far;
 					uniforms.shadowCameraFar = shadow.camera.far;
 
 
+					state.pointShadowMap[ pointLength ] = shadowMap;
+					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
+
+					++ numPointShadows;
+
 				}
 				}
 
 
-				state.pointShadowMap[ pointLength ] = shadowMap;
-				state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
 				state.point[ pointLength ] = uniforms;
 				state.point[ pointLength ] = uniforms;
 
 
 				pointLength ++;
 				pointLength ++;
@@ -337,7 +365,9 @@ function WebGLLights() {
 			hash.spotLength !== spotLength ||
 			hash.spotLength !== spotLength ||
 			hash.rectAreaLength !== rectAreaLength ||
 			hash.rectAreaLength !== rectAreaLength ||
 			hash.hemiLength !== hemiLength ||
 			hash.hemiLength !== hemiLength ||
-			hash.shadowsLength !== shadows.length ) {
+			hash.numDirectionalShadows !== numDirectionalShadows || 
+			hash.numPointShadows !== numPointShadows || 
+			hash.numSpotShadows !== numSpotShadows ) {
 
 
 			state.directional.length = directionalLength;
 			state.directional.length = directionalLength;
 			state.spot.length = spotLength;
 			state.spot.length = spotLength;
@@ -345,12 +375,22 @@ function WebGLLights() {
 			state.point.length = pointLength;
 			state.point.length = pointLength;
 			state.hemi.length = hemiLength;
 			state.hemi.length = hemiLength;
 
 
+			state.directionalShadowMap.length = numDirectionalShadows;
+			state.pointShadowMap.length = numPointShadows;
+			state.spotShadowMap.length = numSpotShadows;
+			state.directionalShadowMatrix.length = numDirectionalShadows;
+			state.pointShadowMatrix.length = numPointShadows;
+			state.spotShadowMatrix.length = numSpotShadows;
+
 			hash.directionalLength = directionalLength;
 			hash.directionalLength = directionalLength;
 			hash.pointLength = pointLength;
 			hash.pointLength = pointLength;
 			hash.spotLength = spotLength;
 			hash.spotLength = spotLength;
 			hash.rectAreaLength = rectAreaLength;
 			hash.rectAreaLength = rectAreaLength;
 			hash.hemiLength = hemiLength;
 			hash.hemiLength = hemiLength;
-			hash.shadowsLength = shadows.length;
+
+			hash.numDirectionalShadows = numDirectionalShadows;
+			hash.numPointShadows = numPointShadows;
+			hash.numSpotShadows = numSpotShadows;
 
 
 			state.version = nextVersion ++;
 			state.version = nextVersion ++;
 
 

+ 7 - 2
src/renderers/webgl/WebGLProgram.js

@@ -180,7 +180,10 @@ function replaceLightNums( string, parameters ) {
 		.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
 		.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
 		.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
 		.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
 		.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
 		.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
-		.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights );
+		.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
+		.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
+		.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
+		.replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );
 
 
 }
 }
 
 
@@ -224,7 +227,9 @@ function unrollLoops( string ) {
 
 
 		for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
 		for ( var i = parseInt( start ); i < parseInt( end ); i ++ ) {
 
 
-			unroll += snippet.replace( /\[ i \]/g, '[ ' + i + ' ]' );
+			unroll += snippet
+				.replace( /\[ i \]/g, '[ ' + i + ' ]' )
+				.replace( /UNROLLED_LOOP_INDEX/g, i );
 
 
 		}
 		}
 
 

+ 4 - 0
src/renderers/webgl/WebGLPrograms.js

@@ -190,6 +190,10 @@ function WebGLPrograms( renderer, extensions, capabilities ) {
 			numRectAreaLights: lights.rectArea.length,
 			numRectAreaLights: lights.rectArea.length,
 			numHemiLights: lights.hemi.length,
 			numHemiLights: lights.hemi.length,
 
 
+			numDirLightShadows: lights.directionalShadowMap.length,
+			numPointLightShadows: lights.pointShadowMap.length,
+			numSpotLightShadows: lights.spotShadowMap.length,
+
 			numClippingPlanes: nClipPlanes,
 			numClippingPlanes: nClipPlanes,
 			numClipIntersection: nClipIntersection,
 			numClipIntersection: nClipIntersection,