Browse Source

Improve performance of shader lighting code in Forward renderers.

- Skip sampling shadows if attenuation is very small.
- Skip computing diffuse and specular light if attenuation and shadow are very small.
Dario 9 months ago
parent
commit
0ce4c6dac3

+ 2 - 10
servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl

@@ -2369,11 +2369,7 @@ void fragment_shader(in SceneData scene_data) {
 					continue; // Statically baked light and object uses lightmap, skip
 					continue; // Statically baked light and object uses lightmap, skip
 				}
 				}
 
 
-				float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
-
-				shadow = blur_shadow(shadow);
-
-				light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
+				light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 						backlight,
 						backlight,
 #endif
 #endif
@@ -2441,11 +2437,7 @@ void fragment_shader(in SceneData scene_data) {
 					continue; // Statically baked light and object uses lightmap, skip
 					continue; // Statically baked light and object uses lightmap, skip
 				}
 				}
 
 
-				float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
-
-				shadow = blur_shadow(shadow);
-
-				light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
+				light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 						backlight,
 						backlight,
 #endif
 #endif

+ 2 - 13
servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl

@@ -1622,13 +1622,7 @@ void main() {
 	uvec2 omni_indices = instances.data[draw_call.instance_index].omni_lights;
 	uvec2 omni_indices = instances.data[draw_call.instance_index].omni_lights;
 	for (uint i = 0; i < sc_omni_lights(); i++) {
 	for (uint i = 0; i < sc_omni_lights(); i++) {
 		uint light_index = (i > 3) ? ((omni_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_indices.x >> (i * 8)) & 0xFF);
 		uint light_index = (i > 3) ? ((omni_indices.y >> ((i - 4) * 8)) & 0xFF) : ((omni_indices.x >> (i * 8)) & 0xFF);
-
-		float shadow = light_process_omni_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
-
-		shadow = blur_shadow(shadow);
-
-		// Fragment lighting
-		light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
+		light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 				backlight,
 				backlight,
 #endif
 #endif
@@ -1656,12 +1650,7 @@ void main() {
 	uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights;
 	uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights;
 	for (uint i = 0; i < sc_spot_lights(); i++) {
 	for (uint i = 0; i < sc_spot_lights(); i++) {
 		uint light_index = (i > 3) ? ((spot_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_indices.x >> (i * 8)) & 0xFF);
 		uint light_index = (i > 3) ? ((spot_indices.y >> ((i - 4) * 8)) & 0xFF) : ((spot_indices.x >> (i * 8)) & 0xFF);
-
-		float shadow = light_process_spot_shadow(light_index, vertex, normal, scene_data.taa_frame_count);
-
-		shadow = blur_shadow(shadow);
-
-		light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
+		light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 				backlight,
 				backlight,
 #endif
 #endif

+ 207 - 246
servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl

@@ -59,16 +59,14 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
 		vec3 B, vec3 T, float anisotropy,
 		vec3 B, vec3 T, float anisotropy,
 #endif
 #endif
 		inout vec3 diffuse_light, inout vec3 specular_light) {
 		inout vec3 diffuse_light, inout vec3 specular_light) {
-
 	vec4 orms_unpacked = unpackUnorm4x8(orms);
 	vec4 orms_unpacked = unpackUnorm4x8(orms);
-
 	float roughness = orms_unpacked.y;
 	float roughness = orms_unpacked.y;
 	float metallic = orms_unpacked.z;
 	float metallic = orms_unpacked.z;
 
 
 #if defined(LIGHT_CODE_USED)
 #if defined(LIGHT_CODE_USED)
-	// light is written by the light shader
-
+	// Light is written by the user shader.
 	mat4 inv_view_matrix = scene_data_block.data.inv_view_matrix;
 	mat4 inv_view_matrix = scene_data_block.data.inv_view_matrix;
+	mat4 read_view_matrix = scene_data_block.data.view_matrix;
 
 
 #ifdef USING_MOBILE_RENDERER
 #ifdef USING_MOBILE_RENDERER
 	mat4 read_model_matrix = instances.data[draw_call.instance_index].transform;
 	mat4 read_model_matrix = instances.data[draw_call.instance_index].transform;
@@ -76,183 +74,159 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di
 	mat4 read_model_matrix = instances.data[instance_index_interp].transform;
 	mat4 read_model_matrix = instances.data[instance_index_interp].transform;
 #endif
 #endif
 
 
-	mat4 read_view_matrix = scene_data_block.data.view_matrix;
-
 #undef projection_matrix
 #undef projection_matrix
 #define projection_matrix scene_data_block.data.projection_matrix
 #define projection_matrix scene_data_block.data.projection_matrix
 #undef inv_projection_matrix
 #undef inv_projection_matrix
 #define inv_projection_matrix scene_data_block.data.inv_projection_matrix
 #define inv_projection_matrix scene_data_block.data.inv_projection_matrix
 
 
 	vec2 read_viewport_size = scene_data_block.data.viewport_size;
 	vec2 read_viewport_size = scene_data_block.data.viewport_size;
-
 	vec3 normal = N;
 	vec3 normal = N;
 	vec3 light = L;
 	vec3 light = L;
 	vec3 view = V;
 	vec3 view = V;
 
 
 #CODE : LIGHT
 #CODE : LIGHT
+#else // !LIGHT_CODE_USED
+	float NdotL = min(A + dot(N, L), 1.0);
+	float cNdotV = max(dot(N, V), 1e-4);
 
 
+#ifdef LIGHT_TRANSMITTANCE_USED
+	{
+#ifdef SSS_MODE_SKIN
+		float scale = 8.25 / transmittance_depth;
+		float d = scale * abs(transmittance_z);
+		float dd = -d * d;
+		vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
+				vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+				vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+				vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+				vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+				vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+
+		diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
 #else
 #else
 
 
-	float NdotL = min(A + dot(N, L), 1.0);
-	float cNdotL = max(NdotL, 0.0); // clamped NdotL
-	float NdotV = dot(N, V);
-	float cNdotV = max(NdotV, 1e-4);
-
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-	vec3 H = normalize(V + L);
+		float scale = 8.25 / transmittance_depth;
+		float d = scale * abs(transmittance_z);
+		float dd = -d * d;
+		diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
 #endif
 #endif
+	}
+#endif //LIGHT_TRANSMITTANCE_USED
 
 
-#if defined(SPECULAR_SCHLICK_GGX)
-	float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
+#if defined(LIGHT_RIM_USED)
+	// Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior.
+	float rim_light = pow(max(1e-4, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
+	diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
 #endif
 #endif
 
 
+	// We skip checking on attenuation on directional lights to avoid a branch that is not as beneficial for directional lights as the other ones.
+	const float EPSILON = 1e-3f;
+	if (is_directional || attenuation > EPSILON) {
+		float cNdotL = max(NdotL, 0.0);
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+		vec3 H = normalize(V + L);
+#endif
 #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
 #if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
-	float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
+		float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
 #endif
 #endif
+#if defined(LIGHT_CLEARCOAT_USED)
+		// Clearcoat ignores normal_map, use vertex normal instead
+		float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0);
+		float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0);
+		float ccNdotV = max(dot(vertex_normal, V), 1e-4);
+
+#if !defined(SPECULAR_SCHLICK_GGX)
+		float cLdotH5 = SchlickFresnel(cLdotH);
+#endif
+		float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness));
+		float Gr = 0.25 / (cLdotH * cLdotH);
+		float Fr = mix(.04, 1.0, cLdotH5);
+		float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL;
+
+		specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
+
+		// TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR)
+		// but to do so we need to rearrange this entire function
+#endif // LIGHT_CLEARCOAT_USED
 
 
-	if (metallic < 1.0) {
-		float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
+		if (metallic < 1.0) {
+			float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
 
 
 #if defined(DIFFUSE_LAMBERT_WRAP)
 #if defined(DIFFUSE_LAMBERT_WRAP)
-		// Energy conserving lambert wrap shader.
-		// https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
-		diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI);
+			// Energy conserving lambert wrap shader.
+			// https://web.archive.org/web/20210228210901/http://blog.stevemcauley.com/2011/12/03/energy-conserving-wrapped-diffuse/
+			diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))) * (1.0 / M_PI);
 #elif defined(DIFFUSE_TOON)
 #elif defined(DIFFUSE_TOON)
 
 
-		diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI);
+			diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI);
 
 
 #elif defined(DIFFUSE_BURLEY)
 #elif defined(DIFFUSE_BURLEY)
-
-		{
-			float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
-			float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
-			float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL);
-			diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
-			/*
-			float energyBias = mix(roughness, 0.0, 0.5);
-			float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
-			float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
-			float f0 = 1.0;
-			float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
-			float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
-
-			diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;
-			*/
-		}
+			{
+				float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5;
+				float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV);
+				float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL);
+				diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
+			}
 #else
 #else
-		// lambert
-		diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
+			// lambert
+			diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
 #endif
 #endif
 
 
-		diffuse_light += light_color * diffuse_brdf_NL * attenuation;
+			diffuse_light += light_color * diffuse_brdf_NL * attenuation;
 
 
 #if defined(LIGHT_BACKLIGHT_USED)
 #if defined(LIGHT_BACKLIGHT_USED)
-		diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
-#endif
-
-#if defined(LIGHT_RIM_USED)
-		// Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior.
-		float rim_light = pow(max(1e-4, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
-		diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
-#endif
-
-#ifdef LIGHT_TRANSMITTANCE_USED
-
-		{
-#ifdef SSS_MODE_SKIN
-			float scale = 8.25 / transmittance_depth;
-			float d = scale * abs(transmittance_z);
-			float dd = -d * d;
-			vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
-					vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
-					vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
-					vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
-					vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
-					vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
-
-			diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
-#else
-
-			float scale = 8.25 / transmittance_depth;
-			float d = scale * abs(transmittance_z);
-			float dd = -d * d;
-			diffuse_light += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
+			diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
 #endif
 #endif
 		}
 		}
-#else
-
-#endif //LIGHT_TRANSMITTANCE_USED
-	}
-
-	if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-
-		// D
 
 
+		if (roughness > 0.0) {
+#if defined(SPECULAR_SCHLICK_GGX)
+			float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
+#endif
+			// Apply specular light.
+			// FIXME: roughness == 0 should not disable specular light entirely
 #if defined(SPECULAR_TOON)
 #if defined(SPECULAR_TOON)
-
-		vec3 R = normalize(-reflect(L, N));
-		float RdotV = dot(R, V);
-		float mid = 1.0 - roughness;
-		mid *= mid;
-		float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
-		diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
+			vec3 R = normalize(-reflect(L, N));
+			float RdotV = dot(R, V);
+			float mid = 1.0 - roughness;
+			mid *= mid;
+			float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
+			diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
 
 
 #elif defined(SPECULAR_DISABLED)
 #elif defined(SPECULAR_DISABLED)
-		// none..
+			// Do nothing.
 
 
 #elif defined(SPECULAR_SCHLICK_GGX)
 #elif defined(SPECULAR_SCHLICK_GGX)
-		// shlick+ggx as default
-		float alpha_ggx = roughness * roughness;
+			// shlick+ggx as default
+			float alpha_ggx = roughness * roughness;
 #if defined(LIGHT_ANISOTROPY_USED)
 #if defined(LIGHT_ANISOTROPY_USED)
-
-		float aspect = sqrt(1.0 - anisotropy * 0.9);
-		float ax = alpha_ggx / aspect;
-		float ay = alpha_ggx * aspect;
-		float XdotH = dot(T, H);
-		float YdotH = dot(B, H);
-		float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
-		float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL);
+			float aspect = sqrt(1.0 - anisotropy * 0.9);
+			float ax = alpha_ggx / aspect;
+			float ay = alpha_ggx * aspect;
+			float XdotH = dot(T, H);
+			float YdotH = dot(B, H);
+			float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
+			float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL);
 #else // LIGHT_ANISOTROPY_USED
 #else // LIGHT_ANISOTROPY_USED
-		float D = D_GGX(cNdotH, alpha_ggx);
-		float G = V_GGX(cNdotL, cNdotV, alpha_ggx);
+			float D = D_GGX(cNdotH, alpha_ggx);
+			float G = V_GGX(cNdotL, cNdotV, alpha_ggx);
 #endif // LIGHT_ANISOTROPY_USED
 #endif // LIGHT_ANISOTROPY_USED
 	   // F
 	   // F
-		float cLdotH5 = SchlickFresnel(cLdotH);
-		// Calculate Fresnel using specular occlusion term from Filament:
-		// https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion
-		float f90 = clamp(dot(f0, vec3(50.0 * 0.33)), metallic, 1.0);
-		vec3 F = f0 + (f90 - f0) * cLdotH5;
-
-		vec3 specular_brdf_NL = cNdotL * D * F * G;
-
-		specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
-#endif
-
-#if defined(LIGHT_CLEARCOAT_USED)
-		// Clearcoat ignores normal_map, use vertex normal instead
-		float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0);
-		float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0);
-		float ccNdotV = max(dot(vertex_normal, V), 1e-4);
-
-#if !defined(SPECULAR_SCHLICK_GGX)
-		float cLdotH5 = SchlickFresnel(cLdotH);
+			float cLdotH5 = SchlickFresnel(cLdotH);
+			// Calculate Fresnel using specular occlusion term from Filament:
+			// https://google.github.io/filament/Filament.html#lighting/occlusion/specularocclusion
+			float f90 = clamp(dot(f0, vec3(50.0 * 0.33)), metallic, 1.0);
+			vec3 F = f0 + (f90 - f0) * cLdotH5;
+			vec3 specular_brdf_NL = cNdotL * D * F * G;
+			specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
 #endif
 #endif
-		float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness));
-		float Gr = 0.25 / (cLdotH * cLdotH);
-		float Fr = mix(.04, 1.0, cLdotH5);
-		float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL;
-
-		specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
-		// TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR)
-		// but to do so we need to rearrange this entire function
-#endif // LIGHT_CLEARCOAT_USED
-	}
+		}
 
 
 #ifdef USE_SHADOW_TO_OPACITY
 #ifdef USE_SHADOW_TO_OPACITY
-	alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
+		alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
 #endif
 #endif
-
-#endif //defined(LIGHT_CODE_USED)
+	}
+#endif // LIGHT_CODE_USED
 }
 }
 
 
 #ifndef SHADOWS_DISABLED
 #ifndef SHADOWS_DISABLED
@@ -412,9 +386,43 @@ float get_omni_attenuation(float distance, float inv_range, float decay) {
 	return nd * pow(max(distance, 0.0001), -decay);
 	return nd * pow(max(distance, 0.0001), -decay);
 }
 }
 
 
-float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_frame_count) {
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float taa_frame_count, vec3 albedo, inout float alpha, vec2 screen_uv,
+#ifdef LIGHT_BACKLIGHT_USED
+		vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+		vec4 transmittance_color,
+		float transmittance_depth,
+		float transmittance_boost,
+#endif
+#ifdef LIGHT_RIM_USED
+		float rim, float rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+		vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+		inout vec3 diffuse_light, inout vec3 specular_light) {
+	const float EPSILON = 1e-3f;
+
+	// Omni light attenuation.
+	vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
+	float light_length = length(light_rel_vec);
+	float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
+
+	// Compute size.
+	float size = 0.0;
+	if (sc_use_light_soft_shadows() && omni_lights.data[idx].size > 0.0) {
+		float t = omni_lights.data[idx].size / max(0.001, light_length);
+		size = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+	}
+
+	float shadow = 1.0;
 #ifndef SHADOWS_DISABLED
 #ifndef SHADOWS_DISABLED
-	if (omni_lights.data[idx].shadow_opacity > 0.001) {
+	// Omni light shadow.
+	if (omni_attenuation > EPSILON && omni_lights.data[idx].shadow_opacity > 0.001) {
 		// there is a shadowmap
 		// there is a shadowmap
 		vec2 texel_size = scene_data_block.data.shadow_atlas_pixel_size;
 		vec2 texel_size = scene_data_block.data.shadow_atlas_pixel_size;
 		vec4 base_uv_rect = omni_lights.data[idx].atlas_rect;
 		vec4 base_uv_rect = omni_lights.data[idx].atlas_rect;
@@ -432,8 +440,6 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
 		vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal);
 		vec3 local_normal = normalize(mat3(omni_lights.data[idx].shadow_matrix) * normal);
 		vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir)));
 		vec3 normal_bias = local_normal * omni_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(local_normal, shadow_dir)));
 
 
-		float shadow;
-
 		if (sc_use_light_soft_shadows() && omni_lights.data[idx].soft_shadow_size > 0.0) {
 		if (sc_use_light_soft_shadows() && omni_lights.data[idx].soft_shadow_size > 0.0) {
 			//soft shadow
 			//soft shadow
 
 
@@ -539,49 +545,14 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
 			depth = 1.0 - depth;
 			depth = 1.0 - depth;
 			shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth, taa_frame_count), omni_lights.data[idx].shadow_opacity);
 			shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth, taa_frame_count), omni_lights.data[idx].shadow_opacity);
 		}
 		}
-
-		return shadow;
 	}
 	}
 #endif
 #endif
 
 
-	return 1.0;
-}
-
-void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv,
-#ifdef LIGHT_BACKLIGHT_USED
-		vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
-		vec4 transmittance_color,
-		float transmittance_depth,
-		float transmittance_boost,
-#endif
-#ifdef LIGHT_RIM_USED
-		float rim, float rim_tint,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
-		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
-		vec3 binormal, vec3 tangent, float anisotropy,
-#endif
-		inout vec3 diffuse_light, inout vec3 specular_light) {
-	vec3 light_rel_vec = omni_lights.data[idx].position - vertex;
-	float light_length = length(light_rel_vec);
-	float omni_attenuation = get_omni_attenuation(light_length, omni_lights.data[idx].inv_radius, omni_lights.data[idx].attenuation);
-	float light_attenuation = omni_attenuation;
 	vec3 color = omni_lights.data[idx].color;
 	vec3 color = omni_lights.data[idx].color;
 
 
-	float size_A = 0.0;
-
-	if (sc_use_light_soft_shadows() && omni_lights.data[idx].size > 0.0) {
-		float t = omni_lights.data[idx].size / max(0.001, light_length);
-		size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
-	}
-
 #ifdef LIGHT_TRANSMITTANCE_USED
 #ifdef LIGHT_TRANSMITTANCE_USED
 	float transmittance_z = transmittance_depth; //no transmittance by default
 	float transmittance_z = transmittance_depth; //no transmittance by default
-	transmittance_color.a *= light_attenuation;
+	transmittance_color.a *= omni_attenuation;
 #ifndef SHADOWS_DISABLED
 #ifndef SHADOWS_DISABLED
 	if (omni_lights.data[idx].shadow_opacity > 0.001) {
 	if (omni_lights.data[idx].shadow_opacity > 0.001) {
 		// Redo shadowmapping, but shrink the model a bit to avoid artifacts.
 		// Redo shadowmapping, but shrink the model a bit to avoid artifacts.
@@ -673,9 +644,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
 		}
 		}
 	}
 	}
 
 
-	light_attenuation *= shadow;
-
-	light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, screen_uv,
+	vec3 light_rel_vec_norm = light_rel_vec / light_length;
+	light_compute(normal, light_rel_vec_norm, eye_vec, size, color, false, omni_attenuation * shadow, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, screen_uv,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 			backlight,
 			backlight,
 #endif
 #endif
@@ -698,15 +668,66 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
 			specular_light);
 			specular_light);
 }
 }
 
 
-float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_frame_count) {
-#ifndef SHADOWS_DISABLED
-	if (spot_lights.data[idx].shadow_opacity > 0.001) {
-		vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
-		float light_length = length(light_rel_vec);
-		vec3 spot_dir = spot_lights.data[idx].direction;
+vec2 normal_to_panorama(vec3 n) {
+	n = normalize(n);
+	vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y));
+
+	if (panorama_coords.x < 0.0) {
+		panorama_coords.x += M_PI * 2.0;
+	}
+
+	panorama_coords /= vec2(M_PI * 2.0, M_PI);
+	return panorama_coords;
+}
+
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float taa_frame_count, vec3 albedo, inout float alpha, vec2 screen_uv,
+#ifdef LIGHT_BACKLIGHT_USED
+		vec3 backlight,
+#endif
+#ifdef LIGHT_TRANSMITTANCE_USED
+		vec4 transmittance_color,
+		float transmittance_depth,
+		float transmittance_boost,
+#endif
+#ifdef LIGHT_RIM_USED
+		float rim, float rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+		vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+		inout vec3 diffuse_light,
+		inout vec3 specular_light) {
+	const float EPSILON = 1e-3f;
+
+	// Spot light attenuation.
+	vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
+	float light_length = length(light_rel_vec);
+	vec3 light_rel_vec_norm = light_rel_vec / light_length;
+	float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
+	vec3 spot_dir = spot_lights.data[idx].direction;
 
 
-		vec3 shadow_dir = light_rel_vec / light_length;
-		vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir)));
+	// This conversion to a highp float is crucial to prevent light leaking
+	// due to precision errors in the following calculations (cone angle is mediump).
+	highp float cone_angle = spot_lights.data[idx].cone_angle;
+	float scos = max(dot(-light_rel_vec_norm, spot_dir), cone_angle);
+	float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle));
+	spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
+
+	// Compute size.
+	float size = 0.0;
+	if (sc_use_light_soft_shadows() && spot_lights.data[idx].size > 0.0) {
+		float t = spot_lights.data[idx].size / max(0.001, light_length);
+		size = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+	}
+
+	float shadow = 1.0;
+#ifndef SHADOWS_DISABLED
+	// Spot light shadow.
+	if (spot_attenuation > EPSILON && spot_lights.data[idx].shadow_opacity > 0.001) {
+		vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, light_rel_vec_norm)));
 
 
 		//there is a shadowmap
 		//there is a shadowmap
 		vec4 v = vec4(vertex + normal_bias, 1.0);
 		vec4 v = vec4(vertex + normal_bias, 1.0);
@@ -715,7 +736,6 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
 		splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
 		splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
 		splane /= splane.w;
 		splane /= splane.w;
 
 
-		float shadow;
 		if (sc_use_light_soft_shadows() && spot_lights.data[idx].soft_shadow_size > 0.0) {
 		if (sc_use_light_soft_shadows() && spot_lights.data[idx].soft_shadow_size > 0.0) {
 			//soft shadow
 			//soft shadow
 
 
@@ -772,73 +792,15 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr
 			vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z);
 			vec3 shadow_uv = vec3(splane.xy * spot_lights.data[idx].atlas_rect.zw + spot_lights.data[idx].atlas_rect.xy, splane.z);
 			shadow = mix(1.0, sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv, taa_frame_count), spot_lights.data[idx].shadow_opacity);
 			shadow = mix(1.0, sample_pcf_shadow(shadow_atlas, spot_lights.data[idx].soft_shadow_scale * scene_data_block.data.shadow_atlas_pixel_size, shadow_uv, taa_frame_count), spot_lights.data[idx].shadow_opacity);
 		}
 		}
-
-		return shadow;
 	}
 	}
-
 #endif // SHADOWS_DISABLED
 #endif // SHADOWS_DISABLED
 
 
-	return 1.0;
-}
-
-vec2 normal_to_panorama(vec3 n) {
-	n = normalize(n);
-	vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y));
-
-	if (panorama_coords.x < 0.0) {
-		panorama_coords.x += M_PI * 2.0;
-	}
-
-	panorama_coords /= vec2(M_PI * 2.0, M_PI);
-	return panorama_coords;
-}
-
-void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, vec2 screen_uv,
-#ifdef LIGHT_BACKLIGHT_USED
-		vec3 backlight,
-#endif
-#ifdef LIGHT_TRANSMITTANCE_USED
-		vec4 transmittance_color,
-		float transmittance_depth,
-		float transmittance_boost,
-#endif
-#ifdef LIGHT_RIM_USED
-		float rim, float rim_tint,
-#endif
-#ifdef LIGHT_CLEARCOAT_USED
-		float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
-#endif
-#ifdef LIGHT_ANISOTROPY_USED
-		vec3 binormal, vec3 tangent, float anisotropy,
-#endif
-		inout vec3 diffuse_light,
-		inout vec3 specular_light) {
-	vec3 light_rel_vec = spot_lights.data[idx].position - vertex;
-	float light_length = length(light_rel_vec);
-	float spot_attenuation = get_omni_attenuation(light_length, spot_lights.data[idx].inv_radius, spot_lights.data[idx].attenuation);
-	vec3 spot_dir = spot_lights.data[idx].direction;
-
-	// This conversion to a highp float is crucial to prevent light leaking
-	// due to precision errors in the following calculations (cone angle is mediump).
-	highp float cone_angle = spot_lights.data[idx].cone_angle;
-	float scos = max(dot(-normalize(light_rel_vec), spot_dir), cone_angle);
-	float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cone_angle));
-
-	spot_attenuation *= 1.0 - pow(spot_rim, spot_lights.data[idx].cone_attenuation);
-	float light_attenuation = spot_attenuation;
 	vec3 color = spot_lights.data[idx].color;
 	vec3 color = spot_lights.data[idx].color;
 	float specular_amount = spot_lights.data[idx].specular_amount;
 	float specular_amount = spot_lights.data[idx].specular_amount;
 
 
-	float size_A = 0.0;
-
-	if (sc_use_light_soft_shadows() && spot_lights.data[idx].size > 0.0) {
-		float t = spot_lights.data[idx].size / max(0.001, light_length);
-		size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
-	}
-
 #ifdef LIGHT_TRANSMITTANCE_USED
 #ifdef LIGHT_TRANSMITTANCE_USED
 	float transmittance_z = transmittance_depth;
 	float transmittance_z = transmittance_depth;
-	transmittance_color.a *= light_attenuation;
+	transmittance_color.a *= spot_attenuation;
 #ifndef SHADOWS_DISABLED
 #ifndef SHADOWS_DISABLED
 	if (spot_lights.data[idx].shadow_opacity > 0.001) {
 	if (spot_lights.data[idx].shadow_opacity > 0.001) {
 		vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal) * spot_lights.data[idx].transmittance_bias, 1.0));
 		vec4 splane = (spot_lights.data[idx].shadow_matrix * vec4(vertex - normalize(normal) * spot_lights.data[idx].transmittance_bias, 1.0));
@@ -882,9 +844,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
 			color *= proj.rgb * proj.a;
 			color *= proj.rgb * proj.a;
 		}
 		}
 	}
 	}
-	light_attenuation *= shadow;
 
 
-	light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, false, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, screen_uv,
+	light_compute(normal, light_rel_vec_norm, eye_vec, size, color, false, spot_attenuation * shadow, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, screen_uv,
 #ifdef LIGHT_BACKLIGHT_USED
 #ifdef LIGHT_BACKLIGHT_USED
 			backlight,
 			backlight,
 #endif
 #endif