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

Group-local ReSTIR #161

Draft
wants to merge 26 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
a7eea0d
WIP local storage for reservoirs
kvark Aug 19, 2024
aa31733
Work around workgroup memory addressing GPU hang
kvark Aug 20, 2024
32fd30c
Hook up the resampling
kvark Aug 22, 2024
07112f1
Reject spatial samples that are too close
kvark Aug 22, 2024
6eb0bbe
Jitter the ray compute grid
kvark Aug 22, 2024
41e9b6f
Scaling jittering
kvark Aug 23, 2024
8fd67a6
Refine group mixing and visualization
kvark Aug 23, 2024
e625b50
True separation between temporal and spatial resampling
kvark Aug 24, 2024
f872720
Refactor MIS according to GRIS paper
kvark Aug 25, 2024
5573b8e
Fix groups, canonical sampling, refactor MIS
kvark Aug 26, 2024
7e37196
Remove extra reservoirs buffer
kvark Sep 2, 2024
53b9411
Merge G-Buffer pass into the Main
kvark Sep 3, 2024
de0ebd5
Merge temporal accumulation into the Main pass
kvark Sep 3, 2024
ddf0f17
Fix debug modes rendering
kvark Sep 3, 2024
c6a9833
Tweak Grouping debug mode
kvark Sep 4, 2024
07e573e
Search within 2x2 grid for temporal reprojection
kvark Sep 5, 2024
0d662fa
Refactor temporal reprojection out of the temporal pass
kvark Sep 6, 2024
ab1bf33
Use confidence term more widely, include in the RayConfig
kvark Sep 6, 2024
1490f05
Use mouse wheel for fly speed control
kvark Sep 7, 2024
8643a83
Refactor temporal accumulation, add WRITE_DEBUG_IMAGE flag
kvark Sep 7, 2024
d326d6a
Expose pairwise MIS in settings
kvark Sep 7, 2024
28b8123
Tweak spatial re-use settings to avoid misses
kvark Sep 8, 2024
5ec4396
make debug rendering optional
kvark Sep 12, 2024
239e9ca
Move the debug flag and the random gen into private vars
kvark Sep 14, 2024
ceb233c
Refactor MIS to include 1/M and follow a simple balanced heuristic
kvark Sep 18, 2024
8f153f2
Proper defensive MIS
kvark Sep 18, 2024
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 Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ gltf = { version = "1.1", default-features = false }
log = "0.4"
mint = "0.5"
naga = { version = "22", features = ["wgsl-in"] }
nanorand = { version = "0.7", default-features = false }
profiling = "1"
slab = "0.4"
strum = { version = "0.25", features = ["derive"] }
Expand Down Expand Up @@ -79,7 +80,7 @@ glam = { workspace = true }
log = { workspace = true }
mint = { workspace = true, features = ["serde"] }
naga = { workspace = true }
nanorand = { version = "0.7", default-features = false, features = ["wyrand"] }
nanorand = { workspace = true, features = ["wyrand"] }
profiling = { workspace = true }
ron = "0.8"
serde = { version = "1", features = ["serde_derive"] }
Expand All @@ -95,7 +96,6 @@ egui-winit = "0.28"
console_error_panic_hook = "0.1.7"
console_log = "1"
web-sys = { workspace = true, features = ["Window"] }
getrandom = { version = "0.2", features = ["js"] }

[target.'cfg(any(target_os = "windows", target_os = "linux"))'.dev-dependencies]
renderdoc = "0.12"
Expand Down
17 changes: 11 additions & 6 deletions blade-graphics/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,19 @@ impl super::TextureFormat {
}
}

impl super::Extent {
pub fn group_by(&self, size: [u32; 3]) -> [u32; 3] {
[
(self.width + size[0] - 1) / size[0],
(self.height + size[1] - 1) / size[1],
(self.depth + size[2] - 1) / size[2],
]
}
}

impl super::ComputePipeline {
/// Return the dispatch group counts sufficient to cover the given extent.
pub fn get_dispatch_for(&self, extent: super::Extent) -> [u32; 3] {
let wg_size = self.get_workgroup_size();
[
(extent.width + wg_size[0] - 1) / wg_size[0],
(extent.height + wg_size[1] - 1) / wg_size[1],
(extent.depth + wg_size[2] - 1) / wg_size[2],
]
extent.group_by(self.get_workgroup_size())
}
}
12 changes: 11 additions & 1 deletion blade-helpers/src/camera.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use super::ExposeHud;

const MAX_FLY_SPEED: f32 = 1000000.0;

pub struct ControlledCamera {
pub inner: blade_render::Camera,
pub fly_speed: f32,
Expand Down Expand Up @@ -86,6 +88,14 @@ impl ControlledCamera {

true
}

pub fn on_wheel(&mut self, delta: winit::event::MouseScrollDelta) {
let shift = match delta {
winit::event::MouseScrollDelta::LineDelta(_, lines) => lines,
winit::event::MouseScrollDelta::PixelDelta(position) => position.y as f32,
};
self.fly_speed = (self.fly_speed * shift.exp()).clamp(1.0, MAX_FLY_SPEED);
}
}

impl ExposeHud for ControlledCamera {
Expand All @@ -105,7 +115,7 @@ impl ExposeHud for ControlledCamera {
});
ui.add(egui::Slider::new(&mut self.inner.fov_y, 0.5f32..=2.0f32).text("FOV"));
ui.add(
egui::Slider::new(&mut self.fly_speed, 1f32..=100000f32)
egui::Slider::new(&mut self.fly_speed, 1f32..=MAX_FLY_SPEED)
.text("Fly speed")
.logarithmic(true),
);
Expand Down
26 changes: 21 additions & 5 deletions blade-helpers/src/hud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,27 +15,34 @@ impl ExposeHud for blade_render::RayConfig {
);
ui.checkbox(&mut self.temporal_tap, "Temporal tap");
ui.add(
egui::widgets::Slider::new(&mut self.temporal_history, 0..=50).text("Temporal history"),
egui::widgets::Slider::new(&mut self.temporal_confidence, 0.0..=50.0)
.text("Temporal confidence"),
);
ui.add(egui::widgets::Slider::new(&mut self.spatial_taps, 0..=10).text("Spatial taps"));
ui.add(
egui::widgets::Slider::new(&mut self.spatial_tap_history, 0..=50)
.text("Spatial tap history"),
egui::widgets::Slider::new(&mut self.spatial_confidence, 0.0..=50.0)
.text("Spatial confidence"),
);
ui.add(egui::widgets::Slider::new(&mut self.group_mixer, 1..=10).text("Group mixer"));
ui.add(
egui::widgets::Slider::new(&mut self.spatial_radius, 1..=50)
.text("Spatial radius (px)"),
egui::widgets::Slider::new(&mut self.spatial_min_distance, 1..=10)
.text("Spatial minimum distance (px)"),
);
ui.add(
egui::widgets::Slider::new(&mut self.t_start, 0.001..=0.5)
.text("T min")
.logarithmic(true),
);
ui.checkbox(&mut self.pairwise_mis, "Pairwise MIS");
ui.add(
egui::widgets::Slider::new(&mut self.defensive_mis, 0.0..=1.0).text("Defensive MIS"),
);
}
}

impl ExposeHud for blade_render::DenoiserConfig {
fn populate_hud(&mut self, ui: &mut egui::Ui) {
ui.checkbox(&mut self.enabled, "Enable denoiser");
ui.add(egui::Slider::new(&mut self.temporal_weight, 0.0..=1.0f32).text("Temporal weight"));
ui.add(egui::Slider::new(&mut self.num_passes, 0..=5u32).text("A-trous passes"));
}
Expand All @@ -57,6 +64,15 @@ impl ExposeHud for blade_render::PostProcConfig {
}
}

impl ExposeHud for blade_render::FrameConfig {
fn populate_hud(&mut self, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
self.reset_reservoirs |= ui.button("Reset Accumulation").clicked();
ui.toggle_value(&mut self.frozen, "Freeze");
});
}
}

impl ExposeHud for blade_render::DebugConfig {
fn populate_hud(&mut self, ui: &mut egui::Ui) {
use strum::IntoEnumIterator as _;
Expand Down
79 changes: 79 additions & 0 deletions blade-render/code/a-trous.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "quaternion.inc.wgsl"
#include "surface.inc.wgsl"

// Spatio-temporal variance-guided filtering
// https://research.nvidia.com/sites/default/files/pubs/2017-07_Spatiotemporal-Variance-Guided-Filtering%3A//svgf_preprint.pdf

// Note: using "ilm" in place of "illumination and the 2nd moment of its luminance"

struct Params {
extent: vec2<i32>,
iteration: u32,
}

var<uniform> params: Params;
var t_depth: texture_2d<f32>;
var t_flat_normal: texture_2d<f32>;
var input: texture_2d<f32>;
var output: texture_storage_2d<rgba16float, write>;

const LUMA: vec3<f32> = vec3<f32>(0.2126, 0.7152, 0.0722);
const MIN_WEIGHT: f32 = 0.01;

fn read_surface(pixel: vec2<i32>) -> Surface {
var surface = Surface();
surface.flat_normal = normalize(textureLoad(t_flat_normal, pixel, 0).xyz);
surface.depth = textureLoad(t_depth, pixel, 0).x;
return surface;
}

const GAUSSIAN_WEIGHTS = vec2<f32>(0.44198, 0.27901);
const SIGMA_L: f32 = 4.0;
const EPSILON: f32 = 0.001;

fn compare_luminance(a_lum: f32, b_lum: f32, variance: f32) -> f32 {
return exp(-abs(a_lum - b_lum) / (SIGMA_L * variance + EPSILON));
}

fn w4(w: f32) -> vec4<f32> {
return vec4<f32>(vec3<f32>(w), w * w);
}

@compute @workgroup_size(8, 8)
fn atrous3x3(@builtin(global_invocation_id) global_id: vec3<u32>) {
let center = vec2<i32>(global_id.xy);
if (any(center >= params.extent)) {
return;
}

let center_ilm = textureLoad(input, center, 0);
let center_luma = dot(center_ilm.xyz, LUMA);
let variance = sqrt(center_ilm.w);
let center_suf = read_surface(center);
var sum_weight = GAUSSIAN_WEIGHTS[0] * GAUSSIAN_WEIGHTS[0];
var sum_ilm = w4(sum_weight) * center_ilm;

for (var yy=-1; yy<=1; yy+=1) {
for (var xx=-1; xx<=1; xx+=1) {
let p = center + vec2<i32>(xx, yy) * (1i << params.iteration);
if (all(p == center) || any(p < vec2<i32>(0)) || any(p >= params.extent)) {
continue;
}

//TODO: store in group-shared memory
let surface = read_surface(p);
var weight = GAUSSIAN_WEIGHTS[abs(xx)] * GAUSSIAN_WEIGHTS[abs(yy)];
//TODO: make it stricter on higher iterations
weight *= compare_flat_normals(surface.flat_normal, center_suf.flat_normal);
//Note: should we use a projected depth instead of the surface one?
weight *= compare_depths(surface.depth, center_suf.depth);
let other_ilm = textureLoad(input, p, 0);
weight *= compare_luminance(center_luma, dot(other_ilm.xyz, LUMA), variance);
sum_ilm += w4(weight) * other_ilm;
sum_weight += weight;
}
}

let filtered_ilm = select(center_ilm, sum_ilm / w4(sum_weight), sum_weight > MIN_WEIGHT);
textureStore(output, global_id.xy, filtered_ilm);
}
21 changes: 21 additions & 0 deletions blade-render/code/accum.inc.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const LUMA: vec3<f32> = vec3<f32>(0.2126, 0.7152, 0.0722);
const MOTION_FACTOR: f32 = 0.1;

var inout_diffuse: texture_storage_2d<rgba16float, read_write>;

fn accumulate_temporal(
pixel: vec2<i32>, cur_illumination: vec3<f32>,
temporal_weight: f32, prev_pixel: vec2<i32>,
motion_sqr: f32,
) {
var illumination = cur_illumination;
if (prev_pixel.x >= 0 && temporal_weight < 1.0) {
let factor = mix(temporal_weight, 1.0, min(pow(motion_sqr, 0.25) * MOTION_FACTOR, 1.0));
let prev_illumination = textureLoad(inout_diffuse, prev_pixel).xyz;
illumination = mix(prev_illumination, illumination, factor);
}

let luminocity = dot(illumination, LUMA);
let ilm = vec4<f32>(illumination, luminocity * luminocity);
textureStore(inout_diffuse, pixel, ilm);
}
Loading
Loading