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.spotLights.value = lights.state.spot;
 			uniforms.rectAreaLights.value = lights.state.rectArea;
 			uniforms.rectAreaLights.value = lights.state.rectArea;
 			uniforms.pointLights.value = lights.state.point;
 			uniforms.pointLights.value = lights.state.point;
+			uniforms.pointLightShadows.value = lights.state.pointShadow;
 			uniforms.hemisphereLights.value = lights.state.hemi;
 			uniforms.hemisphereLights.value = lights.state.hemi;
 
 
 			uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
 			uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
@@ -2594,6 +2595,7 @@ function WebGLRenderer( parameters ) {
 
 
 		uniforms.directionalLights.needsUpdate = value;
 		uniforms.directionalLights.needsUpdate = value;
 		uniforms.pointLights.needsUpdate = value;
 		uniforms.pointLights.needsUpdate = value;
+		uniforms.pointLightShadows.needsUpdate = value;
 		uniforms.spotLights.needsUpdate = value;
 		uniforms.spotLights.needsUpdate = value;
 		uniforms.rectAreaLights.needsUpdate = value;
 		uniforms.rectAreaLights.needsUpdate = value;
 		uniforms.hemisphereLights.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 )
 #if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )
 
 
 	PointLight pointLight;
 	PointLight pointLight;
+	#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0
+	PointLightShadow pointLightShadow;
+	#endif
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
 	for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {
@@ -40,7 +43,8 @@ IncidentLight directLight;
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 		getPointDirectLightIrradiance( pointLight, geometry, directLight );
 
 
 		#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )
 		#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
 		#endif
 
 
 		RE_Direct( directLight, geometry, material, reflectedLight );
 		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;
 		vec3 color;
 		float distance;
 		float distance;
 		float decay;
 		float decay;
-
-		int shadow;
-		float shadowBias;
-		float shadowRadius;
-		vec2 shadowMapSize;
-		float shadowCameraNear;
-		float shadowCameraFar;
 	};
 	};
 
 
 	uniform PointLight pointLights[ NUM_POINT_LIGHTS ];
 	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
 	// 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 ) {
 	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
 	#if NUM_POINT_LIGHT_SHADOWS > 0
 
 
-	PointLight pointLight;
+	PointLightShadow pointLight;
 
 
 	#pragma unroll_loop
 	#pragma unroll_loop
 	for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {
 	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;
 		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: {};
 				position: {};
 				decay: {};
 				decay: {};
 				distance: {};
 				distance: {};
+			};
+		};
+		pointLightShadows: {
+			value: any[];
+			properties: {
 				shadow: {};
 				shadow: {};
 				shadowBias: {};
 				shadowBias: {};
 				shadowRadius: {};
 				shadowRadius: {};

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

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

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

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

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

@@ -60,13 +60,6 @@ function UniformsCache() {
 						color: new Color(),
 						color: new Color(),
 						distance: 0,
 						distance: 0,
 						decay: 0,
 						decay: 0,
-
-						shadow: false,
-						shadowBias: 0,
-						shadowRadius: 1,
-						shadowMapSize: new Vector2(),
-						shadowCameraNear: 1,
-						shadowCameraFar: 1000
 					};
 					};
 					break;
 					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;
 var nextVersion = 0;
 
 
 function shadowCastingLightsFirst( lightA, lightB ) {
 function shadowCastingLightsFirst( lightA, lightB ) {
@@ -112,6 +166,8 @@ function WebGLLights() {
 
 
 	var cache = new UniformsCache();
 	var cache = new UniformsCache();
 
 
+	var shadowCache = ShadowUniformsCache();
+
 	var state = {
 	var state = {
 
 
 		version: 0,
 		version: 0,
@@ -138,6 +194,7 @@ function WebGLLights() {
 		spotShadowMatrix: [],
 		spotShadowMatrix: [],
 		rectArea: [],
 		rectArea: [],
 		point: [],
 		point: [],
+		pointShadow: [],
 		pointShadowMap: [],
 		pointShadowMap: [],
 		pointShadowMatrix: [],
 		pointShadowMatrix: [],
 		hemi: []
 		hemi: []
@@ -308,18 +365,20 @@ function WebGLLights() {
 				uniforms.distance = light.distance;
 				uniforms.distance = light.distance;
 				uniforms.decay = light.decay;
 				uniforms.decay = light.decay;
 
 
-				uniforms.shadow = light.castShadow;
-
 				if ( light.castShadow ) {
 				if ( light.castShadow ) {
 
 
 					var shadow = light.shadow;
 					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.pointShadowMap[ pointLength ] = shadowMap;
 					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
 					state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;
 
 
@@ -372,6 +431,7 @@ function WebGLLights() {
 			state.hemi.length = hemiLength;
 			state.hemi.length = hemiLength;
 
 
 			state.directionalShadowMap.length = numDirectionalShadows;
 			state.directionalShadowMap.length = numDirectionalShadows;
+			state.pointShadow.length = numPointShadows;
 			state.pointShadowMap.length = numPointShadows;
 			state.pointShadowMap.length = numPointShadows;
 			state.spotShadowMap.length = numSpotShadows;
 			state.spotShadowMap.length = numSpotShadows;
 			state.directionalShadowMatrix.length = numDirectionalShadows;
 			state.directionalShadowMatrix.length = numDirectionalShadows;