aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-02-05 20:17:20 +0100
committerJulian T <julian@jtle.dk>2021-02-05 20:17:20 +0100
commit1e83ea211055eb234b89c69b5d03602e3fcb98fb (patch)
tree7b58c7e6d7d174906541e9f2acf546294f8e9ca5
parent9235e74dfbc41895a5f8807e1ab93508268a39ea (diff)
Achieve anti aliasing with multi pixel sampling
-rw-r--r--Cargo.lock74
-rw-r--r--Cargo.toml2
-rw-r--r--src/camera/film.rs6
-rw-r--r--src/core/spectrum.rs12
-rw-r--r--src/core/vector2.rs4
-rw-r--r--src/lib.rs1
-rw-r--r--src/main.rs7
-rw-r--r--src/render.rs23
-rw-r--r--src/sample/mod.rs11
-rw-r--r--src/sample/uniform.rs32
10 files changed, 156 insertions, 16 deletions
diff --git a/Cargo.lock b/Cargo.lock
index a6626c8..b0a6179 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -126,6 +126,17 @@ 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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -268,6 +279,8 @@ name = "pathtrace"
version = "0.1.0"
dependencies = [
"image",
+ "rand",
+ "rand_pcg",
]
[[package]]
@@ -283,6 +296,61 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -331,6 +399,12 @@ dependencies = [
]
[[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"
source = "registry+https://github.com/rust-lang/crates.io-index"
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<Float> for &Spectrum {
}
}
+impl std::ops::Div<Float> 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<Float>,
+}
+
+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())
+ }
+}