From 0ce4c6dac3c78c2e159f22abc802299737fe7c89 Mon Sep 17 00:00:00 2001 From: Dario Date: Tue, 12 Nov 2024 14:33:32 -0300 Subject: [PATCH] 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. --- .../scene_forward_clustered.glsl | 12 +- .../forward_mobile/scene_forward_mobile.glsl | 15 +- .../shaders/scene_forward_lights_inc.glsl | 461 ++++++++---------- 3 files changed, 215 insertions(+), 273 deletions(-) diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 1e1b6d8937..52b3d5d1e3 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/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 } - 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 backlight, #endif @@ -2441,11 +2437,7 @@ void fragment_shader(in SceneData scene_data) { 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 backlight, #endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 0cb34557ea..c0ebf917cc 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/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; 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); - - 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 backlight, #endif @@ -1656,12 +1650,7 @@ void main() { uvec2 spot_indices = instances.data[draw_call.instance_index].spot_lights; 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); - - 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 backlight, #endif diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index 1e8fc7eab4..f58304aa8d 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/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, #endif inout vec3 diffuse_light, inout vec3 specular_light) { - vec4 orms_unpacked = unpackUnorm4x8(orms); - float roughness = orms_unpacked.y; float metallic = orms_unpacked.z; #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 read_view_matrix = scene_data_block.data.view_matrix; #ifdef USING_MOBILE_RENDERER mat4 read_model_matrix = instances.data[draw_call.instance_index].transform; @@ -76,158 +74,61 @@ 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; #endif - mat4 read_view_matrix = scene_data_block.data.view_matrix; - #undef projection_matrix #define projection_matrix scene_data_block.data.projection_matrix #undef inv_projection_matrix #define inv_projection_matrix scene_data_block.data.inv_projection_matrix vec2 read_viewport_size = scene_data_block.data.viewport_size; - vec3 normal = N; vec3 light = L; vec3 view = V; #CODE : LIGHT - -#else - +#else // !LIGHT_CODE_USED 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); -#endif - -#if defined(SPECULAR_SCHLICK_GGX) - float cNdotH = clamp(A + dot(N, H), 0.0, 1.0); -#endif - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED) - float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); -#endif - - if (metallic < 1.0) { - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance - -#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); -#elif defined(DIFFUSE_TOON) - - diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI); - -#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; - */ - } -#else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - diffuse_light += light_color * diffuse_brdf_NL * attenuation; - -#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 + 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); + 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); + 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); + 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 - } -#else - -#endif //LIGHT_TRANSMITTANCE_USED } +#endif //LIGHT_TRANSMITTANCE_USED - if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely - - // D - -#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 - -#elif defined(SPECULAR_DISABLED) - // none.. - -#elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - float alpha_ggx = roughness * roughness; -#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); -#else // LIGHT_ANISOTROPY_USED - float D = D_GGX(cNdotH, alpha_ggx); - float G = V_GGX(cNdotL, cNdotV, alpha_ggx); -#endif // LIGHT_ANISOTROPY_USED - // 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; +#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 + // 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) + float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); +#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); @@ -243,16 +144,89 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, bool is_di 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 - alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0)); + if (metallic < 1.0) { + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance + +#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); +#elif defined(DIFFUSE_TOON) + + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL) * (1.0 / M_PI); + +#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; + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); #endif -#endif //defined(LIGHT_CODE_USED) + diffuse_light += light_color * diffuse_brdf_NL * attenuation; + +#if defined(LIGHT_BACKLIGHT_USED) + diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation; +#endif + } + + 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) + 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) + // Do nothing. + +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + float alpha_ggx = roughness * roughness; +#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); +#else // LIGHT_ANISOTROPY_USED + float D = D_GGX(cNdotH, alpha_ggx); + float G = V_GGX(cNdotL, cNdotV, alpha_ggx); +#endif // LIGHT_ANISOTROPY_USED + // 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 + } + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0)); +#endif + } +#endif // LIGHT_CODE_USED } #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); } -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 - 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 vec2 texel_size = scene_data_block.data.shadow_atlas_pixel_size; 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 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) { //soft shadow @@ -539,49 +545,14 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal, float taa_fr 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); } - - return shadow; } #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; - 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 float transmittance_z = transmittance_depth; //no transmittance by default - transmittance_color.a *= light_attenuation; + transmittance_color.a *= omni_attenuation; #ifndef SHADOWS_DISABLED if (omni_lights.data[idx].shadow_opacity > 0.001) { // 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 backlight, #endif @@ -698,15 +668,66 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v 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)); - 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))); + 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; + + // 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 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 /= splane.w; - float shadow; if (sc_use_light_soft_shadows() && spot_lights.data[idx].soft_shadow_size > 0.0) { //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); 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 - 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; 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 float transmittance_z = transmittance_depth; - transmittance_color.a *= light_attenuation; + transmittance_color.a *= spot_attenuation; #ifndef SHADOWS_DISABLED 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)); @@ -882,9 +844,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v 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 backlight, #endif