Skip to content

Commit afae1c0

Browse files
Solari: More reactive world cache (#21810)
Thanks to Guillaume Boissé, the world cache is both more stable in static scenarios, and more reactive in dynamic scenarios! https://bsky.app/profile/gboisse.bsky.social/post/3m5blga3ftk2a Co-authored-by: Alice Cecile <[email protected]>
1 parent 0500409 commit afae1c0

File tree

5 files changed

+40
-8
lines changed

5 files changed

+40
-8
lines changed

crates/bevy_solari/src/realtime/node.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ impl ViewNode for SolariLightingNode {
185185
s.world_cache_life.as_entire_binding(),
186186
s.world_cache_radiance.as_entire_binding(),
187187
s.world_cache_geometry_data.as_entire_binding(),
188+
s.world_cache_luminance_deltas.as_entire_binding(),
188189
s.world_cache_active_cells_new_radiance.as_entire_binding(),
189190
s.world_cache_a.as_entire_binding(),
190191
s.world_cache_b.as_entire_binding(),
@@ -399,6 +400,7 @@ impl FromWorld for SolariLightingNode {
399400
storage_buffer_sized(false, None),
400401
storage_buffer_sized(false, None),
401402
storage_buffer_sized(false, None),
403+
storage_buffer_sized(false, None),
402404
),
403405
),
404406
);

crates/bevy_solari/src/realtime/prepare.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ pub struct SolariLightingResources {
5656
pub world_cache_life: Buffer,
5757
pub world_cache_radiance: Buffer,
5858
pub world_cache_geometry_data: Buffer,
59+
pub world_cache_luminance_deltas: Buffer,
5960
pub world_cache_active_cells_new_radiance: Buffer,
6061
pub world_cache_a: Buffer,
6162
pub world_cache_b: Buffer,
@@ -202,6 +203,13 @@ pub fn prepare_solari_lighting_resources(
202203
mapped_at_creation: false,
203204
});
204205

206+
let world_cache_luminance_deltas = render_device.create_buffer(&BufferDescriptor {
207+
label: Some("solari_lighting_world_cache_luminance_deltas"),
208+
size: WORLD_CACHE_SIZE * size_of::<f32>() as u64,
209+
usage: BufferUsages::STORAGE,
210+
mapped_at_creation: false,
211+
});
212+
205213
let world_cache_active_cells_new_radiance =
206214
render_device.create_buffer(&BufferDescriptor {
207215
label: Some("solari_lighting_world_cache_active_cells_new_radiance"),
@@ -257,6 +265,7 @@ pub fn prepare_solari_lighting_resources(
257265
world_cache_life,
258266
world_cache_radiance,
259267
world_cache_geometry_data,
268+
world_cache_luminance_deltas,
260269
world_cache_active_cells_new_radiance,
261270
world_cache_a,
262271
world_cache_b,

crates/bevy_solari/src/realtime/world_cache_compact.wgsl

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
#import bevy_solari::world_cache::{WORLD_CACHE_EMPTY_CELL, world_cache_life, world_cache_checksums, world_cache_radiance, world_cache_a, world_cache_b, world_cache_active_cell_indices, world_cache_active_cells_count}
1+
#import bevy_solari::world_cache::{
2+
WORLD_CACHE_EMPTY_CELL,
3+
world_cache_life,
4+
world_cache_checksums,
5+
world_cache_radiance,
6+
world_cache_luminance_deltas,
7+
world_cache_a,
8+
world_cache_b,
9+
world_cache_active_cell_indices,
10+
world_cache_active_cells_count,
11+
}
212

313
@group(2) @binding(0) var<storage, read_write> world_cache_active_cells_dispatch: vec3<u32>;
414

@@ -15,6 +25,7 @@ fn decay_world_cache(@builtin(global_invocation_id) global_id: vec3<u32>) {
1525
if life == 0u {
1626
world_cache_checksums[global_id.x] = WORLD_CACHE_EMPTY_CELL;
1727
world_cache_radiance[global_id.x] = vec4(0.0);
28+
world_cache_luminance_deltas[global_id.x] = 0.0;
1829
}
1930
}
2031
}

crates/bevy_solari/src/realtime/world_cache_query.wgsl

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#import bevy_render::maths::orthonormalize
55

66
/// How responsive the world cache is to changes in lighting (higher is less responsive, lower is more responsive)
7-
const WORLD_CACHE_MAX_TEMPORAL_SAMPLES: f32 = 10.0;
7+
const WORLD_CACHE_MAX_TEMPORAL_SAMPLES: f32 = 32.0;
88
/// How many direct light samples each cell takes when updating each frame
99
const WORLD_CACHE_DIRECT_LIGHT_SAMPLE_COUNT: u32 = 32u;
1010
/// Maximum amount of distance to trace GI rays between two cache cells
@@ -38,11 +38,12 @@ struct WorldCacheGeometryData {
3838
#endif
3939
@group(1) @binding(16) var<storage, read_write> world_cache_radiance: array<vec4<f32>, #{WORLD_CACHE_SIZE}>;
4040
@group(1) @binding(17) var<storage, read_write> world_cache_geometry_data: array<WorldCacheGeometryData, #{WORLD_CACHE_SIZE}>;
41-
@group(1) @binding(18) var<storage, read_write> world_cache_active_cells_new_radiance: array<vec3<f32>, #{WORLD_CACHE_SIZE}>;
42-
@group(1) @binding(19) var<storage, read_write> world_cache_a: array<u32, #{WORLD_CACHE_SIZE}>;
43-
@group(1) @binding(20) var<storage, read_write> world_cache_b: array<u32, 1024u>;
44-
@group(1) @binding(21) var<storage, read_write> world_cache_active_cell_indices: array<u32, #{WORLD_CACHE_SIZE}>;
45-
@group(1) @binding(22) var<storage, read_write> world_cache_active_cells_count: u32;
41+
@group(1) @binding(18) var<storage, read_write> world_cache_luminance_deltas: array<f32, #{WORLD_CACHE_SIZE}>;
42+
@group(1) @binding(19) var<storage, read_write> world_cache_active_cells_new_radiance: array<vec3<f32>, #{WORLD_CACHE_SIZE}>;
43+
@group(1) @binding(20) var<storage, read_write> world_cache_a: array<u32, #{WORLD_CACHE_SIZE}>;
44+
@group(1) @binding(21) var<storage, read_write> world_cache_b: array<u32, 1024u>;
45+
@group(1) @binding(22) var<storage, read_write> world_cache_active_cell_indices: array<u32, #{WORLD_CACHE_SIZE}>;
46+
@group(1) @binding(23) var<storage, read_write> world_cache_active_cells_count: u32;
4647

4748
#ifndef WORLD_CACHE_NON_ATOMIC_LIFE_BUFFER
4849
fn query_world_cache(world_position: vec3<f32>, world_normal: vec3<f32>, view_position: vec3<f32>, cell_lifetime: u32, rng: ptr<function, u32>) -> vec3<f32> {

crates/bevy_solari/src/realtime/world_cache_update.wgsl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
world_cache_life,
1515
world_cache_geometry_data,
1616
world_cache_radiance,
17+
world_cache_luminance_deltas,
1718
world_cache_active_cells_new_radiance,
1819
}
1920

@@ -54,11 +55,19 @@ fn blend_new_samples(@builtin(global_invocation_id) active_cell_id: vec3<u32>) {
5455

5556
let old_radiance = world_cache_radiance[cell_index];
5657
let new_radiance = world_cache_active_cells_new_radiance[active_cell_id.x];
58+
let luminance_delta = world_cache_luminance_deltas[cell_index];
59+
60+
// https://bsky.app/profile/gboisse.bsky.social/post/3m5blga3ftk2a
5761
let sample_count = min(old_radiance.a + 1.0, WORLD_CACHE_MAX_TEMPORAL_SAMPLES);
62+
let alpha = abs(luminance_delta) / max(luminance(old_radiance.rgb), 0.001);
63+
let max_sample_count = mix(WORLD_CACHE_MAX_TEMPORAL_SAMPLES, 1.0, pow(saturate(alpha), 1.0 / 8.0));
64+
let blend_amount = 1.0 / min(sample_count, max_sample_count);
5865

59-
let blended_radiance = mix(old_radiance.rgb, new_radiance, 1.0 / sample_count);
66+
let blended_radiance = mix(old_radiance.rgb, new_radiance, blend_amount);
67+
let blended_luminance_delta = mix(luminance_delta, luminance(blended_radiance) - luminance(old_radiance.rgb), 1.0 / 8.0);
6068

6169
world_cache_radiance[cell_index] = vec4(blended_radiance, sample_count);
70+
world_cache_luminance_deltas[cell_index] = blended_luminance_delta;
6271
}
6372
}
6473

0 commit comments

Comments
 (0)