WIP: pathtrace soup
This commit is contained in:
parent
8afc5ba382
commit
c5867bca84
|
@ -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<Vector>, 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::*;
|
||||
|
||||
|
|
|
@ -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<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.
|
||||
///
|
||||
/// # 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 <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)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
|
|
@ -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<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.
|
||||
///
|
||||
/// # 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 <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)]
|
||||
struct SerializedSpotLight {
|
||||
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;
|
||||
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::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<Vector>) -> 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 {
|
||||
|
|
|
@ -8,13 +8,13 @@ use std::iter::Iterator;
|
|||
/// A struct centralizing the light computation logic.
|
||||
pub struct LightAggregate {
|
||||
#[serde(default)]
|
||||
ambients: Vec<AmbientLight>,
|
||||
pub(crate) ambients: Vec<AmbientLight>,
|
||||
#[serde(default)]
|
||||
directionals: Vec<DirectionalLight>,
|
||||
pub(crate) directionals: Vec<DirectionalLight>,
|
||||
#[serde(default)]
|
||||
points: Vec<PointLight>,
|
||||
pub(crate) points: Vec<PointLight>,
|
||||
#[serde(default)]
|
||||
spots: Vec<SpotLight>,
|
||||
pub(crate) spots: Vec<SpotLight>,
|
||||
}
|
||||
|
||||
impl LightAggregate {
|
||||
|
|
Loading…
Reference in a new issue