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
38 changes: 31 additions & 7 deletions crates/bevy_pbr/src/ssao/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,38 @@ impl Plugin for ScreenSpaceAmbientOcclusionPlugin {
pub struct ScreenSpaceAmbientOcclusion {
/// Quality of the SSAO effect.
pub quality_level: ScreenSpaceAmbientOcclusionQualityLevel,
/// Maximum sample distance, in view-space units.
///
/// Use larger values for broader occlusion. This can increase haloing and noise.
Comment thread
GageHowe marked this conversation as resolved.
/// This value must be greater than `0.0`.
///
/// To disable SSAO, remove [`ScreenSpaceAmbientOcclusion`] from the camera instead.
pub radius: f32,
/// A constant estimated thickness of objects.
///
/// This value is used to decide how far behind an object a ray of light needs to be in order
/// to pass behind it. Any ray closer than that will be occluded.
pub constant_object_thickness: f32,
}

const DEFAULT_SSAO_RADIUS: f32 = 0.5 * 1.457;

impl Default for ScreenSpaceAmbientOcclusion {
fn default() -> Self {
Self {
quality_level: ScreenSpaceAmbientOcclusionQualityLevel::default(),
radius: DEFAULT_SSAO_RADIUS,
constant_object_thickness: 0.25,
}
}
}

#[derive(Clone, Copy, ShaderType)]
struct SsaoSettingsUniform {
radius: f32,
constant_object_thickness: f32,
}

#[derive(Reflect, PartialEq, Eq, Hash, Clone, Copy, Default, Debug)]
#[reflect(PartialEq, Hash, Clone, Default)]
pub enum ScreenSpaceAmbientOcclusionQualityLevel {
Expand Down Expand Up @@ -368,7 +384,7 @@ impl FromWorld for SsaoPipelines {
texture_storage_2d(depth_format, StorageTextureAccess::WriteOnly),
texture_storage_2d(TextureFormat::R32Uint, StorageTextureAccess::WriteOnly),
uniform_buffer::<GlobalsUniform>(false),
uniform_buffer::<f32>(false),
uniform_buffer::<SsaoSettingsUniform>(false),
),
),
);
Expand Down Expand Up @@ -508,7 +524,7 @@ pub struct ScreenSpaceAmbientOcclusionResources {
ssao_noisy_texture: CachedTexture, // Pre-spatially denoised texture
pub screen_space_ambient_occlusion_texture: CachedTexture, // Spatially denoised texture
depth_differences_texture: CachedTexture,
thickness_buffer: Buffer,
settings_buffer: Buffer,
}

fn prepare_ssao_textures(
Expand Down Expand Up @@ -580,9 +596,17 @@ fn prepare_ssao_textures(
},
);

let thickness_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
label: Some("thickness_buffer"),
contents: &ssao_settings.constant_object_thickness.to_le_bytes(),
let mut settings_uniform_buffer = encase::UniformBuffer::new(Vec::new());
settings_uniform_buffer
.write(&SsaoSettingsUniform {
radius: ssao_settings.radius,
constant_object_thickness: ssao_settings.constant_object_thickness,
})
.unwrap();

let settings_buffer = render_device.create_buffer_with_data(&BufferInitDescriptor {
label: Some("ssao_settings_buffer"),
contents: settings_uniform_buffer.as_ref(),
usage: BufferUsages::UNIFORM,
});

Expand All @@ -593,7 +617,7 @@ fn prepare_ssao_textures(
ssao_noisy_texture,
screen_space_ambient_occlusion_texture: ssao_texture,
depth_differences_texture,
thickness_buffer,
settings_buffer,
});
}
}
Expand Down Expand Up @@ -698,7 +722,7 @@ fn prepare_ssao_bind_groups(
&ssao_resources.ssao_noisy_texture.default_view,
&ssao_resources.depth_differences_texture.default_view,
globals_uniforms.clone(),
ssao_resources.thickness_buffer.as_entire_binding(),
ssao_resources.settings_buffer.as_entire_binding(),
)),
);

Expand Down
16 changes: 8 additions & 8 deletions crates/bevy_pbr/src/ssao/ssao.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,11 @@
#endif
@group(0) @binding(4) var depth_differences: texture_storage_2d<r32uint, write>;
@group(0) @binding(5) var<uniform> globals: Globals;
@group(0) @binding(6) var<uniform> thickness: f32;
struct SsaoSettings {
radius: f32,
thickness: f32,
}
@group(0) @binding(6) var<uniform> settings: SsaoSettings;
@group(1) @binding(0) var point_clamp_sampler: sampler;
@group(1) @binding(1) var linear_clamp_sampler: sampler;
@group(1) @binding(2) var<uniform> view: View;
Expand Down Expand Up @@ -116,7 +120,7 @@ fn processSample(
samples_per_slice: f32,
bitmask: ptr<function, u32>,
) {
let delta_position_back_face = delta_position - view_vec * thickness;
let delta_position_back_face = delta_position - view_vec * settings.thickness;

var front_back_horizon = vec2(
fast_acos(dot(normalize(delta_position), view_vec)),
Expand All @@ -134,11 +138,6 @@ fn processSample(
fn ssao(@builtin(global_invocation_id) global_id: vec3<u32>) {
let slice_count = f32(#SLICE_COUNT);
let samples_per_slice_side = f32(#SAMPLES_PER_SLICE_SIDE);
let effect_radius = 0.5 * 1.457;
let falloff_range = 0.615 * effect_radius;
let falloff_from = effect_radius * (1.0 - 0.615);
let falloff_mul = -1.0 / falloff_range;
let falloff_add = falloff_from / falloff_range + 1.0;

let pixel_coordinates = vec2<i32>(global_id.xy);
let uv = (vec2<f32>(pixel_coordinates) + 0.5) / view.viewport.zw;
Expand All @@ -151,7 +150,8 @@ fn ssao(@builtin(global_invocation_id) global_id: vec3<u32>) {
let view_vec = normalize(-pixel_position);

let noise = load_noise(pixel_coordinates);
let sample_scale = (-0.5 * effect_radius * view.clip_from_view[0][0]) / pixel_position.z;
let safe_radius = max(settings.radius, 0.0001);
let sample_scale = (-0.5 * safe_radius * view.clip_from_view[0][0]) / pixel_position.z;

var visibility = 0.0;
var occluded_sample_count = 0u;
Expand Down
18 changes: 18 additions & 0 deletions examples/3d/ssao.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,20 @@ fn update(
..current_ssao
},
|| keycode.just_pressed(KeyCode::ArrowDown),
)
.insert_if(
ScreenSpaceAmbientOcclusion {
radius: (current_ssao.radius * 1.25).min(8.0),
..current_ssao
},
|| keycode.just_pressed(KeyCode::ArrowRight),
)
.insert_if(
ScreenSpaceAmbientOcclusion {
radius: (current_ssao.radius * 0.8).max(0.1),
..current_ssao
},
|| keycode.just_pressed(KeyCode::ArrowLeft),
);
if keycode.just_pressed(KeyCode::Digit1) {
commands.remove::<ScreenSpaceAmbientOcclusion>();
Expand All @@ -174,6 +188,10 @@ fn update(
_ => unreachable!(),
};

if let Some(radius) = ssao.map(|s| s.radius) {
text.push_str(&format!("Radius: {radius} (Left/Right)\n"));
}

if let Some(thickness) = ssao.map(|s| s.constant_object_thickness) {
text.push_str(&format!(
"Constant object thickness: {thickness} (Up/Down)\n\n"
Expand Down
Loading