Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added visibility bitmask as an alternative SSAO method #13454

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/deferred/deferred_lighting.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
#import bevy_pbr::mesh_view_bindings::screen_space_ambient_occlusion_texture
#import bevy_pbr::gtao_utils::gtao_multibounce
#import bevy_pbr::gtao_utils::ssao_multibounce
#endif

struct FullscreenVertexOutput {
Expand Down Expand Up @@ -64,7 +64,7 @@ fn fragment(in: FullscreenVertexOutput) -> @location(0) vec4<f32> {

#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
let ssao_multibounce = gtao_multibounce(ssao, pbr_input.material.base_color.rgb);
let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
pbr_input.diffuse_occlusion = min(pbr_input.diffuse_occlusion, ssao_multibounce);

// Neubelt and Pettineo 2013, "Crafting a Next-gen Material Pipeline for The Order: 1886"
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_pbr/src/render/pbr_fragment.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
#import bevy_pbr::mesh_view_bindings::screen_space_ambient_occlusion_texture
#import bevy_pbr::gtao_utils::gtao_multibounce
#import bevy_pbr::gtao_utils::ssao_multibounce
#endif

#ifdef MESHLET_MESH_MATERIAL_PASS
Expand Down Expand Up @@ -339,7 +339,7 @@ fn pbr_input_from_standard_material(
#endif
#ifdef SCREEN_SPACE_AMBIENT_OCCLUSION
let ssao = textureLoad(screen_space_ambient_occlusion_texture, vec2<i32>(in.position.xy), 0i).r;
let ssao_multibounce = gtao_multibounce(ssao, pbr_input.material.base_color.rgb);
let ssao_multibounce = ssao_multibounce(ssao, pbr_input.material.base_color.rgb);
diffuse_occlusion = min(diffuse_occlusion, ssao_multibounce);
// Use SSAO to estimate the specular occlusion.
// Lagarde and Rousiers 2014, "Moving Frostbite to Physically Based Rendering"
Expand Down
132 changes: 104 additions & 28 deletions crates/bevy_pbr/src/ssao/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ use bevy_utils::{
prelude::default,
tracing::{error, warn},
};
use std::mem;
use std::{hash, mem};

const PREPROCESS_DEPTH_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(102258915420479);
const GTAO_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(253938746510568);
const SSAO_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(253938746510568);
const SPATIAL_DENOISE_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(466162052558226);
const GTAO_UTILS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(366465052568786);
const SSAO_UTILS_SHADER_HANDLE: Handle<Shader> = Handle::weak_from_u128(366465052568786);

/// Plugin for screen space ambient occlusion.
pub struct ScreenSpaceAmbientOcclusionPlugin;
Expand All @@ -54,7 +54,7 @@ impl Plugin for ScreenSpaceAmbientOcclusionPlugin {
"preprocess_depth.wgsl",
Shader::from_wgsl
);
load_internal_asset!(app, GTAO_SHADER_HANDLE, "gtao.wgsl", Shader::from_wgsl);
load_internal_asset!(app, SSAO_SHADER_HANDLE, "ssao.wgsl", Shader::from_wgsl);
load_internal_asset!(
app,
SPATIAL_DENOISE_SHADER_HANDLE,
Expand All @@ -63,8 +63,8 @@ impl Plugin for ScreenSpaceAmbientOcclusionPlugin {
);
load_internal_asset!(
app,
GTAO_UTILS_SHADER_HANDLE,
"gtao_utils.wgsl",
SSAO_UTILS_SHADER_HANDLE,
"ssao_utils.wgsl",
Shader::from_wgsl
);

Expand Down Expand Up @@ -157,6 +157,7 @@ pub struct ScreenSpaceAmbientOcclusionBundle {
#[reflect(Component)]
pub struct ScreenSpaceAmbientOcclusionSettings {
pub quality_level: ScreenSpaceAmbientOcclusionQualityLevel,
pub method: ScreenSpaceAmbientOcclusionMethod,
}

#[derive(Reflect, PartialEq, Eq, Hash, Clone, Copy, Default, Debug)]
Expand Down Expand Up @@ -189,6 +190,49 @@ impl ScreenSpaceAmbientOcclusionQualityLevel {
}
}

#[derive(Reflect, Clone, Copy, Debug)]
pub enum ScreenSpaceAmbientOcclusionMethod {
Gtao,
Vbao { thickness: f32 },
}

impl Default for ScreenSpaceAmbientOcclusionMethod {
fn default() -> Self {
Self::Vbao { thickness: 0.25 }
}
}

impl Eq for ScreenSpaceAmbientOcclusionMethod {}

impl PartialEq for ScreenSpaceAmbientOcclusionMethod {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Gtao, Self::Gtao) => true,
(
Self::Vbao {
thickness: self_thickess,
},
Self::Vbao {
thickness: other_thickness,
},
) => self_thickess == other_thickness,
_ => false,
}
}
}

impl hash::Hash for ScreenSpaceAmbientOcclusionMethod {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
core::mem::discriminant(self).hash(state);

if let Self::Vbao { thickness } = self {
if thickness.is_finite() {
thickness.to_bits().hash(state);
}
}
}
}

#[derive(Default)]
struct SsaoNode {}

Expand All @@ -213,7 +257,7 @@ impl ViewNode for SsaoNode {
Some(camera_size),
Some(preprocess_depth_pipeline),
Some(spatial_denoise_pipeline),
Some(gtao_pipeline),
Some(ssao_pipeline),
) = (
camera.physical_viewport_size,
pipeline_cache.get_compute_pipeline(pipelines.preprocess_depth_pipeline),
Expand Down Expand Up @@ -249,21 +293,21 @@ impl ViewNode for SsaoNode {
}

{
let mut gtao_pass =
let mut ssao_pass =
render_context
.command_encoder()
.begin_compute_pass(&ComputePassDescriptor {
label: Some("ssao_gtao_pass"),
label: Some("ssao_ssao_pass"),
timestamp_writes: None,
});
gtao_pass.set_pipeline(gtao_pipeline);
gtao_pass.set_bind_group(0, &bind_groups.gtao_bind_group, &[]);
gtao_pass.set_bind_group(
ssao_pass.set_pipeline(ssao_pipeline);
ssao_pass.set_bind_group(0, &bind_groups.ssao_bind_group, &[]);
ssao_pass.set_bind_group(
1,
&bind_groups.common_bind_group,
&[view_uniform_offset.offset],
);
gtao_pass.dispatch_workgroups(
ssao_pass.dispatch_workgroups(
div_ceil(camera_size.x, 8),
div_ceil(camera_size.y, 8),
1,
Expand Down Expand Up @@ -304,11 +348,12 @@ struct SsaoPipelines {

common_bind_group_layout: BindGroupLayout,
preprocess_depth_bind_group_layout: BindGroupLayout,
gtao_bind_group_layout: BindGroupLayout,
ssao_bind_group_layout: BindGroupLayout,
spatial_denoise_bind_group_layout: BindGroupLayout,

hilbert_index_lut: TextureView,
point_clamp_sampler: Sampler,
linear_point_clamp_sampler: Sampler,
}

impl FromWorld for SsaoPipelines {
Expand Down Expand Up @@ -347,13 +392,22 @@ impl FromWorld for SsaoPipelines {
address_mode_v: AddressMode::ClampToEdge,
..Default::default()
});
let linear_point_clamp_sampler = render_device.create_sampler(&SamplerDescriptor {
min_filter: FilterMode::Linear,
mag_filter: FilterMode::Linear,
mipmap_filter: FilterMode::Nearest,
address_mode_u: AddressMode::ClampToEdge,
address_mode_v: AddressMode::ClampToEdge,
..Default::default()
});

let common_bind_group_layout = render_device.create_bind_group_layout(
"ssao_common_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::COMPUTE,
(
sampler(SamplerBindingType::NonFiltering),
sampler(SamplerBindingType::Filtering),
uniform_buffer::<ViewUniform>(true),
),
),
Expand All @@ -374,12 +428,12 @@ impl FromWorld for SsaoPipelines {
),
);

let gtao_bind_group_layout = render_device.create_bind_group_layout(
"ssao_gtao_bind_group_layout",
let ssao_bind_group_layout = render_device.create_bind_group_layout(
"ssao_ssao_bind_group_layout",
&BindGroupLayoutEntries::sequential(
ShaderStages::COMPUTE,
(
texture_2d(TextureSampleType::Float { filterable: false }),
texture_2d(TextureSampleType::Float { filterable: true }),
texture_2d(TextureSampleType::Float { filterable: false }),
texture_2d(TextureSampleType::Uint),
texture_storage_2d(TextureFormat::R16Float, StorageTextureAccess::WriteOnly),
Expand Down Expand Up @@ -433,11 +487,12 @@ impl FromWorld for SsaoPipelines {

common_bind_group_layout,
preprocess_depth_bind_group_layout,
gtao_bind_group_layout,
ssao_bind_group_layout,
spatial_denoise_bind_group_layout,

hilbert_index_lut,
point_clamp_sampler,
linear_point_clamp_sampler,
}
}
}
Expand All @@ -460,22 +515,39 @@ impl SpecializedComputePipeline for SsaoPipelines {
"SAMPLES_PER_SLICE_SIDE".to_string(),
samples_per_slice_side as i32,
),
ShaderDefVal::UInt(
"METHOD".to_string(),
match key.ssao_settings.method {
ScreenSpaceAmbientOcclusionMethod::Gtao => 0,
ScreenSpaceAmbientOcclusionMethod::Vbao { .. } => 1,
},
),
ShaderDefVal::UInt(
"THICKNESS".to_string(),
if let ScreenSpaceAmbientOcclusionMethod::Vbao { thickness } =
key.ssao_settings.method
{
thickness.to_bits()
} else {
0
},
),
];

if key.temporal_jitter {
dragostis marked this conversation as resolved.
Show resolved Hide resolved
shader_defs.push("TEMPORAL_JITTER".into());
}

ComputePipelineDescriptor {
label: Some("ssao_gtao_pipeline".into()),
label: Some("ssao_ssao_pipeline".into()),
layout: vec![
self.gtao_bind_group_layout.clone(),
self.ssao_bind_group_layout.clone(),
self.common_bind_group_layout.clone(),
],
push_constant_ranges: vec![],
shader: GTAO_SHADER_HANDLE,
shader: SSAO_SHADER_HANDLE,
shader_defs,
entry_point: "gtao".into(),
entry_point: "ssao".into(),
}
}
}
Expand Down Expand Up @@ -628,7 +700,7 @@ fn prepare_ssao_pipelines(
struct SsaoBindGroups {
common_bind_group: BindGroup,
preprocess_depth_bind_group: BindGroup,
gtao_bind_group: BindGroup,
ssao_bind_group: BindGroup,
spatial_denoise_bind_group: BindGroup,
}

Expand All @@ -655,7 +727,11 @@ fn prepare_ssao_bind_groups(
let common_bind_group = render_device.create_bind_group(
"ssao_common_bind_group",
&pipelines.common_bind_group_layout,
&BindGroupEntries::sequential((&pipelines.point_clamp_sampler, view_uniforms.clone())),
&BindGroupEntries::sequential((
&pipelines.point_clamp_sampler,
&pipelines.linear_point_clamp_sampler,
view_uniforms.clone(),
)),
);

let create_depth_view = |mip_level| {
Expand Down Expand Up @@ -685,9 +761,9 @@ fn prepare_ssao_bind_groups(
)),
);

let gtao_bind_group = render_device.create_bind_group(
"ssao_gtao_bind_group",
&pipelines.gtao_bind_group_layout,
let ssao_bind_group = render_device.create_bind_group(
"ssao_ssao_bind_group",
&pipelines.ssao_bind_group_layout,
&BindGroupEntries::sequential((
&ssao_textures.preprocessed_depth_texture.default_view,
prepass_textures.normal_view().unwrap(),
Expand All @@ -713,7 +789,7 @@ fn prepare_ssao_bind_groups(
commands.entity(entity).insert(SsaoBindGroups {
common_bind_group,
preprocess_depth_bind_group,
gtao_bind_group,
ssao_bind_group,
spatial_denoise_bind_group,
});
}
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_pbr/src/ssao/preprocess_depth.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
@group(0) @binding(4) var preprocessed_depth_mip3: texture_storage_2d<r16float, write>;
@group(0) @binding(5) var preprocessed_depth_mip4: texture_storage_2d<r16float, write>;
@group(1) @binding(0) var point_clamp_sampler: sampler;
@group(1) @binding(1) var<uniform> view: View;
@group(1) @binding(1) var linear_point_clamp_sampler: sampler;
@group(1) @binding(2) var<uniform> view: View;


// Using 4 depths from the previous MIP, compute a weighted average for the depth of the current MIP
Expand Down
3 changes: 2 additions & 1 deletion crates/bevy_pbr/src/ssao/spatial_denoise.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
@group(0) @binding(1) var depth_differences: texture_2d<u32>;
@group(0) @binding(2) var ambient_occlusion: texture_storage_2d<r16float, write>;
@group(1) @binding(0) var point_clamp_sampler: sampler;
@group(1) @binding(1) var<uniform> view: View;
@group(1) @binding(1) var linear_point_clamp_sampler: sampler;
@group(1) @binding(2) var<uniform> view: View;

@compute
@workgroup_size(8, 8, 1)
Expand Down
Loading