From 4203391783a0d9912b3dbd6093898c1f991aa190 Mon Sep 17 00:00:00 2001 From: nullprop Date: Tue, 26 Dec 2023 20:23:40 +0200 Subject: [PATCH] Better ambient light estimation --- res/shaders/constants.wgsl | 2 -- res/shaders/fog.wgsl | 12 ++++++------ res/shaders/light.wgsl | 17 +++++++++++++++++ res/shaders/pbr.wgsl | 30 +++++++++++++++++------------- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/res/shaders/constants.wgsl b/res/shaders/constants.wgsl index bbb3eed..98f3424 100644 --- a/res/shaders/constants.wgsl +++ b/res/shaders/constants.wgsl @@ -14,7 +14,5 @@ const FOG_LIGHT_STEP_SIZE = 10.0; const FOG_DENSITY = 2.0; const FOG_LIGHT_DENSITY = 3.0; const FOG_ALPHA = 1.0; -const FOG_AMBIENT = 0.06; const FOG_DENSITY_COLOR = vec2(0.5, 0.1); -const PBR_AMBIENT = 0.02; diff --git a/res/shaders/fog.wgsl b/res/shaders/fog.wgsl index df2b956..e57c7f8 100644 --- a/res/shaders/fog.wgsl +++ b/res/shaders/fog.wgsl @@ -140,24 +140,24 @@ fn fs_main(vert: FogVertexOutput) -> @location(0) vec4 { let fog_depth = march_result.y; let occlusion = march_result.z; + let fog_position = vert.world_position.xyz + direction * fog_depth; + let light_dist = length(light.position - fog_position); + let base_color = vec3(mix(FOG_DENSITY_COLOR.x, FOG_DENSITY_COLOR.y, fog_density)); - let ambient_strength = FOG_AMBIENT; - let ambient_color = base_color * ambient_strength; + var ambient = 2.0 * sample_ambient_light(light.color, light_dist, 1.0); + ambient *= base_color; var radiance = vec3(0.0); - let fog_position = vert.world_position.xyz + direction * fog_depth; let in_light = sample_direct_light(vec4(fog_position, 1.0)); if (in_light > 0.0) { // attenuation - let light_dist = length(light.position - fog_position); let coef_a = 0.0; let coef_b = 1.0; let light_attenuation = 1.0 / (1.0 + coef_a * light_dist + coef_b * light_dist * light_dist); - radiance = light.color.rgb * light.color.a * light_attenuation * in_light * (1.0 - occlusion); } - var result = ambient_color + radiance; + var result = ambient + radiance; // tonemap result = result / (result + vec3(1.0)); diff --git a/res/shaders/light.wgsl b/res/shaders/light.wgsl index ed6f743..d0971e7 100644 --- a/res/shaders/light.wgsl +++ b/res/shaders/light.wgsl @@ -59,3 +59,20 @@ fn sample_direct_light(world_position: vec4) -> f32 { } return in_light; } + +fn sample_ambient_light(light: vec4, light_dist: f32, surface_light_dot: f32) -> vec3 { + // base ambient + var ambient = vec3(0.01); + + // lower attenuation to reduce light bleed + let diff_coef_a = -0.75; + let diff_coef_b = 0.25; + let diff_light_attenuation = 1.0 / (1.0 + diff_coef_a * light_dist + diff_coef_b * light_dist * light_dist); + let diff_direct_light = light.rgb * light.a * diff_light_attenuation; + + // very rough bounce light estimation + let diffuse_mult = max(surface_light_dot, 0.0); + ambient += diffuse_mult * 0.03 * diff_direct_light; + + return ambient; +} diff --git a/res/shaders/pbr.wgsl b/res/shaders/pbr.wgsl index 56cb5d7..5122337 100644 --- a/res/shaders/pbr.wgsl +++ b/res/shaders/pbr.wgsl @@ -84,23 +84,27 @@ fn fs_main(vert: VertexOutput) -> @location(0) vec4 { var total_radiance: vec3; + let normal_dir = tex_normal.xyz * 2.0 - 1.0; + var light_dir = normalize(vert.tangent_light_position - vert.tangent_position); + let surface_light_dot = dot(normal_dir, light_dir); + let light_dist = length(light.position - vert.world_position.xyz); + + // attenuation + let coef_a = 0.0; + let coef_b = 1.0; + let light_attenuation = 1.0 / (1.0 + coef_a * light_dist + coef_b * light_dist * light_dist); + + let direct_light = light.color.rgb * light.color.a * light_attenuation; + let in_light = sample_direct_light(vert.world_position); if (in_light > 0.0) { // lighting vecs - let normal_dir = tex_normal.xyz * 2.0 - 1.0; - var light_dir = normalize(vert.tangent_light_position - vert.tangent_position); let view_dir = normalize(vert.tangent_view_position - vert.tangent_position); let half_dir = normalize(view_dir + light_dir); - // attenuation - let light_dist = length(light.position - vert.world_position.xyz); - let coef_a = 0.0; - let coef_b = 1.0; - let light_attenuation = 1.0 / (1.0 + coef_a * light_dist + coef_b * light_dist * light_dist); - // radiance - let radiance_strength = max(dot(normal_dir, light_dir), 0.0); - let radiance = radiance_strength * light.color.rgb * light.color.a * light_attenuation * in_light; + let radiance_strength = max(surface_light_dot, 0.0); + let radiance = radiance_strength * direct_light * in_light; // brdf shading total_radiance += radiance * brdf( @@ -114,10 +118,10 @@ fn fs_main(vert: VertexOutput) -> @location(0) vec4 { ); } - // ambient - let ambient_color = PBR_AMBIENT * albedo; + var ambient = sample_ambient_light(light.color, light_dist, surface_light_dot); + ambient *= albedo; - var result = ambient_color + total_radiance; + var result = ambient + total_radiance; // tonemap result = result / (result + vec3(1.0));