From dbe5f54957ddc13549a6ce822da95170aa09a0c6 Mon Sep 17 00:00:00 2001 From: Julian T Date: Mon, 8 Feb 2021 14:32:11 +0100 Subject: Rename to pathtrace, started for of depth of field, choose closest intersect --- Cargo.lock | 18 ++++++------ Cargo.toml | 2 +- src/camera/camera.rs | 71 +++++++++++++++++++++++++++++----------------- src/core/bound.rs | 4 +-- src/core/hittable.rs | 2 ++ src/core/vector3.rs | 2 +- src/main.rs | 24 +++++++++------- src/scene/scene.rs | 16 +++++++++-- src/scene/shapes/sphere.rs | 5 ++-- src/trace/mod.rs | 4 +-- src/trace/pathtrace.rs | 4 +-- 11 files changed, 93 insertions(+), 59 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b0a6179..c9f49c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -274,15 +274,6 @@ dependencies = [ "libc", ] -[[package]] -name = "pathtrace" -version = "0.1.0" -dependencies = [ - "image", - "rand", - "rand_pcg", -] - [[package]] name = "png" version = "0.16.8" @@ -375,6 +366,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "rendering" +version = "0.1.0" +dependencies = [ + "image", + "rand", + "rand_pcg", +] + [[package]] name = "scoped_threadpool" version = "0.1.9" diff --git a/Cargo.toml b/Cargo.toml index f1d384d..09f2c2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "pathtrace" +name = "rendering" version = "0.1.0" authors = ["Julian T "] edition = "2018" diff --git a/src/camera/camera.rs b/src/camera/camera.rs index d49220b..e770efe 100644 --- a/src/camera/camera.rs +++ b/src/camera/camera.rs @@ -6,23 +6,28 @@ //! # Examples //! //! ``` -//! use pathtrace::camera::Camera; -//! use pathtrace::core::{Vector3f, Vector2f, Vector2i}; +//! use rendering::camera::{CameraSettings, Camera}; +//! use rendering::core::{Vector3f, Vector2f, Vector2i}; //! -//! let cam = Camera::new( -//! Vector3f::new(10.0), -//! Vector3f::new(0.0), -//! Vector3f::new_xyz(0.0, 1.0, 0.0), -//! 90.0, Vector2i::new(10.0), -//! ); +//! let set = CameraSettings { +//! origin: Vector3f::new(10.0), +//! target: Vector3f::new(0.0), +//! up: Vector3f::new_xyz(0.0, 1.0, 0.0), +//! fov: 90.0, +//! filmsize: Vector2i::new(10), +//! focus: None, +//! aperture: 0.0, +//! }; +//! +//! let cam = Camera::new(&set); //! //! let (r, _) = cam.generate_ray(&Vector2f::new(5.0)); //! let dir = r.direction; //! //! assert!( -//! dir.x == -0.44792563 && -//! dir.y == -0.659974 && -//! dir.z == -0.6031559 +//! dir.x == -0.6031558065478413 && +//! dir.y == -0.6599739684616743 && +//! dir.z == -0.4479257014065748 //! ); //! //! ``` @@ -33,43 +38,58 @@ use crate::core::{Vector3f, Vector2f, Vector2i, Ray}; pub struct Camera { /// The camera origin in the screen origin: Vector3f, - /// Vector from camera origin to the screen lower left corner + /// Vector from camera origin to the screen lower left corner of the film plane screen_origin: Vector3f, /// Scaling vectors from screen_origin qx: Vector3f, qy: Vector3f, } +/// Settings for initializing camera pub struct CameraSettings { + /// Where rays originate from pub origin: Vector3f, + /// Point where center of image is pointed at pub target: Vector3f, + /// Vector that will be up in the resulting image pub up: Vector3f, + /// The vertical field of view in degrees. + /// Currently must be between [0; 180[. pub fov: Float, - pub screensize: Vector2i, + /// The film aspect ratio, height / width + pub filmsize: Vector2i, + /// The lens aperture + pub aperture: Float, + /// The distance to the focus plane + /// + /// if None it will be set to the distance between origin and target + pub focus: Option, } impl Camera { /// Create a new camera look at a target - /// - /// The field of view specifies how wide the image should be. - /// Currently must be between [0; 180[. pub fn new(set: &CameraSettings) -> Camera { - let screensize = Vector2f::from(set.screensize); + let filmsize = Vector2f::from(set.filmsize); // Calculate translation vectors - let forward = (set.target - set.origin).norm(); + let mut forward = set.target - set.origin; + + let focus = set.focus.unwrap_or(forward.len()); + + forward.norm_in(); + let right = set.up.cross(&forward).norm(); let newup = forward.cross(&right).norm(); - // Calculate screen size from fov - let aspect = screensize.y / screensize.x; - let width = 2.0 * (set.fov / 2.0).to_radians().tan(); + let aspect = (filmsize.y) / (filmsize.x); + // Calculate screen size from fov and focus distance + let width = 2.0 * focus * (set.fov / 2.0).to_radians().tan(); let height = aspect * width; // Calculate screen scaling vectors - let qx = right * (width / (screensize.x - 1.0)); - let qy = newup * (height / (screensize.y - 1.0)); + let qx = right * (width / (filmsize.x - 1.0)); + let qy = newup * (height / (filmsize.y - 1.0)); - let screen_origin = forward - (right * (width/2.0)) + (newup * (height/2.0)); + let screen_origin = forward * focus - (right * (width/2.0)) + (newup * (height/2.0)); Camera { origin: set.origin, @@ -81,8 +101,7 @@ impl Camera { /// Generates a ray a screen space point /// - /// The point coordinates should be between [0,0] (lower left corner) and [screensize.x, - /// screensize.y] (upper right corner) + /// The point coordinates should be between [0,1) with (0, 0) being the upper let corner /// /// Will return a ray and a weight /// diff --git a/src/core/bound.rs b/src/core/bound.rs index 635218a..a1c1070 100644 --- a/src/core/bound.rs +++ b/src/core/bound.rs @@ -52,7 +52,7 @@ impl Bound2 { /// # Examples /// /// ``` - /// use pathtrace::core::Bound2i; + /// use rendering::core::Bound2i; /// let b = Bound2i::new_xyxy(2, 2, 6, 7); /// let diag = b.diagonal(); /// @@ -67,7 +67,7 @@ impl Bound2 { /// # Examples /// /// ``` - /// use pathtrace::core::Bound2i; + /// use rendering::core::Bound2i; /// let b = Bound2i::new_xyxy(10, 10, 20, 20); /// /// assert!(b.area() == 100); diff --git a/src/core/hittable.rs b/src/core/hittable.rs index 20c82f7..e495d5b 100644 --- a/src/core/hittable.rs +++ b/src/core/hittable.rs @@ -1,10 +1,12 @@ use crate::core::{Vector3f, Ray}; +use crate::Float; /// Returns the context of a intersection pub struct Intersection { /// Normal vector at intersection pub n: Vector3f, pub p: Vector3f, + pub t: Float, } impl Intersection { diff --git a/src/core/vector3.rs b/src/core/vector3.rs index 9d6c1cf..1ae4db2 100644 --- a/src/core/vector3.rs +++ b/src/core/vector3.rs @@ -128,7 +128,7 @@ impl Vector3f { /// # Example /// /// ``` - /// use pathtrace::core::Vector3f; + /// use rendering::core::Vector3f; /// let mut v = Vector3f::new_xyz(10.0, 0.0, 0.0); /// v.norm_in(); /// assert!(v.x == 1.0); diff --git a/src/main.rs b/src/main.rs index ac197a1..1707360 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,11 +1,11 @@ -use pathtrace::camera::{Camera, Film, CameraSettings}; -use pathtrace::scene::{Scene, Object}; -use pathtrace::trace::DefaultTracer; -use pathtrace::scene::shapes::Sphere; -use pathtrace::core::{Vector2i, Vector3f, Spectrum}; -use pathtrace::render::{RenderContext, RenderTask}; -use pathtrace::sample::UniformSampler; -use pathtrace::material::{Reflectant, Lambertian}; +use rendering::camera::{Camera, Film, CameraSettings}; +use rendering::scene::{Scene, Object}; +use rendering::trace::DefaultTracer; +use rendering::scene::shapes::Sphere; +use rendering::core::{Vector2i, Vector3f, Spectrum}; +use rendering::render::{RenderContext, RenderTask}; +use rendering::sample::UniformSampler; +use rendering::material::{Reflectant, Lambertian}; use std::rc::Rc; @@ -14,10 +14,12 @@ fn main() { let cam = Camera::new(&CameraSettings { target: Vector3f::new_xyz(0.5, 0.0, -1.0), - origin: Vector3f::new_xyz(0.0, 0.0, 0.5), + origin: Vector3f::new_xyz(1.7, 0.0, 0.0), up: Vector3f::new_xyz(0.0, 1.0, 0.0), fov: 90.0, - screensize: res, + filmsize: res, + focus: None, + aperture: 0.5, }); let brown = Rc::new(Lambertian::new(Spectrum::new_rgb(0.5, 0.3, 0.0))); @@ -40,7 +42,7 @@ fn main() { let mut film = Film::new(res); let tile = film.get_tile(&film.frame); - let mut task = RenderTask::new(Box::new(tile), 100); + let mut task = RenderTask::new(Box::new(tile), 10); task.render(&ctx, &mut sampler); film.commit_tile(&task.tile); diff --git a/src/scene/scene.rs b/src/scene/scene.rs index 8575217..83a43c7 100644 --- a/src/scene/scene.rs +++ b/src/scene/scene.rs @@ -7,6 +7,11 @@ pub struct Scene { objs: Vec, } +pub struct SceneIntersect<'a> { + pub mat: &'a dyn Material, + pub i: Intersection, +} + impl Scene { pub fn new() -> Self { Self { @@ -24,14 +29,19 @@ impl Scene { } } - pub fn intersect(&self, ray: &Ray) -> Option<(&dyn Material, Intersection)> { + pub fn intersect(&self, ray: &Ray) -> Option { + let mut min: Option = None; + for obj in self.objs.iter() { if let Some(i) = obj.shape.intersect(&ray) { - return Some((obj.mat.as_ref(), i)) + match min { + Some(ref si) if si.i.t < i.t => (), + _ => min = Some(SceneIntersect {i, mat: obj.mat.as_ref() }), + } } } - None + min } } diff --git a/src/scene/shapes/sphere.rs b/src/scene/shapes/sphere.rs index 3f07b9e..eaa6625 100644 --- a/src/scene/shapes/sphere.rs +++ b/src/scene/shapes/sphere.rs @@ -44,6 +44,7 @@ impl Hittable for Sphere { Some(Intersection { n: self.norm_at(&w), p: w, + t: distance, }) } @@ -63,7 +64,7 @@ mod tests { direction: Vector3f::new_xyz(0.0, 1.0, 1.5).norm(), }; - let dist = sph.intersect(&ray); - assert!((dist.unwrap() - 3.28).abs() < 0.01); + let dist = sph.intersect(&ray).unwrap(); + assert!((dist.t - 3.28).abs() < 0.01); } } diff --git a/src/trace/mod.rs b/src/trace/mod.rs index cf06246..6c2c9f3 100644 --- a/src/trace/mod.rs +++ b/src/trace/mod.rs @@ -30,8 +30,8 @@ impl NormTracer<'_> { impl Tracer for NormTracer<'_> { fn trace(&self, _: &mut dyn Sampler, ray: &Ray) -> Spectrum { // Trace ray, we dont care about material - if let Some((_, i)) = self.scn.intersect(ray) { - let norm = i.n * 0.5 + Vector3f::new(0.5); + if let Some(si) = self.scn.intersect(ray) { + let norm = si.i.n * 0.5 + Vector3f::new(0.5); return Spectrum::new_rgb(norm.x, norm.y, norm.z); } diff --git a/src/trace/pathtrace.rs b/src/trace/pathtrace.rs index 811b653..af24118 100644 --- a/src/trace/pathtrace.rs +++ b/src/trace/pathtrace.rs @@ -24,8 +24,8 @@ impl PathTracer<'_> { return Spectrum::ZERO; } - if let Some((mat, i)) = self.scn.intersect(ray) { - if let Some((scalar, nray)) = mat.scatter(ray, &i, sampler) { + if let Some(si) = self.scn.intersect(ray) { + if let Some((scalar, nray)) = si.mat.scatter(ray, &si.i, sampler) { return self.trace_recur(sampler, &nray, depth-1) * scalar; } else { return Spectrum::ZERO; -- cgit v1.2.3