Browse Source

Optimize number of point light shadow uniforms

Point light shadow uniforms are now in a separate struct so they don't need to be included in case shadows are not enabled.

This makes it possible to use more shadowless lights on platforms that have low limits for uniform count.

It was experimentally verified that this change makes a difference on 7th gen iPad with iPadOS 13.3.1.
Olli Etuaho 5 years ago
parent
commit
188e4decf3

+ 2 - 0
src/renderers/WebGLRenderer.js

@@ -1613,6 +1613,7 @@ function WebGLRenderer( parameters ) {
 			uniforms.spotLights.value = lights.state.spot;
 			uniforms.rectAreaLights.value = lights.state.rectArea;
 			uniforms.pointLights.value = lights.state.point;
+			uniforms.pointLightShadows.value = lights.state.pointShadow;
 			uniforms.hemisphereLights.value = lights.state.hemi;
 
 			uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
@@ -2594,6 +2595,7 @@ function WebGLRenderer( parameters ) {
 
 		uniforms.directionalLights.needsUpdate = value;
 		uniforms.pointLights.needsUpdate = value;
+		uniforms.pointLightShadows.needsUpdate = value;
 		uniforms.spotLights.needsUpdate = value;
 		uniforms.rectAreaLights.needsUpdate = value;
 		uniforms.hemisphereLights.needsUpdate = value;

+ 5 - 1
src/renderers/shaders/ShaderChunk/lights_fragment_begin.glsl.js

@@ -31,6 +31,9 @@ IncidentLight directLight;
 #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )
 
 	PointLight pointLight;
+	#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0
+	PointLightShadow pointLightShadow;
+	#endif
 
 	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
@@ -40,7 +43,8 @@ IncidentLight directLight;
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 
 		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )
-		directLight.color *= all( bvec3( pointLight.shadow, directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
+		pointLightShadow = pointLightShadows[ i ];
+		directLight.color *= all( bvec3( pointLightShadow.shadow, directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;
 		#endif
 
 		RE_Direct( directLight, geometry, material, reflectedLight );

+ 15 - 7
src/renderers/shaders/ShaderChunk/lights_pars_begin.glsl.js

@@ -86,17 +86,25 @@ vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
 		vec3 color;
 		float distance;
 		float decay;
-
-		int shadow;
-		float shadowBias;
-		float shadowRadius;
-		vec2 shadowMapSize;
-		float shadowCameraNear;
-		float shadowCameraFar;
 	};
 
 	uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
 
+	#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0
+
+		struct PointLightShadow {
+			int shadow;
+			float shadowBias;
+			float shadowRadius;
+			vec2 shadowMapSize;
+			float shadowCameraNear;
+			float shadowCameraFar;
+		};
+
+		uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];
+
+	#endif
+
 	// directLight is an out parameter as having it as a return value caused compiler errors on some devices
 	void getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {
 

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

@@ -35,12 +35,12 @@ float getShadowMask() {
 
 	#if NUM_POINT_LIGHT_SHADOWS > 0
 
-	PointLight pointLight;
+	PointLightShadow pointLight;
 
 	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 
-		pointLight = pointLights[ i ];
+		pointLight = pointLightShadows[ i ];
 		shadow *= all( bvec2( pointLight.shadow, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
 
 	}

+ 5 - 0
src/renderers/shaders/UniformsLib.d.ts

@@ -100,6 +100,11 @@ export let UniformsLib: {
 				position: {};
 				decay: {};
 				distance: {};
+			};
+		};
+		pointLightShadows: {
+			value: any[];
+			properties: {
 				shadow: {};
 				shadowBias: {};
 				shadowRadius: {};

+ 3 - 1
src/renderers/shaders/UniformsLib.js

@@ -147,8 +147,10 @@ var UniformsLib = {
 			color: {},
 			position: {},
 			decay: {},
-			distance: {},
+			distance: {}
+		} },
 
+		pointLightShadows: { value: [], properties: {
 			shadow: {},
 			shadowBias: {},
 			shadowRadius: {},

+ 1 - 0
src/renderers/webgl/WebGLLights.d.ts

@@ -27,6 +27,7 @@ export class WebGLLights {
 		spotShadowMatrix: Array<any>;
 		rectArea: Array<any>;
 		point: Array<any>;
+		pointShadow: Array<any>;
 		pointShadowMap: Array<any>;
 		pointShadowMatrix: Array<any>;
 		hemi: Array<any>;

+ 74 - 14
src/renderers/webgl/WebGLLights.js

@@ -60,13 +60,6 @@ function UniformsCache() {
 						color: new Color(),
 						distance: 0,
 						decay: 0,
-
-						shadow: false,
-						shadowBias: 0,
-						shadowRadius: 1,
-						shadowMapSize: new Vector2(),
-						shadowCameraNear: 1,
-						shadowCameraFar: 1000
 					};
 					break;
 
@@ -100,6 +93,67 @@ function UniformsCache() {
 
 }
 
+function ShadowUniformsCache() {
+
+	var lights = {};
+
+	return {
+
+		get: function ( light ) {
+
+			if ( lights[ light.id ] !== undefined ) {
+
+				return lights[ light.id ];
+
+			}
+
+			var uniforms;
+
+			switch ( light.type ) {
+
+				case 'DirectionalLight':
+					uniforms = {
+						shadow: false,
+						shadowBias: 0,
+						shadowRadius: 1,
+						shadowMapSize: new Vector2()
+					};
+					break;
+
+				case 'SpotLight':
+					uniforms = {
+						shadow: false,
+						shadowBias: 0,
+						shadowRadius: 1,
+						shadowMapSize: new Vector2()
+					};
+					break;
+
+				case 'PointLight':
+					uniforms = {
+						shadow: false,
+						shadowBias: 0,
+						shadowRadius: 1,
+						shadowMapSize: new Vector2(),
+						shadowCameraNear: 1,
+						shadowCameraFar: 1000
+					};
+					break;
+
+			}
+
+			lights[ light.id ] = uniforms;
+
+			return uniforms;
+
+		}
+
+	};
+
+}
+
+
+
 var nextVersion = 0;
 
 function shadowCastingLightsFirst( lightA, lightB ) {
@@ -112,6 +166,8 @@ function WebGLLights() {
 
 	var cache = new UniformsCache();
 
+	var shadowCache = ShadowUniformsCache();
+
 	var state = {
 
 		version: 0,
@@ -138,6 +194,7 @@ function WebGLLights() {
 		spotShadowMatrix: [],
 		rectArea: [],
 		point: [],
+		pointShadow: [],
 		pointShadowMap: [],
 		pointShadowMatrix: [],
 		hemi: []
@@ -308,18 +365,20 @@ function WebGLLights() {
 				uniforms.distance = light.distance;
 				uniforms.decay = light.decay;
 
-				uniforms.shadow = light.castShadow;
-
 				if ( light.castShadow ) {
 
 					var shadow = light.shadow;
 
-					uniforms.shadowBias = shadow.bias;
-					uniforms.shadowRadius = shadow.radius;
-					uniforms.shadowMapSize = shadow.mapSize;
-					uniforms.shadowCameraNear = shadow.camera.near;
-					uniforms.shadowCameraFar = shadow.camera.far;
+					var shadowUniforms = shadowCache.get( light );
+
+					shadowUniforms.shadow = light.castShadow;
+					shadowUniforms.shadowBias = shadow.bias;
+					shadowUniforms.shadowRadius = shadow.radius;
+					shadowUniforms.shadowMapSize = shadow.mapSize;
+					shadowUniforms.shadowCameraNear = shadow.camera.near;
+					shadowUniforms.shadowCameraFar = shadow.camera.far;
 
+					state.pointShadow[ pointLength ] = shadowUniforms;
 					state.pointShadowMap[ pointLength ] = shadowMap;
 					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
 
@@ -372,6 +431,7 @@ function WebGLLights() {
 			state.hemi.length = hemiLength;
 
 			state.directionalShadowMap.length = numDirectionalShadows;
+			state.pointShadow.length = numPointShadows;
 			state.pointShadowMap.length = numPointShadows;
 			state.spotShadowMap.length = numSpotShadows;
 			state.directionalShadowMatrix.length = numDirectionalShadows;