diff options
author | reduz <reduzio@gmail.com> | 2021-01-05 12:33:54 -0300 |
---|---|---|
committer | reduz <reduzio@gmail.com> | 2021-01-05 14:44:05 -0300 |
commit | 446618cf94fac48168e6fc8ead545ab3f349da0a (patch) | |
tree | 25ee8685b15145a9d20c1047c4d9fccc28e26bd0 | |
parent | 6e23ab4fa20f766ef9e1ec64be88675db6c708af (diff) |
Change the light attenuation formulas.
-Much better looking, physically based.
-Almost negligible extra cost.
5 files changed, 58 insertions, 14 deletions
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 56976bd623..8a9adbc5cc 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -249,6 +249,15 @@ float quick_hash(vec2 pos) { return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + void main() { #ifdef MODE_LIGHT_PROBES int probe_index = int(gl_GlobalInvocationID.x); @@ -300,7 +309,7 @@ void main() { d /= lights.data[i].range; - attenuation = pow(max(1.0 - d, 0.0), lights.data[i].attenuation); + attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation); if (lights.data[i].type == LIGHT_TYPE_SPOT) { vec3 rel = normalize(position - light_pos); diff --git a/servers/rendering/renderer_rd/shaders/giprobe.glsl b/servers/rendering/renderer_rd/shaders/giprobe.glsl index ea4237a45e..4f4753d147 100644 --- a/servers/rendering/renderer_rd/shaders/giprobe.glsl +++ b/servers/rendering/renderer_rd/shaders/giprobe.glsl @@ -208,6 +208,15 @@ float raymarch(float distance, float distance_adv, vec3 from, vec3 direction) { return occlusion; //max(0.0,distance); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 light_pos) { if (lights.data[light].type == LIGHT_TYPE_DIRECTIONAL) { light_pos = pos - lights.data[light].direction * length(vec3(params.limits)); @@ -220,7 +229,7 @@ bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 return false; } - attenuation = pow(clamp(1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation); + attenuation = get_omni_attenuation(distance, 1.0 / lights.data[light].radius, lights.data[light].attenuation); if (lights.data[light].type == LIGHT_TYPE_SPOT) { vec3 rel = normalize(pos - light_pos); diff --git a/servers/rendering/renderer_rd/shaders/scene_forward.glsl b/servers/rendering/renderer_rd/shaders/scene_forward.glsl index 5d041babf1..0518976322 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward.glsl @@ -891,6 +891,15 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex #endif //USE_NO_SHADOWS +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, @@ -916,9 +925,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = lights.data[idx].position - vertex; float light_length = length(light_rel_vec); - float normalized_distance = light_length * lights.data[idx].inv_radius; vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); - float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x); + float omni_attenuation = get_omni_attenuation(light_length, lights.data[idx].inv_radius, attenuation_energy.x); float light_attenuation = omni_attenuation; vec3 shadow_attenuation = vec3(1.0); vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular); @@ -1205,9 +1213,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v inout vec3 specular_light) { vec3 light_rel_vec = lights.data[idx].position - vertex; float light_length = length(light_rel_vec); - float normalized_distance = light_length * lights.data[idx].inv_radius; vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy); - float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x); + float spot_attenuation = get_omni_attenuation(light_length, lights.data[idx].inv_radius, attenuation_energy.x); vec3 spot_dir = lights.data[idx].direction; vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle); float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y); diff --git a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl index 61e4bf5e18..30dbf5871f 100644 --- a/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl +++ b/servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl @@ -112,6 +112,15 @@ vec2 octahedron_encode(vec3 n) { return n.xy; } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + void main() { uint voxel_index = uint(gl_GlobalInvocationID.x); @@ -184,14 +193,15 @@ void main() { direction = normalize(rel_vec); light_distance = length(rel_vec); rel_vec.y /= params.y_mult; - attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation); + attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation); + } break; case LIGHT_TYPE_SPOT: { vec3 rel_vec = lights.data[i].position - position; direction = normalize(rel_vec); light_distance = length(rel_vec); rel_vec.y /= params.y_mult; - attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation); + attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation); float angle = acos(dot(normalize(rel_vec), -lights.data[i].direction)); if (angle > lights.data[i].spot_angle) { diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index 13b162f0c9..498a6ddb5b 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -169,6 +169,15 @@ vec3 hash3f(uvec3 x) { return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF)); } +float get_omni_attenuation(float distance, float inv_range, float decay) { + float nd = distance * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(distance, 0.0001), -decay); +} + void main() { vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size); @@ -270,14 +279,14 @@ void main() { uint light_index = cluster_data.indices[omni_light_pointer + i]; vec3 light_pos = lights.data[i].position; - float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius; + float d = distance(lights.data[i].position, view_pos); vec3 shadow_attenuation = vec3(1.0); - if (d < 1.0) { + if (d * lights.data[i].inv_radius < 1.0) { vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); - float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + float attenuation = get_omni_attenuation(d, lights.data[i].inv_radius, attenuation_energy.x); vec3 light = attenuation_energy.y * color_specular.rgb / M_PI; @@ -326,14 +335,14 @@ void main() { vec3 light_pos = lights.data[i].position; vec3 light_rel_vec = lights.data[i].position - view_pos; - float d = length(light_rel_vec) * lights.data[i].inv_radius; + float d = length(light_rel_vec); vec3 shadow_attenuation = vec3(1.0); - if (d < 1.0) { + if (d * lights.data[i].inv_radius < 1.0) { vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy); vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular); - float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x); + float attenuation = get_omni_attenuation(d, lights.data[i].inv_radius, attenuation_energy.x); vec3 spot_dir = lights.data[i].direction; vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle); |