Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/bevy_pbr/src/ssr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ impl SpecializedRenderPipeline for ScreenSpaceReflectionsPipeline {
shader_defs.push("ATMOSPHERE".into());
}

#[cfg(not(target_arch = "wasm32"))]
shader_defs.push("USE_DEPTH_SAMPLERS".into());

RenderPipelineDescriptor {
label: Some("SSR pipeline".into()),
layout,
Expand Down
55 changes: 51 additions & 4 deletions crates/bevy_pbr/src/ssr/raymarch.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,60 @@
position_world_to_ndc,
}

#ifdef USE_DEPTH_SAMPLERS
// Allows us to sample from the depth buffer with bilinear filtering.
@group(2) @binding(2) var depth_linear_sampler: sampler;

// Allows us to sample from the depth buffer with nearest-neighbor filtering.
@group(2) @binding(3) var depth_nearest_sampler: sampler;
#endif

// Manual depth fetch helpers used on WebGPU where depth + filtering sampler is invalid.
#ifndef USE_DEPTH_SAMPLERS
fn depth_texel_clamped(texel: vec2<i32>) -> f32 {
let dims = textureDimensions(depth_prepass_texture);
let max_coord = vec2<i32>(i32(dims.x) - 1, i32(dims.y) - 1);
let clamped = clamp(texel, vec2<i32>(0), max_coord);
return textureLoad(depth_prepass_texture, clamped, 0);
}

fn depth_sample_nearest_clamped(uv: vec2<f32>, tex_size: vec2<f32>) -> f32 {
// Match nearest sampling by snapping to the closest texel center.
let coord = uv * tex_size - vec2(0.5);
return depth_texel_clamped(vec2<i32>(floor(coord + vec2(0.5))));
}

fn depth_sample_bilinear_clamped(uv: vec2<f32>, tex_size: vec2<f32>) -> f32 {
let coord = uv * tex_size - vec2(0.5);
let base = vec2<i32>(floor(coord));
let frac = coord - floor(coord);

let d00 = depth_texel_clamped(base);
let d10 = depth_texel_clamped(base + vec2(1, 0));
let d01 = depth_texel_clamped(base + vec2(0, 1));
let d11 = depth_texel_clamped(base + vec2(1, 1));

let d0 = mix(d00, d10, frac.x);
let d1 = mix(d01, d11, frac.x);
return mix(d0, d1, frac.y);
}
#endif

fn depth_sample_linear(uv: vec2<f32>, tex_size: vec2<f32>) -> f32 {
#ifdef USE_DEPTH_SAMPLERS
return textureSampleLevel(depth_prepass_texture, depth_linear_sampler, uv, 0u);
#else
return depth_sample_bilinear_clamped(uv, tex_size);
#endif
}

fn depth_sample_nearest(uv: vec2<f32>, tex_size: vec2<f32>) -> f32 {
#ifdef USE_DEPTH_SAMPLERS
return textureSampleLevel(depth_prepass_texture, depth_nearest_sampler, uv, 0u);
#else
return depth_sample_nearest_clamped(uv, tex_size);
#endif
}

// Main code

Expand Down Expand Up @@ -241,10 +290,8 @@ fn depth_raymarch_distance_fn_evaluate(
// * The false occlusions due to duplo land are rejected because the ray stays above the smooth surface.
// * The shrink-wrap surface is no longer continuous, so it's possible for rays to miss it.

let linear_depth =
1.0 / textureSampleLevel(depth_prepass_texture, depth_linear_sampler, interp_uv, 0u);
let unfiltered_depth =
1.0 / textureSampleLevel(depth_prepass_texture, depth_nearest_sampler, interp_uv, 0u);
let linear_depth = 1.0 / depth_sample_linear(interp_uv, (*distance_fn).depth_tex_size);
let unfiltered_depth = 1.0 / depth_sample_nearest(interp_uv, (*distance_fn).depth_tex_size);

var max_depth: f32;
var min_depth: f32;
Expand Down