diff --git a/README.md b/README.md index 6f6bc55..da77296 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ Controls: - PBS - glTF models - 1 realtime pointlight +- Shadow mapping +- Soft shadows - Simple wgsl preprocessor for includes - Runs on WASM and native desktop - Tested on: @@ -27,7 +29,6 @@ Controls: - `Chrome 109.0.5414.120` TODO: -- Shadow mapping - Transparency - Restructuring - Simplify/abstract renderpasses; will be nice to have for PP and GI diff --git a/res/shaders/constants.wgsl b/res/shaders/constants.wgsl index 4be90be..ad50ca7 100644 --- a/res/shaders/constants.wgsl +++ b/res/shaders/constants.wgsl @@ -1,3 +1,6 @@ const PI = 3.14159; const INV_SQRT_2 = 0.70710678118654752440; // 1 / sqrt(2) -const INV_SQRT_3 = 0.57735026918962576451; // 1 / sqrt(3) \ No newline at end of file +const INV_SQRT_3 = 0.57735026918962576451; // 1 / sqrt(3) +const SHADOW_SAMPLES = 8; +const INV_SHADOW_SAMPLES = 1.0 / 8.0; +const SHADOW_SAMPLE_DIST = 0.001; diff --git a/res/shaders/pbr.wgsl b/res/shaders/pbr.wgsl index fb8393e..7ebb29b 100644 --- a/res/shaders/pbr.wgsl +++ b/res/shaders/pbr.wgsl @@ -74,14 +74,29 @@ fn sample_direct_light(index: i32, light_coords: vec4) -> f32 { let flip_correction = vec2(0.5, -0.5); let proj_correction = 1.0 / light_coords.w; let light_local = light_coords.xy * flip_correction * proj_correction + vec2(0.5, 0.5); + let reference_depth = light_coords.z * proj_correction; - return textureSampleCompareLevel( - t_light_depth, - s_light_depth, - light_local, - index, - light_coords.z * proj_correction - ); + var total_sample = 0.0; + for (var i: i32 = 0; i < SHADOW_SAMPLES; i++) { + let phase = i % 4; + var offset = vec2(f32(i / 4) * SHADOW_SAMPLE_DIST); + if (phase == 1 || phase == 3) { + offset.x = -offset.x; + } + if (phase == 2 || phase == 3) { + offset.y = -offset.y; + } + let s = textureSampleCompareLevel( + t_light_depth, + s_light_depth, + light_local + offset, + index, + reference_depth + ); + total_sample += s * INV_SHADOW_SAMPLES; + } + + return total_sample; } @fragment @@ -118,6 +133,8 @@ fn fs_main(vert: VertexOutput) -> @location(0) vec4 { } in_light = sample_direct_light(i, light_coords); + // TODO should break even if 0 since we're inside frustum. + // See if causes issues with bias overlap between directions. if (in_light > 0.0) { break; } @@ -138,7 +155,7 @@ fn fs_main(vert: VertexOutput) -> @location(0) vec4 { // radiance let radiance_strength = max(dot(normal_dir, light_dir), 0.0); - let radiance = radiance_strength * light.color.xyz * light.color.w * light_attenuation; + let radiance = radiance_strength * light.color.xyz * light.color.w * light_attenuation * in_light; // brdf shading total_radiance += radiance * brdf(