From 1e83ea211055eb234b89c69b5d03602e3fcb98fb Mon Sep 17 00:00:00 2001 From: Julian T Date: Fri, 5 Feb 2021 20:17:20 +0100 Subject: Achieve anti aliasing with multi pixel sampling --- Cargo.lock | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/camera/film.rs | 6 ++--- src/core/spectrum.rs | 12 +++++++++ src/core/vector2.rs | 4 +-- src/lib.rs | 1 + src/main.rs | 7 +++-- src/render.rs | 23 +++++++++------- src/sample/mod.rs | 11 ++++++++ src/sample/uniform.rs | 32 ++++++++++++++++++++++ 10 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 src/sample/mod.rs create mode 100644 src/sample/uniform.rs diff --git a/Cargo.lock b/Cargo.lock index a6626c8..b0a6179 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,17 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gif" version = "0.11.1" @@ -268,6 +279,8 @@ name = "pathtrace" version = "0.1.0" dependencies = [ "image", + "rand", + "rand_pcg", ] [[package]] @@ -282,6 +295,61 @@ dependencies = [ "miniz_oxide 0.3.7", ] +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_pcg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de198537002b913568a3847e53535ace266f93526caf5c360ec41d72c5787f0" +dependencies = [ + "rand_core", +] + [[package]] name = "rayon" version = "1.5.0" @@ -330,6 +398,12 @@ dependencies = [ "weezl", ] +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "weezl" version = "0.1.4" diff --git a/Cargo.toml b/Cargo.toml index 63e31c6..f1d384d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,5 @@ edition = "2018" [dependencies] image = "0.23.12" +rand = "0.8.3" +rand_pcg = "0.3.0" diff --git a/src/camera/film.rs b/src/camera/film.rs index 3586374..7193e1d 100644 --- a/src/camera/film.rs +++ b/src/camera/film.rs @@ -45,7 +45,7 @@ impl Pixel { } fn finalize_rgb(&self) -> [u8; 3] { - let (r, g, b) = self.rgb.to_rgb(255.0); + let (r, g, b) = (&self.rgb / (self.samples as Float)).to_rgb(255.0); [ r as u8, g as u8, @@ -128,8 +128,8 @@ impl FilmTile { } /// Add a single sample sampled from the scene - pub fn add_sample(&mut self, point: &Vector2f, c: Spectrum) { - let point = Vector2i::from(point.floor()); + pub fn add_sample(&mut self, inp: &Vector2f, c: Spectrum) { + let point = Vector2i::from(inp.floor()); // Subtract the offset let point = point - self.bounds.min; diff --git a/src/core/spectrum.rs b/src/core/spectrum.rs index fb82a9e..41b3342 100644 --- a/src/core/spectrum.rs +++ b/src/core/spectrum.rs @@ -33,6 +33,18 @@ impl std::ops::Mul for &Spectrum { } } +impl std::ops::Div for &Spectrum { + type Output = Spectrum; + + fn div(self, op: Float) -> Self::Output { + Self::Output::new_rgb( + self.c[0] / op, + self.c[1] / op, + self.c[2] / op, + ) + } +} + impl std::ops::AddAssign<&Self> for Spectrum { fn add_assign(&mut self, op: &Self) { self.c[0] += op.c[0]; diff --git a/src/core/vector2.rs b/src/core/vector2.rs index 3aadb46..858068e 100644 --- a/src/core/vector2.rs +++ b/src/core/vector2.rs @@ -60,8 +60,8 @@ impl Vector2f { pub fn floor(&self) -> Self { Self::new_xy( - self.x.ceil(), - self.y.ceil() + self.x.floor(), + self.y.floor() ) } } diff --git a/src/lib.rs b/src/lib.rs index 555bd89..5883167 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod camera; pub mod render; pub mod scene; pub mod trace; +pub mod sample; use std::ops::{Add, Sub, Mul, DivAssign}; use std::cmp; diff --git a/src/main.rs b/src/main.rs index 9985a80..c1383ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use pathtrace::trace::Tracer; use pathtrace::scene::shapes::Sphere; use pathtrace::core::{Vector2i, Vector3f}; use pathtrace::render::{RenderContext, RenderTask}; +use pathtrace::sample::UniformSampler; fn main() { let res = Vector2i::new_xy(500, 500); @@ -22,13 +23,15 @@ fn main() { let tracer = Tracer::new(); + let mut sampler = UniformSampler::new(); + let ctx = RenderContext { cam: &cam, scn: &scn, trc: &tracer }; let mut film = Film::new(res); let tile = film.get_tile(&film.frame); - let mut task = RenderTask::new(Box::new(tile), 1); - task.render(&ctx); + let mut task = RenderTask::new(Box::new(tile), 500); + task.render(&ctx, &mut sampler); film.commit_tile(&task.tile); diff --git a/src/render.rs b/src/render.rs index 7d05aba..c8a75da 100644 --- a/src/render.rs +++ b/src/render.rs @@ -5,8 +5,9 @@ use crate::camera::film::FilmTile; use crate::camera::Camera; use crate::scene::Scene; use crate::trace::Tracer; +use crate::sample::Sampler; -use crate::core::{Vector2f, Vector3f, Spectrum}; +use crate::core::{Vector2f, Spectrum}; use crate::Float; pub struct RenderTask { @@ -25,20 +26,24 @@ impl RenderTask { Self { tile, samples } } - fn render_at(&self, ctx: &RenderContext, x: i32, y: i32) -> Spectrum { - // Create a ray - let (r, _) = ctx.cam.generate_ray(&Vector2f::new_xy(x as Float, y as Float)); + fn render_at(&mut self, ctx: &RenderContext, x: i32, y: i32, sampler: &mut dyn Sampler) { + let corner = Vector2f::new_xy(x as Float, y as Float); - ctx.trc.trace(ctx.scn, &r) + for _ in 0..self.samples { + let p = corner + sampler.get_sample_2d(); + + // Create a ray + let (r, _) = ctx.cam.generate_ray(&p); + + self.tile.add_sample(&p, ctx.trc.trace(ctx.scn, &r)); + } } - pub fn render(&mut self, ctx: &RenderContext) { + pub fn render(&mut self, ctx: &RenderContext, sampler: &mut dyn Sampler) { let b = self.tile.bounds.clone(); for x in b.min.x .. b.max.x { for y in b.min.y .. b.max.y { - let p = Vector2f::new_xy(x as Float, y as Float); - - self.tile.add_sample(&p, self.render_at(ctx, x, y)) + self.render_at(ctx, x, y, sampler); } } } diff --git a/src/sample/mod.rs b/src/sample/mod.rs new file mode 100644 index 0000000..6f2c3eb --- /dev/null +++ b/src/sample/mod.rs @@ -0,0 +1,11 @@ +use crate::Float; +use crate::core::Vector2f; + +mod uniform; + +pub use uniform::UniformSampler; + +pub trait Sampler { + fn get_sample(&mut self) -> Float; + fn get_sample_2d(&mut self) -> Vector2f; +} diff --git a/src/sample/uniform.rs b/src/sample/uniform.rs new file mode 100644 index 0000000..221fdf8 --- /dev/null +++ b/src/sample/uniform.rs @@ -0,0 +1,32 @@ +use crate::core::Vector2f; +use crate::Float; +use super::Sampler; + +use rand::prelude::*; +use rand::distributions::Uniform; +use rand_pcg::Pcg32; + +#[derive(Clone)] +pub struct UniformSampler { + r: Pcg32, + d: Uniform, +} + +impl UniformSampler { + pub fn new() -> Self { + Self { + r: Pcg32::seed_from_u64(1), + d: Uniform::from(0.0..1.0), + } + } +} + +impl Sampler for UniformSampler { + fn get_sample(&mut self) -> Float { + self.d.sample(&mut self.r) + } + + fn get_sample_2d(&mut self) -> Vector2f { + Vector2f::new_xy(self.get_sample(), self.get_sample()) + } +} -- cgit v1.2.3