Merge pull request #99136 from DarioSamo/light-compute-attenuation-skip

Improve performance of shader lighting code in Forward renderers.
This commit is contained in:
Thaddeus Crews 2024-12-05 14:12:08 -06:00
commit f5d82af1fd
No known key found for this signature in database
GPG key ID: 62181B86FE9E5D84
3 changed files with 215 additions and 273 deletions

View file

@ -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); light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
shadow = blur_shadow(shadow);
light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, 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); light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
shadow = blur_shadow(shadow);
light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, screen_uv,
#ifdef LIGHT_BACKLIGHT_USED #ifdef LIGHT_BACKLIGHT_USED
backlight, backlight,
#endif #endif

View file

@ -1624,13 +1624,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);
light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
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,
#ifdef LIGHT_BACKLIGHT_USED #ifdef LIGHT_BACKLIGHT_USED
backlight, backlight,
#endif #endif
@ -1658,12 +1652,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);
light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, scene_data.taa_frame_count, albedo, alpha, screen_uv,
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,
#ifdef LIGHT_BACKLIGHT_USED #ifdef LIGHT_BACKLIGHT_USED
backlight, backlight,
#endif #endif

View file

@ -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,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; 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
#else
float NdotL = min(A + dot(N, L), 1.0); float NdotL = min(A + dot(N, L), 1.0);
float cNdotL = max(NdotL, 0.0); // clamped NdotL float cNdotV = max(dot(N, V), 1e-4);
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
#ifdef LIGHT_TRANSMITTANCE_USED #ifdef LIGHT_TRANSMITTANCE_USED
{
{
#ifdef SSS_MODE_SKIN #ifdef SSS_MODE_SKIN
float scale = 8.25 / transmittance_depth; float scale = 8.25 / transmittance_depth;
float d = scale * abs(transmittance_z); float d = scale * abs(transmittance_z);
float dd = -d * d; float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + 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.1, 0.336, 0.344) * exp(dd / 0.0484) +
vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); 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 #else
float scale = 8.25 / transmittance_depth; float scale = 8.25 / transmittance_depth;
float d = scale * abs(transmittance_z); float d = scale * abs(transmittance_z);
float dd = -d * d; 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 += exp(dd) * transmittance_color.rgb * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI);
#endif #endif
}
#else
#endif //LIGHT_TRANSMITTANCE_USED
} }
#endif //LIGHT_TRANSMITTANCE_USED
if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely #if defined(LIGHT_RIM_USED)
// Epsilon min to prevent pow(0, 0) singularity which results in undefined behavior.
// D 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;
#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;
#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)
float cLdotH = clamp(A + dot(L, H), 0.0, 1.0);
#endif
#if defined(LIGHT_CLEARCOAT_USED) #if defined(LIGHT_CLEARCOAT_USED)
// Clearcoat ignores normal_map, use vertex normal instead // Clearcoat ignores normal_map, use vertex normal instead
float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0); 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; float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL;
specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount; 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) // 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 // but to do so we need to rearrange this entire function
#endif // LIGHT_CLEARCOAT_USED #endif // LIGHT_CLEARCOAT_USED
}
#ifdef USE_SHADOW_TO_OPACITY if (metallic < 1.0) {
alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 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
#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 #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; 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,
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,
#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) { vec2 normal_to_panorama(vec3 n) {
#ifndef SHADOWS_DISABLED n = normalize(n);
if (spot_lights.data[idx].shadow_opacity > 0.001) { vec2 panorama_coords = vec2(atan(n.x, n.z), acos(-n.y));
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;
vec3 shadow_dir = light_rel_vec / light_length; if (panorama_coords.x < 0.0) {
vec3 normal_bias = normal * light_length * spot_lights.data[idx].shadow_normal_bias * (1.0 - abs(dot(normal, shadow_dir))); 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 //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