From 5497e8d6cefe103dbd8ce0ba6eb0ce7fab6db287 Mon Sep 17 00:00:00 2001 From: nullprop Date: Sat, 11 Nov 2023 16:43:07 +0200 Subject: [PATCH] Add march from fog to light for occlusion --- res/shaders/constants.wgsl | 3 +++ res/shaders/fog.wgsl | 50 ++++++++++++++++++++++++++------------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/res/shaders/constants.wgsl b/res/shaders/constants.wgsl index 5de93ee..d178a5b 100644 --- a/res/shaders/constants.wgsl +++ b/res/shaders/constants.wgsl @@ -7,6 +7,9 @@ const SHADOW_SAMPLES = 2; const INV_SHADOW_SAMPLES = 1.0 / 25.0; const FOG_MAX_STEPS = 30; const FOG_STEP_SIZE = 5.0; +const FOG_LIGHT_MAX_STEPS = 10; +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_BLEND_STEPS = 4; diff --git a/res/shaders/fog.wgsl b/res/shaders/fog.wgsl index e63312d..93eecee 100644 --- a/res/shaders/fog.wgsl +++ b/res/shaders/fog.wgsl @@ -61,27 +61,45 @@ fn fog_noise(pos: vec3) -> f32 { return 0.8 * noise1 + 0.2 * noise2; } -fn ray_march(origin: vec3, direction: vec3, scene_depth: f32) -> vec2 { +fn ray_march(origin: vec3, direction: vec3, max_depth: f32, max_steps: i32, step_size: f32, fog_density: f32) -> vec2 { var density = 0.0; var depth = 0.0; - for (var i = 0; i < FOG_MAX_STEPS; i++) + for (var i = 0; i < max_steps; i++) { + depth += step_size; + if (depth >= max_depth) + { + break; + } let noise = fog_noise(origin + direction * depth); - depth += FOG_STEP_SIZE; let blend = min(f32(i + 1) / f32(FOG_BLEND_STEPS), 1.0); - let contribution = FOG_DENSITY / f32(FOG_MAX_STEPS); + let contribution = fog_density / f32(max_steps); density += blend * noise * contribution; if (density >= 1.0) { density = 1.0; break; } - if (depth >= scene_depth) - { - break; - } } - return vec2(density, depth); + + return vec2(density, depth); +} + +fn ray_march_fog(origin: vec3, direction: vec3, scene_depth: f32) -> vec3 { + // march into the fog volume + let fog_march = ray_march(origin, direction, scene_depth, FOG_MAX_STEPS, FOG_STEP_SIZE, FOG_DENSITY); + let fog_density = fog_march.x; + let fog_depth = fog_march.y; + let fog_end_position = origin + direction * fog_depth; + + // march from fog volume to the light + let fog_to_light = light.position - fog_end_position; + let max_light_dist = length(fog_to_light); + let light_direction = fog_to_light / max_light_dist; + let light_march = ray_march(fog_end_position, light_direction, max_light_dist, FOG_LIGHT_MAX_STEPS, FOG_LIGHT_STEP_SIZE, FOG_LIGHT_DENSITY); + let occlusion = light_march.x; + + return vec3(fog_density, fog_depth, occlusion); } fn depth_to_linear(depth: f32) -> f32 { @@ -93,7 +111,8 @@ fn depth_to_linear(depth: f32) -> f32 { @fragment fn fs_main(vert: FogVertexOutput) -> @location(0) vec4 { - let direction = normalize(vert.world_position.xyz - camera.position.xyz); + let origin = vert.world_position.xyz; + let direction = normalize(origin - camera.position.xyz); let volume_depth = depth_to_linear(vert.clip_position.z); let uv = vert.clip_position.xy / camera.planes.zw; let geometry_depth = depth_to_linear(textureSample(t_geometry_depth, s_geometry_depth, uv)); @@ -103,12 +122,13 @@ fn fs_main(vert: FogVertexOutput) -> @location(0) vec4 { return vec4(0.0); } - let dd = ray_march(vert.world_position.xyz, direction, max_fog_depth); - let fog_density = dd.x; - let fog_depth = dd.y; + let march_result = ray_march_fog(origin, direction, max_fog_depth); + let fog_density = march_result.x; + let fog_depth = march_result.y; + let occlusion = march_result.z; var base_color = vec3(mix(0.5, 0.1, fog_density)); - let ambient_strength = 0.04; + let ambient_strength = 0.05; let ambient_color = base_color * ambient_strength; var radiance = vec3(0.0); @@ -121,7 +141,7 @@ fn fs_main(vert: FogVertexOutput) -> @location(0) vec4 { 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; + radiance = light.color.rgb * light.color.a * light_attenuation * in_light * (1.0 - occlusion); } var result = ambient_color + radiance;