WIP: pathtrace soup
This commit is contained in:
parent
8afc5ba382
commit
c5867bca84
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use super::core::LinearColor;
|
use super::core::LinearColor;
|
||||||
use super::{Point, Vector};
|
use super::{Point, Vector};
|
||||||
|
use beevee::ray::Ray;
|
||||||
use nalgebra::Unit;
|
use nalgebra::Unit;
|
||||||
|
|
||||||
/// Represent a light in the scene being rendered.
|
/// Represent a light in the scene being rendered.
|
||||||
|
@ -16,6 +17,11 @@ pub trait SpatialLight: Light {
|
||||||
fn to_source(&self, origin: &Point) -> (Unit<Vector>, f32);
|
fn to_source(&self, origin: &Point) -> (Unit<Vector>, f32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represent a light from which rays can be sampled
|
||||||
|
pub trait SampleLight: SpatialLight {
|
||||||
|
fn sample_ray(&self) -> Ray;
|
||||||
|
}
|
||||||
|
|
||||||
mod ambient_light;
|
mod ambient_light;
|
||||||
pub use ambient_light::*;
|
pub use ambient_light::*;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Light, SpatialLight};
|
use super::{Light, SampleLight, SpatialLight};
|
||||||
use crate::core::LinearColor;
|
use crate::core::LinearColor;
|
||||||
use crate::{Point, Vector};
|
use crate::{Point, Vector};
|
||||||
use beevee::ray::Ray;
|
use beevee::ray::Ray;
|
||||||
|
@ -31,7 +31,23 @@ impl PointLight {
|
||||||
pub fn new(position: Point, color: LinearColor) -> Self {
|
pub fn new(position: Point, color: LinearColor) -> Self {
|
||||||
PointLight { position, color }
|
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<Vector>, 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.
|
/// Uniformly sample a ray from the point-light in a random direction.
|
||||||
///
|
///
|
||||||
/// # Examles
|
/// # Examles
|
||||||
|
@ -47,7 +63,7 @@ impl PointLight {
|
||||||
/// );
|
/// );
|
||||||
/// let sampled = dir_light.sample_ray();
|
/// let sampled = dir_light.sample_ray();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn sample_ray(&self) -> Ray {
|
fn sample_ray(&self) -> Ray {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
// Sample sphere uniformly
|
// Sample sphere uniformly
|
||||||
// See <https://mathworld.wolfram.com/SpherePointPicking.html>
|
// See <https://mathworld.wolfram.com/SpherePointPicking.html>
|
||||||
|
@ -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<Vector>, f32) {
|
|
||||||
let delt = self.position - point;
|
|
||||||
let dist = delt.norm();
|
|
||||||
(Unit::new_normalize(delt), dist)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::{Light, SpatialLight};
|
use super::{Light, SampleLight, SpatialLight};
|
||||||
use crate::core::LinearColor;
|
use crate::core::LinearColor;
|
||||||
use crate::{Point, Vector};
|
use crate::{Point, Vector};
|
||||||
use beevee::ray::Ray;
|
use beevee::ray::Ray;
|
||||||
|
@ -47,7 +47,28 @@ impl SpotLight {
|
||||||
color,
|
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<Vector>, 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.
|
/// Uniformly sample a ray from the spot-light in a random direction.
|
||||||
///
|
///
|
||||||
/// # Examles
|
/// # Examles
|
||||||
|
@ -65,7 +86,7 @@ impl SpotLight {
|
||||||
/// );
|
/// );
|
||||||
/// let sampled = spot_light.sample_ray();
|
/// let sampled = spot_light.sample_ray();
|
||||||
/// ```
|
/// ```
|
||||||
pub fn sample_ray(&self) -> Ray {
|
fn sample_ray(&self) -> Ray {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
// Sample cap at Z-pole uniformly
|
// Sample cap at Z-pole uniformly
|
||||||
// See <https://math.stackexchange.com/questions/56784>
|
// See <https://math.stackexchange.com/questions/56784>
|
||||||
|
@ -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<Vector>, f32) {
|
|
||||||
let delt = self.position - point;
|
|
||||||
let dist = delt.norm();
|
|
||||||
(Unit::new_normalize(delt), dist)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct SerializedSpotLight {
|
struct SerializedSpotLight {
|
||||||
position: Point,
|
position: Point,
|
||||||
|
|
37
pathtracer/src/render/pathtrace/light_path.rs
Normal file
37
pathtracer/src/render/pathtrace/light_path.rs
Normal file
|
@ -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<LightPathPoint>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
mod path;
|
mod light_path;
|
||||||
|
|
||||||
mod pathtracer;
|
mod pathtracer;
|
||||||
pub use self::pathtracer::*;
|
pub use self::pathtracer::*;
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
use crate::core::LightProperties;
|
|
||||||
use crate::{Point, Vector};
|
|
||||||
use nalgebra::Unit;
|
|
||||||
|
|
||||||
pub struct PathPoint {
|
|
||||||
pub point: Point,
|
|
||||||
pub incident: Unit<Vector>,
|
|
||||||
pub normal: Unit<Vector>,
|
|
||||||
pub properties: LightProperties,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PathPoint {
|
|
||||||
pub fn new(
|
|
||||||
point: Point,
|
|
||||||
incident: Unit<Vector>,
|
|
||||||
normal: Unit<Vector>,
|
|
||||||
properties: LightProperties,
|
|
||||||
) -> Self {
|
|
||||||
PathPoint {
|
|
||||||
point,
|
|
||||||
incident,
|
|
||||||
normal,
|
|
||||||
properties,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Path {
|
|
||||||
pub origin: Point,
|
|
||||||
pub points: Vec<PathPoint>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
use super::super::utils::*;
|
||||||
use super::super::Renderer;
|
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::scene::Scene;
|
||||||
|
use crate::shape::Shape;
|
||||||
use crate::{Point, Vector};
|
use crate::{Point, Vector};
|
||||||
|
use beevee::ray::Ray;
|
||||||
use image::RgbImage;
|
use image::RgbImage;
|
||||||
use nalgebra::Unit;
|
use nalgebra::Unit;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
/// Render the [`Scene`] using Bidirectional-Pathtracing
|
/// Render the [`Scene`] using Bidirectional-Pathtracing
|
||||||
///
|
///
|
||||||
|
@ -29,17 +37,57 @@ impl Pathtracer {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_path(&self, point: Point, direction: Unit<Vector>) -> Path {
|
fn cast_ray(&self, ray: Ray) -> Option<(f32, &Object)> {
|
||||||
let mut res = Path::new(point);
|
self.scene.bvh.walk(&ray, &self.scene.objects)
|
||||||
for _ in 0..self.scene.reflection_limit {
|
}
|
||||||
// FIXME:
|
|
||||||
// * cast_ray: if no intersection, return the empty path
|
fn construct_light_path(&self) -> LightPath {
|
||||||
// * look-up information at intersection
|
let mut rng = rand::thread_rng();
|
||||||
// * append to path
|
let num_lights = self.scene.lights.points.len() + self.scene.lights.spots.len();
|
||||||
// * start again with new origin
|
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
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn illuminate(
|
||||||
|
&self,
|
||||||
|
point: Point,
|
||||||
|
properties: LightProperties,
|
||||||
|
path: LightPath,
|
||||||
|
) -> LinearColor {
|
||||||
|
path.points.iter().map(|p| p.luminance.clone()).sum()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Renderer for Pathtracer {
|
impl Renderer for Pathtracer {
|
||||||
|
|
|
@ -8,13 +8,13 @@ use std::iter::Iterator;
|
||||||
/// A struct centralizing the light computation logic.
|
/// A struct centralizing the light computation logic.
|
||||||
pub struct LightAggregate {
|
pub struct LightAggregate {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
ambients: Vec<AmbientLight>,
|
pub(crate) ambients: Vec<AmbientLight>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
directionals: Vec<DirectionalLight>,
|
pub(crate) directionals: Vec<DirectionalLight>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
points: Vec<PointLight>,
|
pub(crate) points: Vec<PointLight>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
spots: Vec<SpotLight>,
|
pub(crate) spots: Vec<SpotLight>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LightAggregate {
|
impl LightAggregate {
|
||||||
|
|
Loading…
Reference in a new issue