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 --- 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 ++++++++++++++++++++++++++++++++ 8 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 src/sample/mod.rs create mode 100644 src/sample/uniform.rs (limited to 'src') 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