Skip to content
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
2 changes: 1 addition & 1 deletion crates/bevy_anti_alias/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ trace = []
webgl = []
webgpu = []
smaa_luts = ["bevy_image/ktx2", "bevy_image/zstd"]
dlss = ["dep:dlss_wgpu", "dep:uuid", "bevy_render/raw_vulkan_init"]
dlss = ["dep:dlss_wgpu", "dep:uuid", "bevy_render/raw_vulkan_init", "dlss_wgpu/debug_overlay"]
force_disable_dlss = ["dlss_wgpu?/mock"]

[dependencies]
Expand Down
2 changes: 2 additions & 0 deletions crates/bevy_solari/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,7 @@ impl SolariPlugins {
| WgpuFeatures::TEXTURE_BINDING_ARRAY
| WgpuFeatures::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING
| WgpuFeatures::PARTIALLY_BOUND_BINDING_ARRAY
| WgpuFeatures::SHADER_INT64
| WgpuFeatures::SHADER_INT64_ATOMIC_MIN_MAX
}
}
8 changes: 4 additions & 4 deletions crates/bevy_solari/src/pathtracer/pathtracer.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#import bevy_render::maths::PI
#import bevy_render::view::View
#import bevy_solari::brdf::evaluate_brdf
#import bevy_solari::sampling::{sample_random_light, random_light_pdf, sample_ggx_vndf, ggx_vndf_pdf, balance_heuristic, power_heuristic}
#import bevy_solari::sampling::{random_light_contribution, hit_random_light_pdf, sample_ggx_vndf, ggx_vndf_pdf, balance_heuristic, power_heuristic}
#import bevy_solari::scene_bindings::{trace_ray, resolve_ray_hit_full, ResolvedRayHitFull, RAY_T_MIN, RAY_T_MAX}

@group(1) @binding(0) var accumulation_texture: texture_storage_2d<rgba32float, read_write>;
Expand Down Expand Up @@ -40,23 +40,23 @@ fn pathtrace(@builtin(global_invocation_id) global_id: vec3<u32>) {
var p_bounce = 0.0;
var bounce_was_perfect_reflection = true;
var previous_normal = vec3(0.0);
loop {
for (var bounces = 0; bounces < 10; bounces++) {
let ray_hit = trace_ray(ray_origin, ray_direction, ray_t_min, RAY_T_MAX, RAY_FLAG_NONE);
if ray_hit.kind != RAY_QUERY_INTERSECTION_NONE {
let ray_hit = resolve_ray_hit_full(ray_hit);
let wo = -ray_direction;

var mis_weight = 1.0;
if !bounce_was_perfect_reflection {
let p_light = random_light_pdf(ray_hit);
let p_light = hit_random_light_pdf(ray_hit);
mis_weight = power_heuristic(p_bounce, p_light);
}
radiance += mis_weight * throughput * ray_hit.material.emissive;

// Sample direct lighting, but only if the surface is not mirror-like
let is_perfectly_specular = ray_hit.material.roughness < 0.0001 && ray_hit.material.metallic > 0.9999;
if !is_perfectly_specular {
let direct_lighting = sample_random_light(ray_hit.world_position, ray_hit.world_normal, &rng);
let direct_lighting = random_light_contribution(&rng, ray_hit.world_position, ray_hit.world_normal);
let pdf_of_bounce = brdf_pdf(wo, direct_lighting.wi, ray_hit);
mis_weight = power_heuristic(1.0 / direct_lighting.inverse_pdf, pdf_of_bounce);
let direct_lighting_brdf = evaluate_brdf(ray_hit.world_normal, wo, direct_lighting.wi, ray_hit.material);
Expand Down
3 changes: 1 addition & 2 deletions crates/bevy_solari/src/realtime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ pub struct SolariLightingPlugin;

impl Plugin for SolariLightingPlugin {
fn build(&self, app: &mut App) {
load_shader_library!(app, "presample_light_tiles.wgsl");
embedded_asset!(app, "restir_di.wgsl");
embedded_asset!(app, "shade_di.wgsl");
embedded_asset!(app, "restir_gi.wgsl");
load_shader_library!(app, "world_cache_query.wgsl");
embedded_asset!(app, "world_cache_compact.wgsl");
Expand Down
68 changes: 16 additions & 52 deletions crates/bevy_solari/src/realtime/node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{
prepare::{SolariLightingResources, LIGHT_TILE_BLOCKS, WORLD_CACHE_SIZE},
prepare::{SolariLightingResources, WORLD_CACHE_SIZE},
SolariLighting,
};
use crate::scene::RaytracingSceneBindings;
Expand All @@ -15,6 +15,8 @@ use bevy_ecs::{
world::{FromWorld, World},
};
use bevy_image::ToExtents;
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
use bevy_render::render_resource::TextureFormat;
use bevy_render::{
diagnostic::RecordDiagnostics,
render_graph::{NodeRunError, RenderGraphContext, ViewNode},
Expand All @@ -24,7 +26,7 @@ use bevy_render::{
},
BindGroupEntries, BindGroupLayout, BindGroupLayoutEntries, CachedComputePipelineId,
ComputePassDescriptor, ComputePipelineDescriptor, LoadOp, PipelineCache, PushConstantRange,
RenderPassDescriptor, ShaderStages, StorageTextureAccess, TextureFormat, TextureSampleType,
RenderPassDescriptor, ShaderStages, StorageTextureAccess, TextureSampleType,
},
renderer::{RenderContext, RenderDevice},
view::{ViewTarget, ViewUniform, ViewUniformOffset, ViewUniforms},
Expand All @@ -50,9 +52,7 @@ pub struct SolariLightingNode {
compact_world_cache_write_active_cells_pipeline: CachedComputePipelineId,
sample_for_world_cache_pipeline: CachedComputePipelineId,
blend_new_world_cache_samples_pipeline: CachedComputePipelineId,
presample_light_tiles_pipeline: CachedComputePipelineId,
di_initial_and_temporal_pipeline: CachedComputePipelineId,
di_spatial_and_shade_pipeline: CachedComputePipelineId,
di_shade_pipeline: CachedComputePipelineId,
gi_initial_and_temporal_pipeline: CachedComputePipelineId,
gi_spatial_and_shade_pipeline: CachedComputePipelineId,
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
Expand Down Expand Up @@ -115,9 +115,7 @@ impl ViewNode for SolariLightingNode {
Some(compact_world_cache_write_active_cells_pipeline),
Some(sample_for_world_cache_pipeline),
Some(blend_new_world_cache_samples_pipeline),
Some(presample_light_tiles_pipeline),
Some(di_initial_and_temporal_pipeline),
Some(di_spatial_and_shade_pipeline),
Some(di_shade_pipeline),
Some(gi_initial_and_temporal_pipeline),
Some(gi_spatial_and_shade_pipeline),
Some(scene_bindings),
Expand All @@ -134,9 +132,7 @@ impl ViewNode for SolariLightingNode {
.get_compute_pipeline(self.compact_world_cache_write_active_cells_pipeline),
pipeline_cache.get_compute_pipeline(self.sample_for_world_cache_pipeline),
pipeline_cache.get_compute_pipeline(self.blend_new_world_cache_samples_pipeline),
pipeline_cache.get_compute_pipeline(self.presample_light_tiles_pipeline),
pipeline_cache.get_compute_pipeline(self.di_initial_and_temporal_pipeline),
pipeline_cache.get_compute_pipeline(self.di_spatial_and_shade_pipeline),
pipeline_cache.get_compute_pipeline(self.di_shade_pipeline),
pipeline_cache.get_compute_pipeline(self.gi_initial_and_temporal_pipeline),
pipeline_cache.get_compute_pipeline(self.gi_spatial_and_shade_pipeline),
&scene_bindings.bind_group,
Expand Down Expand Up @@ -164,10 +160,6 @@ impl ViewNode for SolariLightingNode {
&self.bind_group_layout,
&BindGroupEntries::sequential((
view_target.view,
s.light_tile_samples.as_entire_binding(),
s.light_tile_resolved_samples.as_entire_binding(),
&s.di_reservoirs_a.1,
&s.di_reservoirs_b.1,
s.gi_reservoirs_a.as_entire_binding(),
s.gi_reservoirs_b.as_entire_binding(),
gbuffer,
Expand All @@ -181,6 +173,8 @@ impl ViewNode for SolariLightingNode {
s.world_cache_life.as_entire_binding(),
s.world_cache_radiance.as_entire_binding(),
s.world_cache_geometry_data.as_entire_binding(),
s.world_cache_light_data.as_entire_binding(),
s.world_cache_light_data_new_lights.as_entire_binding(),
s.world_cache_active_cells_new_radiance.as_entire_binding(),
s.world_cache_a.as_entire_binding(),
s.world_cache_b.as_entire_binding(),
Expand Down Expand Up @@ -251,13 +245,6 @@ impl ViewNode for SolariLightingNode {
pass.dispatch_workgroups(dx, dy, 1);
}

pass.set_pipeline(presample_light_tiles_pipeline);
pass.set_push_constants(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(LIGHT_TILE_BLOCKS as u32, 1, 1);

pass.set_bind_group(2, &bind_group_world_cache_active_cells_dispatch, &[]);

pass.set_pipeline(decay_world_cache_pipeline);
Expand Down Expand Up @@ -290,14 +277,7 @@ impl ViewNode for SolariLightingNode {
0,
);

pass.set_pipeline(di_initial_and_temporal_pipeline);
pass.set_push_constants(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
);
pass.dispatch_workgroups(dx, dy, 1);

pass.set_pipeline(di_spatial_and_shade_pipeline);
pass.set_pipeline(di_shade_pipeline);
pass.set_push_constants(
0,
bytemuck::cast_slice(&[frame_index, solari_lighting.reset as u32]),
Expand Down Expand Up @@ -366,10 +346,6 @@ impl FromWorld for SolariLightingNode {
),
storage_buffer_sized(false, None),
storage_buffer_sized(false, None),
texture_storage_2d(TextureFormat::Rgba32Uint, StorageTextureAccess::ReadWrite),
texture_storage_2d(TextureFormat::Rgba32Uint, StorageTextureAccess::ReadWrite),
storage_buffer_sized(false, None),
storage_buffer_sized(false, None),
texture_2d(TextureSampleType::Uint),
texture_depth_2d(),
texture_2d(TextureSampleType::Float { filterable: true }),
Expand All @@ -386,6 +362,8 @@ impl FromWorld for SolariLightingNode {
storage_buffer_sized(false, None),
storage_buffer_sized(false, None),
storage_buffer_sized(false, None),
storage_buffer_sized(false, None),
storage_buffer_sized(false, None),
),
),
);
Expand Down Expand Up @@ -495,24 +473,10 @@ impl FromWorld for SolariLightingNode {
None,
vec![],
),
presample_light_tiles_pipeline: create_pipeline(
"solari_lighting_presample_light_tiles_pipeline",
"presample_light_tiles",
load_embedded_asset!(world, "presample_light_tiles.wgsl"),
None,
vec![],
),
di_initial_and_temporal_pipeline: create_pipeline(
"solari_lighting_di_initial_and_temporal_pipeline",
"initial_and_temporal",
load_embedded_asset!(world, "restir_di.wgsl"),
None,
vec![],
),
di_spatial_and_shade_pipeline: create_pipeline(
"solari_lighting_di_spatial_and_shade_pipeline",
"spatial_and_shade",
load_embedded_asset!(world, "restir_di.wgsl"),
di_shade_pipeline: create_pipeline(
"solari_lighting_di_shade_pipeline",
"shade",
load_embedded_asset!(world, "shade_di.wgsl"),
None,
vec![],
),
Expand Down
78 changes: 25 additions & 53 deletions crates/bevy_solari/src/realtime/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,28 @@ use bevy_ecs::{
};
use bevy_image::ToExtents;
use bevy_math::UVec2;
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
use bevy_render::texture::CachedTexture;
use bevy_render::{
camera::ExtractedCamera,
render_resource::{
Buffer, BufferDescriptor, BufferUsages, Texture, TextureDescriptor, TextureDimension,
TextureFormat, TextureUsages, TextureView, TextureViewDescriptor,
TextureUsages, TextureView, TextureViewDescriptor,
},
renderer::RenderDevice,
};

/// Size of the `LightSample` shader struct in bytes.
const LIGHT_SAMPLE_STRUCT_SIZE: u64 = 8;

/// Size of the `ResolvedLightSamplePacked` shader struct in bytes.
const RESOLVED_LIGHT_SAMPLE_STRUCT_SIZE: u64 = 24;
#[cfg(all(feature = "dlss", not(feature = "force_disable_dlss")))]
use bevy_render::{render_resource::TextureFormat, texture::CachedTexture};

/// Size of the GI `Reservoir` shader struct in bytes.
const GI_RESERVOIR_STRUCT_SIZE: u64 = 48;

pub const LIGHT_TILE_BLOCKS: u64 = 128;
pub const LIGHT_TILE_SAMPLES_PER_BLOCK: u64 = 1024;
/// Number of lights stored per world cache cell.
const WORLD_CACHE_CELL_LIGHT_COUNT: u64 = 8;

/// Amount of entries in the world cache (must be a power of 2, and >= 2^10)
pub const WORLD_CACHE_SIZE: u64 = 2u64.pow(20);

/// Internal rendering resources used for Solari lighting.
#[derive(Component)]
pub struct SolariLightingResources {
pub light_tile_samples: Buffer,
pub light_tile_resolved_samples: Buffer,
pub di_reservoirs_a: (Texture, TextureView),
pub di_reservoirs_b: (Texture, TextureView),
pub gi_reservoirs_a: Buffer,
pub gi_reservoirs_b: Buffer,
pub previous_gbuffer: (Texture, TextureView),
Expand All @@ -56,6 +45,8 @@ pub struct SolariLightingResources {
pub world_cache_life: Buffer,
pub world_cache_radiance: Buffer,
pub world_cache_geometry_data: Buffer,
pub world_cache_light_data: Buffer,
pub world_cache_light_data_new_lights: Buffer,
pub world_cache_active_cells_new_radiance: Buffer,
pub world_cache_a: Buffer,
pub world_cache_b: Buffer,
Expand Down Expand Up @@ -106,39 +97,6 @@ pub fn prepare_solari_lighting_resources(
continue;
}

let light_tile_samples = render_device.create_buffer(&BufferDescriptor {
label: Some("solari_lighting_light_tile_samples"),
size: LIGHT_TILE_BLOCKS * LIGHT_TILE_SAMPLES_PER_BLOCK * LIGHT_SAMPLE_STRUCT_SIZE,
usage: BufferUsages::STORAGE,
mapped_at_creation: false,
});

let light_tile_resolved_samples = render_device.create_buffer(&BufferDescriptor {
label: Some("solari_lighting_light_tile_resolved_samples"),
size: LIGHT_TILE_BLOCKS
* LIGHT_TILE_SAMPLES_PER_BLOCK
* RESOLVED_LIGHT_SAMPLE_STRUCT_SIZE,
usage: BufferUsages::STORAGE,
mapped_at_creation: false,
});

let di_reservoirs = |name| {
let tex = render_device.create_texture(&TextureDescriptor {
label: Some(name),
size: view_size.to_extents(),
mip_level_count: 1,
sample_count: 1,
dimension: TextureDimension::D2,
format: TextureFormat::Rgba32Uint,
usage: TextureUsages::STORAGE_BINDING,
view_formats: &[],
});
let view = tex.create_view(&TextureViewDescriptor::default());
(tex, view)
};
let di_reservoirs_a = di_reservoirs("solari_lighting_di_reservoirs_a");
let di_reservoirs_b = di_reservoirs("solari_lighting_di_reservoirs_b");

let gi_reservoirs = |name| {
render_device.create_buffer(&BufferDescriptor {
label: Some(name),
Expand Down Expand Up @@ -202,6 +160,22 @@ pub fn prepare_solari_lighting_resources(
mapped_at_creation: false,
});

let world_cache_light_data = render_device.create_buffer(&BufferDescriptor {
label: Some("solari_lighting_world_cache_light_data"),
size: WORLD_CACHE_SIZE
* size_of::<[u64; 1 + WORLD_CACHE_CELL_LIGHT_COUNT as usize]>() as u64,
usage: BufferUsages::STORAGE,
mapped_at_creation: false,
});

let world_cache_light_data_new_lights = render_device.create_buffer(&BufferDescriptor {
label: Some("solari_lighting_world_cache_light_data_new_lights"),
size: WORLD_CACHE_SIZE
* size_of::<[u64; 1 + WORLD_CACHE_CELL_LIGHT_COUNT as usize]>() as u64,
usage: BufferUsages::STORAGE,
mapped_at_creation: false,
});

let world_cache_active_cells_new_radiance =
render_device.create_buffer(&BufferDescriptor {
label: Some("solari_lighting_world_cache_active_cells_new_irradiance"),
Expand Down Expand Up @@ -245,10 +219,6 @@ pub fn prepare_solari_lighting_resources(
});

commands.entity(entity).insert(SolariLightingResources {
light_tile_samples,
light_tile_resolved_samples,
di_reservoirs_a,
di_reservoirs_b,
gi_reservoirs_a,
gi_reservoirs_b,
previous_gbuffer: (previous_gbuffer, previous_gbuffer_view),
Expand All @@ -257,6 +227,8 @@ pub fn prepare_solari_lighting_resources(
world_cache_life,
world_cache_radiance,
world_cache_geometry_data,
world_cache_light_data,
world_cache_light_data_new_lights,
world_cache_active_cells_new_radiance,
world_cache_a,
world_cache_b,
Expand Down
Loading
Loading