From c5867bca848c994a3e3df8a7b989ca3a4efcf729 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Wed, 1 Apr 2020 23:13:02 +0200 Subject: [PATCH] WIP: pathtrace soup --- pathtracer/src/light/mod.rs | 6 ++ pathtracer/src/light/point_light.rs | 35 +++++----- pathtracer/src/light/spot_light.rs | 45 ++++++------- pathtracer/src/render/pathtrace/light_path.rs | 37 +++++++++++ pathtracer/src/render/pathtrace/mod.rs | 2 +- pathtracer/src/render/pathtrace/path.rs | 44 ------------- pathtracer/src/render/pathtrace/pathtracer.rs | 66 ++++++++++++++++--- pathtracer/src/scene/light_aggregate.rs | 8 +-- 8 files changed, 146 insertions(+), 97 deletions(-) create mode 100644 pathtracer/src/render/pathtrace/light_path.rs delete mode 100644 pathtracer/src/render/pathtrace/path.rs diff --git a/pathtracer/src/light/mod.rs b/pathtracer/src/light/mod.rs index ca3bf77..17e0cb2 100644 --- a/pathtracer/src/light/mod.rs +++ b/pathtracer/src/light/mod.rs @@ -2,6 +2,7 @@ use super::core::LinearColor; use super::{Point, Vector}; +use beevee::ray::Ray; use nalgebra::Unit; /// Represent a light in the scene being rendered. @@ -16,6 +17,11 @@ pub trait SpatialLight: Light { fn to_source(&self, origin: &Point) -> (Unit, f32); } +/// Represent a light from which rays can be sampled +pub trait SampleLight: SpatialLight { + fn sample_ray(&self) -> Ray; +} + mod ambient_light; pub use ambient_light::*; diff --git a/pathtracer/src/light/point_light.rs b/pathtracer/src/light/point_light.rs index 19f9d59..9d73ff6 100644 --- a/pathtracer/src/light/point_light.rs +++ b/pathtracer/src/light/point_light.rs @@ -1,4 +1,4 @@ -use super::{Light, SpatialLight}; +use super::{Light, SampleLight, SpatialLight}; use crate::core::LinearColor; use crate::{Point, Vector}; use beevee::ray::Ray; @@ -31,7 +31,23 @@ impl PointLight { pub fn new(position: Point, color: LinearColor) -> Self { PointLight { position, color } } +} +impl Light for PointLight { + fn illumination(&self, point: &Point) -> LinearColor { + let dist = (self.position - point).norm(); + self.color.clone() / dist + } +} + +impl SpatialLight for PointLight { + fn to_source(&self, point: &Point) -> (Unit, f32) { + let delt = self.position - point; + let dist = delt.norm(); + (Unit::new_normalize(delt), dist) + } +} +impl SampleLight for PointLight { /// Uniformly sample a ray from the point-light in a random direction. /// /// # Examles @@ -47,7 +63,7 @@ impl PointLight { /// ); /// let sampled = dir_light.sample_ray(); /// ``` - pub fn sample_ray(&self) -> Ray { + fn sample_ray(&self) -> Ray { let mut rng = rand::thread_rng(); // Sample sphere uniformly // See @@ -63,21 +79,6 @@ impl PointLight { } } -impl Light for PointLight { - fn illumination(&self, point: &Point) -> LinearColor { - let dist = (self.position - point).norm(); - self.color.clone() / dist - } -} - -impl SpatialLight for PointLight { - fn to_source(&self, point: &Point) -> (Unit, f32) { - let delt = self.position - point; - let dist = delt.norm(); - (Unit::new_normalize(delt), dist) - } -} - #[cfg(test)] mod test { use super::*; diff --git a/pathtracer/src/light/spot_light.rs b/pathtracer/src/light/spot_light.rs index 220e370..eb9ef60 100644 --- a/pathtracer/src/light/spot_light.rs +++ b/pathtracer/src/light/spot_light.rs @@ -1,4 +1,4 @@ -use super::{Light, SpatialLight}; +use super::{Light, SampleLight, SpatialLight}; use crate::core::LinearColor; use crate::{Point, Vector}; use beevee::ray::Ray; @@ -47,7 +47,28 @@ impl SpotLight { color, ) } +} +impl Light for SpotLight { + fn illumination(&self, point: &Point) -> LinearColor { + let delt = point - self.position; + let cos = self.direction.dot(&delt.normalize()); + if cos >= self.cosine_value { + self.color.clone() / delt.norm_squared() + } else { + LinearColor::black() + } + } +} + +impl SpatialLight for SpotLight { + fn to_source(&self, point: &Point) -> (Unit, f32) { + let delt = self.position - point; + let dist = delt.norm(); + (Unit::new_normalize(delt), dist) + } +} +impl SampleLight for SpotLight { /// Uniformly sample a ray from the spot-light in a random direction. /// /// # Examles @@ -65,7 +86,7 @@ impl SpotLight { /// ); /// let sampled = spot_light.sample_ray(); /// ``` - pub fn sample_ray(&self) -> Ray { + fn sample_ray(&self) -> Ray { let mut rng = rand::thread_rng(); // Sample cap at Z-pole uniformly // See @@ -94,26 +115,6 @@ impl SpotLight { } } -impl Light for SpotLight { - fn illumination(&self, point: &Point) -> LinearColor { - let delt = point - self.position; - let cos = self.direction.dot(&delt.normalize()); - if cos >= self.cosine_value { - self.color.clone() / delt.norm_squared() - } else { - LinearColor::black() - } - } -} - -impl SpatialLight for SpotLight { - fn to_source(&self, point: &Point) -> (Unit, f32) { - let delt = self.position - point; - let dist = delt.norm(); - (Unit::new_normalize(delt), dist) - } -} - #[derive(Debug, Deserialize)] struct SerializedSpotLight { position: Point, diff --git a/pathtracer/src/render/pathtrace/light_path.rs b/pathtracer/src/render/pathtrace/light_path.rs new file mode 100644 index 0000000..0f28c33 --- /dev/null +++ b/pathtracer/src/render/pathtrace/light_path.rs @@ -0,0 +1,37 @@ +use crate::core::{LightProperties, LinearColor}; +use crate::light::SampleLight; +use crate::Point; + +pub struct LightPathPoint { + pub point: Point, + pub luminance: LinearColor, + pub properties: LightProperties, +} + +impl LightPathPoint { + pub fn new(point: Point, luminance: LinearColor, properties: LightProperties) -> Self { + LightPathPoint { + point, + luminance, + properties, + } + } +} + +pub struct LightPath<'a> { + pub origin: &'a dyn SampleLight, + pub points: Vec, +} + +impl<'a> LightPath<'a> { + pub fn new(origin: &'a dyn SampleLight) -> Self { + LightPath { + origin, + points: Vec::new(), + } + } + + pub fn push_point(&mut self, new_point: LightPathPoint) { + self.points.push(new_point) + } +} diff --git a/pathtracer/src/render/pathtrace/mod.rs b/pathtracer/src/render/pathtrace/mod.rs index 5f3e759..0cd8127 100644 --- a/pathtracer/src/render/pathtrace/mod.rs +++ b/pathtracer/src/render/pathtrace/mod.rs @@ -1,4 +1,4 @@ -mod path; +mod light_path; mod pathtracer; pub use self::pathtracer::*; diff --git a/pathtracer/src/render/pathtrace/path.rs b/pathtracer/src/render/pathtrace/path.rs deleted file mode 100644 index 28da0d4..0000000 --- a/pathtracer/src/render/pathtrace/path.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::core::LightProperties; -use crate::{Point, Vector}; -use nalgebra::Unit; - -pub struct PathPoint { - pub point: Point, - pub incident: Unit, - pub normal: Unit, - pub properties: LightProperties, -} - -impl PathPoint { - pub fn new( - point: Point, - incident: Unit, - normal: Unit, - properties: LightProperties, - ) -> Self { - PathPoint { - point, - incident, - normal, - properties, - } - } -} - -pub struct Path { - pub origin: Point, - pub points: Vec, -} - -impl Path { - pub fn new(origin: Point) -> Self { - Path { - origin, - points: Vec::new(), - } - } - - pub fn push_point(&mut self, new_point: PathPoint) { - self.points.push(new_point) - } -} diff --git a/pathtracer/src/render/pathtrace/pathtracer.rs b/pathtracer/src/render/pathtrace/pathtracer.rs index 6d113ab..41424f0 100644 --- a/pathtracer/src/render/pathtrace/pathtracer.rs +++ b/pathtracer/src/render/pathtrace/pathtracer.rs @@ -1,9 +1,17 @@ +use super::super::utils::*; use super::super::Renderer; -use super::path::*; +use super::light_path::{LightPath, LightPathPoint}; +use crate::core::{LightProperties, LinearColor}; +use crate::light::SampleLight; +use crate::material::Material; +use crate::scene::object::Object; use crate::scene::Scene; +use crate::shape::Shape; use crate::{Point, Vector}; +use beevee::ray::Ray; use image::RgbImage; use nalgebra::Unit; +use rand::Rng; /// Render the [`Scene`] using Bidirectional-Pathtracing /// @@ -29,17 +37,57 @@ impl Pathtracer { todo!() } - fn construct_path(&self, point: Point, direction: Unit) -> Path { - let mut res = Path::new(point); - for _ in 0..self.scene.reflection_limit { - // FIXME: - // * cast_ray: if no intersection, return the empty path - // * look-up information at intersection - // * append to path - // * start again with new origin + fn cast_ray(&self, ray: Ray) -> Option<(f32, &Object)> { + self.scene.bvh.walk(&ray, &self.scene.objects) + } + + fn construct_light_path(&self) -> LightPath { + let mut rng = rand::thread_rng(); + let num_lights = self.scene.lights.points.len() + self.scene.lights.spots.len(); + let index = rng.gen_range(0, num_lights); + + let sample_light: &dyn SampleLight = if index < self.scene.lights.points.len() { + &self.scene.lights.points[index] + } else { + &self.scene.lights.spots[index - self.scene.lights.points.len()] + }; + + let mut ray = sample_light.sample_ray(); + let mut res = LightPath::new(sample_light); + + if let Some((dist, obj)) = self.cast_ray(ray) { + let hit_pos = ray.origin + ray.direction.as_ref() * dist; + let texel = obj.shape.project_texel(&hit_pos); + let new_point = LightPathPoint::new( + hit_pos, + sample_light.illumination(&hit_pos), + obj.material.properties(texel), + ); + res.push_point(new_point); + ray = todo!(); // Sample new direction + } else { + return res; + }; + + for _ in 1..self.scene.reflection_limit { + if let Some((dist, obj)) = self.cast_ray(ray) { + let new_point = todo!(); + res.push_point(new_point); + } else { + break; + } } res } + + fn illuminate( + &self, + point: Point, + properties: LightProperties, + path: LightPath, + ) -> LinearColor { + path.points.iter().map(|p| p.luminance.clone()).sum() + } } impl Renderer for Pathtracer { diff --git a/pathtracer/src/scene/light_aggregate.rs b/pathtracer/src/scene/light_aggregate.rs index acd0a82..ed23f3b 100644 --- a/pathtracer/src/scene/light_aggregate.rs +++ b/pathtracer/src/scene/light_aggregate.rs @@ -8,13 +8,13 @@ use std::iter::Iterator; /// A struct centralizing the light computation logic. pub struct LightAggregate { #[serde(default)] - ambients: Vec, + pub(crate) ambients: Vec, #[serde(default)] - directionals: Vec, + pub(crate) directionals: Vec, #[serde(default)] - points: Vec, + pub(crate) points: Vec, #[serde(default)] - spots: Vec, + pub(crate) spots: Vec, } impl LightAggregate {