Use unscrambled Van der Corput for sampling time dimension.

This gives notably better results at powers of two.

Also experimenting with Halton bases 3 and 4 for DoF.
This commit is contained in:
Nathan Vegdahl 2022-08-16 23:38:52 -07:00
parent 76781eb639
commit aba177c536

View File

@ -232,16 +232,22 @@ impl<'a> Renderer<'a> {
// to work well with golden-ratio sampling. Since we only use sobol // to work well with golden-ratio sampling. Since we only use sobol
// and golden ratio sampling, we do this up-front here rather than in // and golden ratio sampling, we do this up-front here rather than in
// the samplers themselves. // the samplers themselves.
let si_offset = let pixel_offset = owen4_fast(morton::encode(x, y), self.seed);
owen4_fast(morton::encode(x, y), self.seed).wrapping_mul(self.spp as u32); let si_offset = pixel_offset.wrapping_mul(self.spp as u32);
for si in 0..(self.spp as u32) { for si in 0..(self.spp as u32) {
let mut sample_gen = SampleGen::new(si_offset + si, self.seed); let sii = si_offset.wrapping_add(si);
let mut sample_gen = SampleGen::new(sii, self.seed);
// Raw sample numbers. // Raw sample numbers.
let d0 = golden_ratio_sample(si.wrapping_add(si_offset)); let d0 = golden_ratio_sample(
let [d1, d2, d3, _] = sample_gen.next_dims(); sii.wrapping_add(rrand::mix32_seed(self.seed, 1111)),
sample_gen.inc_padding(); );
let d1 = van_der_corput(sii, rrand::mix32_seed(self.seed, 2222));
let d2 = halton_3(sii, rrand::mix32_seed(self.seed, 3333));
let d3 = halton_5(sii, rrand::mix32_seed(self.seed, 4444));
// let [d2, d3, _, _] = sample_gen.next_dims();
// sample_gen.inc_padding();
let [d4, d5, _, _] = sample_gen.next_dims(); let [d4, d5, _, _] = sample_gen.next_dims();
sample_gen.inc_padding(); sample_gen.inc_padding();
@ -584,7 +590,92 @@ impl SampleGen {
} }
} }
/// Golden ratio sampler. /// The Van der Corput sequence.
///
/// NOTE: use this for motion blur, because the jittering introduced by
/// Owen Scrambling in the main sampler actually causes banding artifacts
/// at the sample cell borders, and actually *increases* noise.
fn van_der_corput(i: u32, seed: u32) -> f32 {
use sobol_burley::parts::u32_to_f32_norm;
u32_to_f32_norm(i.reverse_bits().wrapping_add(seed))
}
/// Halton base 3.
fn halton_3(mut i: u32, seed: u32) -> f32 {
const BASE: u32 = 3;
const POW: u32 = 13;
const TOP_BASE: u32 = {
let mut b = 1;
let mut i = 0;
while i < POW {
b *= BASE;
i += 1;
}
b
};
let mut result = 0;
for _ in 0..POW {
result *= BASE;
let next = i / BASE;
result += i - (next * BASE);
i = next;
}
result = ((result as u64 + seed as u64) % TOP_BASE as u64) as u32;
result as f32 * (1.0 / TOP_BASE as f32)
}
/// Halton base 5.
fn halton_5(mut i: u32, seed: u32) -> f32 {
const BASE: u32 = 5;
const POW: u32 = 13;
const TOP_BASE: u32 = {
let mut b = 1;
let mut i = 0;
while i < POW {
b *= BASE;
i += 1;
}
b
};
const ORDER: [u32; 5] = [0, 3, 1, 4, 2];
let mut result = 0;
for _ in 0..POW {
result *= BASE;
let next = i / BASE;
result += ORDER[(i - (next * BASE)) as usize];
i = next;
}
result = ((result as u64 + seed as u64) % TOP_BASE as u64) as u32;
result as f32 * (1.0 / TOP_BASE as f32)
}
// fn next_power_of_three(mut n: u64) -> u64 {
// n = n.saturating_sub(1);
// let mut i = 1;
// while n > 0 {
// n /= 3;
// i *= 3;
// }
// i
// }
// fn next_power_of_five(mut n: u64) -> u64 {
// n = n.saturating_sub(1);
// let mut i = 1;
// while n > 0 {
// n /= 5;
// i *= 5;
// }
// i
// }
/// The golden ratio sequence.
/// ///
// NOTE: use this for the wavelength dimension, because // NOTE: use this for the wavelength dimension, because
// due to the nature of hero wavelength sampling this ends up // due to the nature of hero wavelength sampling this ends up