aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2021-02-07 17:52:30 +0100
committerJulian T <julian@jtle.dk>2021-02-07 17:52:46 +0100
commitc24d1e52b3f173ba5f4cc04f5a6a449a011a60c7 (patch)
treeff39abb0473a78aa15fbd2ab4c7f5c82660fe3ab
parent33e747fa1c0957546c10e4d7b490ac7fbb0fd2d2 (diff)
Add reflecting material
-rw-r--r--src/core/ray.rs7
-rw-r--r--src/core/spectrum.rs2
-rw-r--r--src/core/vector3.rs10
-rw-r--r--src/lib.rs3
-rw-r--r--src/main.rs12
-rw-r--r--src/material/mod.rs2
-rw-r--r--src/material/reflectant.rs39
-rw-r--r--src/trace/pathtrace.rs12
8 files changed, 77 insertions, 10 deletions
diff --git a/src/core/ray.rs b/src/core/ray.rs
index c944184..0517e50 100644
--- a/src/core/ray.rs
+++ b/src/core/ray.rs
@@ -8,6 +8,13 @@ pub struct Ray {
}
impl Ray {
+ pub fn new(origin: Vector3f, direction: Vector3f) -> Ray {
+ Ray {
+ origin,
+ direction,
+ }
+ }
+
pub fn new_to(origin: Vector3f, target: Vector3f) -> Ray {
let dir = (target - origin).norm();
Ray {
diff --git a/src/core/spectrum.rs b/src/core/spectrum.rs
index 9cca7dc..c33d3af 100644
--- a/src/core/spectrum.rs
+++ b/src/core/spectrum.rs
@@ -12,6 +12,8 @@ pub struct Spectrum {
}
impl Spectrum {
+ pub const ZERO: Self = Spectrum { c: [0.0; 3] };
+
pub fn new_rgb(r: Float, g: Float, b: Float) -> Spectrum {
Spectrum { c: [r, g, b] }
}
diff --git a/src/core/vector3.rs b/src/core/vector3.rs
index ff5a678..9d6c1cf 100644
--- a/src/core/vector3.rs
+++ b/src/core/vector3.rs
@@ -2,7 +2,7 @@
//!
//! Also add more 3d math things needed for shading and 3d calculations.
use crate::{Float, Number, NEAR_ZERO};
-use std::ops::{Mul, Sub, Add, DivAssign, Neg};
+use std::ops::{Mul, Sub, Add, DivAssign, Neg, AddAssign};
use std::fmt;
#[derive(Clone, Copy)]
@@ -85,6 +85,14 @@ impl<T: Number> Neg for Vector3<T> {
}
}
+impl<T: Number> AddAssign<&Self> for Vector3<T> {
+ fn add_assign(&mut self, op: &Self) {
+ self.x += op.x;
+ self.y += op.y;
+ self.z += op.z;
+ }
+}
+
impl<T: Number> DivAssign<T> for Vector3<T> {
fn div_assign(&mut self, op: T) {
self.x /= op;
diff --git a/src/lib.rs b/src/lib.rs
index a0af705..1593471 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,7 +6,7 @@ pub mod trace;
pub mod sample;
pub mod material;
-use std::ops::{Add, Sub, Mul, DivAssign, Neg};
+use std::ops::{Add, Sub, Mul, DivAssign, AddAssign, Neg};
use std::cmp;
use std::fmt;
use std::f64::consts::PI;
@@ -22,6 +22,7 @@ pub trait Number:
Mul<Output = Self> +
Neg<Output = Self> +
DivAssign +
+ AddAssign +
fmt::Display
{}
diff --git a/src/main.rs b/src/main.rs
index 759cbf9..ac197a1 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -5,7 +5,7 @@ use pathtrace::scene::shapes::Sphere;
use pathtrace::core::{Vector2i, Vector3f, Spectrum};
use pathtrace::render::{RenderContext, RenderTask};
use pathtrace::sample::UniformSampler;
-use pathtrace::material::Lambertian;
+use pathtrace::material::{Reflectant, Lambertian};
use std::rc::Rc;
@@ -13,8 +13,8 @@ fn main() {
let res = Vector2i::new_xy(500, 500);
let cam = Camera::new(&CameraSettings {
- target: Vector3f::new_xyz(0.0, 0.0, -1.0),
- origin: Vector3f::new_xyz(0.0, 0.0, 0.0),
+ target: Vector3f::new_xyz(0.5, 0.0, -1.0),
+ origin: Vector3f::new_xyz(0.0, 0.0, 0.5),
up: Vector3f::new_xyz(0.0, 1.0, 0.0),
fov: 90.0,
screensize: res,
@@ -22,10 +22,12 @@ fn main() {
let brown = Rc::new(Lambertian::new(Spectrum::new_rgb(0.5, 0.3, 0.0)));
let blue = Rc::new(Lambertian::new(Spectrum::new_rgb(0.0, 0.3, 0.7)));
+ let metal = Rc::new(Reflectant::new(Spectrum::new_rgb(0.75, 0.75, 0.75), Some(0.1)));
let mut scn = Scene::new();
scn.add_objects(vec![
- Object::new(blue.clone(), Box::new(Sphere::new(0.5, Vector3f::new_xyz(0.0, 0.0, -1.0)))),
+ Object::new(metal.clone(), Box::new(Sphere::new(0.5, Vector3f::new_xyz(0.0, 0.0, -1.0)))),
+ Object::new(blue.clone(), Box::new(Sphere::new(0.5, Vector3f::new_xyz(1.0, 0.0, -1.0)))),
Object::new(brown.clone(), Box::new(Sphere::new(100.0, Vector3f::new_xyz(0.0, -100.5, -1.0)))),
]);
@@ -38,7 +40,7 @@ fn main() {
let mut film = Film::new(res);
let tile = film.get_tile(&film.frame);
- let mut task = RenderTask::new(Box::new(tile), 10);
+ let mut task = RenderTask::new(Box::new(tile), 100);
task.render(&ctx, &mut sampler);
film.commit_tile(&task.tile);
diff --git a/src/material/mod.rs b/src/material/mod.rs
index 62cbf9a..c939385 100644
--- a/src/material/mod.rs
+++ b/src/material/mod.rs
@@ -2,8 +2,10 @@ use crate::core::{Ray, Intersection, Spectrum};
use crate::sample::Sampler;
mod lambertian;
+mod reflectant;
pub use lambertian::Lambertian;
+pub use reflectant::Reflectant;
pub trait Material {
fn scatter(&self, ray: &Ray, i: &Intersection, sampler: &mut dyn Sampler) -> Option<(Spectrum, Ray)>;
diff --git a/src/material/reflectant.rs b/src/material/reflectant.rs
new file mode 100644
index 0000000..f4b110c
--- /dev/null
+++ b/src/material/reflectant.rs
@@ -0,0 +1,39 @@
+use crate::Float;
+use crate::core::{Ray, Intersection, Spectrum, Vector3f};
+use super::Material;
+use crate::sample::Sampler;
+
+pub struct Reflectant {
+ color: Spectrum,
+ fuzz: Option<Float>,
+}
+
+impl Reflectant {
+ pub fn new(c: Spectrum, fuzz: Option<Float>) -> Reflectant {
+ Reflectant {
+ color: c,
+ fuzz,
+ }
+ }
+}
+
+fn reflect(v: &Vector3f, n: &Vector3f) -> Vector3f {
+ *v - *n * (2.0 * v.dot(n))
+}
+
+impl Material for Reflectant {
+ fn scatter(&self, ray: &Ray, i: &Intersection, sampler: &mut dyn Sampler) -> Option<(Spectrum, Ray)> {
+ // Find reflectance vector
+ let mut reflected = reflect(&ray.direction, &i.n);
+ if let Some(fuzz) = self.fuzz {
+ reflected += &(sampler.get_unit_vector() * fuzz);
+ }
+
+ Some((
+ self.color,
+ Ray::new(i.p, reflected.norm()),
+ ))
+ }
+}
+
+
diff --git a/src/trace/pathtrace.rs b/src/trace/pathtrace.rs
index a3a688a..811b653 100644
--- a/src/trace/pathtrace.rs
+++ b/src/trace/pathtrace.rs
@@ -18,11 +18,17 @@ impl PathTracer<'_> {
}
}
- pub fn trace_recur(&self, sampler: &mut dyn Sampler, ray: &Ray) -> Spectrum {
+ pub fn trace_recur(&self, sampler: &mut dyn Sampler, ray: &Ray, depth: i32) -> Spectrum {
+
+ if depth == 0 {
+ return Spectrum::ZERO;
+ }
if let Some((mat, i)) = self.scn.intersect(ray) {
if let Some((scalar, nray)) = mat.scatter(ray, &i, sampler) {
- return self.trace_recur(sampler, &nray) * scalar;
+ return self.trace_recur(sampler, &nray, depth-1) * scalar;
+ } else {
+ return Spectrum::ZERO;
}
}
@@ -35,6 +41,6 @@ impl PathTracer<'_> {
impl Tracer for PathTracer<'_> {
fn trace(&self, sampler: &mut dyn Sampler, ray: &Ray) -> Spectrum {
- self.trace_recur(sampler, ray)
+ self.trace_recur(sampler, ray, self.depth)
}
}