Factor out Sampler struct and add shadow casting

There are now bad rendering artifacts which I believe are caused
by precision issues.
This commit is contained in:
Matthew Gordon 2019-11-23 21:36:59 -05:00
parent cefbc2873b
commit 77cf877210
4 changed files with 42 additions and 19 deletions

View File

@ -4,6 +4,7 @@ use super::colour::{ColourRgbF, NamedColour};
use super::image::ImageRgbF; use super::image::ImageRgbF;
use super::integrators::{DirectionalLight, Integrator, PhongIntegrator}; use super::integrators::{DirectionalLight, Integrator, PhongIntegrator};
use super::raycasting::Ray; use super::raycasting::Ray;
use super::sampler::Sampler;
use super::scene::Scene; use super::scene::Scene;
struct ImageSampler<T: RealField> { struct ImageSampler<T: RealField> {
@ -61,7 +62,7 @@ impl<T: RealField> ImageSampler<T> {
} }
} }
pub fn render_scene<'a, T: RealField>(output_image: &mut ImageRgbF<T>, scene: &Scene<T>) { pub fn render_scene<T: RealField>(output_image: &mut ImageRgbF<T>, scene: &Scene<T>) {
let image_sampler = ImageSampler::new( let image_sampler = ImageSampler::new(
output_image.get_width(), output_image.get_width(),
output_image.get_height(), output_image.get_height(),
@ -76,22 +77,14 @@ pub fn render_scene<'a, T: RealField>(output_image: &mut ImageRgbF<T>, scene: &S
colour: ColourRgbF::from_named(NamedColour::White) * directional_intensity, colour: ColourRgbF::from_named(NamedColour::White) * directional_intensity,
}], }],
}; };
let sampler = Sampler { scene };
for column in 0..output_image.get_width() { for column in 0..output_image.get_width() {
for row in 0..output_image.get_height() { for row in 0..output_image.get_height() {
let ray = image_sampler.ray_for_pixel(row, column); let ray = image_sampler.ray_for_pixel(row, column);
let hit = scene let hit = sampler.sample(&ray);
.objects
.iter()
.flat_map(|object| object.intersect(&ray))
.min_by(
|a, b| match PartialOrd::partial_cmp(&a.distance, &b.distance) {
None => std::cmp::Ordering::Less,
Some(ordering) => ordering,
},
);
let colour = match hit { let colour = match hit {
None => ColourRgbF::from_named(NamedColour::Black), None => ColourRgbF::from_named(NamedColour::Black),
Some(intersection_info) => integrator.integrate(&intersection_info), Some(intersection_info) => integrator.integrate(&sampler, &intersection_info),
}; };
output_image.set_colour(row, column, colour); output_image.set_colour(row, column, colour);
} }

View File

@ -1,10 +1,11 @@
use nalgebra::{RealField, Vector3}; use nalgebra::{RealField, Vector3};
use super::colour::ColourRgbF; use super::colour::ColourRgbF;
use super::raycasting::IntersectionInfo; use super::raycasting::{IntersectionInfo, Ray};
use super::sampler::Sampler;
pub trait Integrator<T: RealField> { pub trait Integrator<T: RealField> {
fn integrate(&self, info: &IntersectionInfo<T>) -> ColourRgbF<T>; fn integrate(&self, sampler: &Sampler<T>, info: &IntersectionInfo<T>) -> ColourRgbF<T>;
} }
pub struct DirectionalLight<T: RealField> { pub struct DirectionalLight<T: RealField> {
@ -18,13 +19,18 @@ pub struct PhongIntegrator<T: RealField> {
} }
impl<T: RealField> Integrator<T> for PhongIntegrator<T> { impl<T: RealField> Integrator<T> for PhongIntegrator<T> {
fn integrate(&self, info: &IntersectionInfo<T>) -> ColourRgbF<T> { fn integrate(&self, sampler: &Sampler<T>, info: &IntersectionInfo<T>) -> ColourRgbF<T> {
self.lights self.lights
.iter() .iter()
.map(|light| { .map(
info.material.bsdf()(info.retro, light.direction, light.colour) |light| match sampler.sample(&Ray::new(info.location, light.direction)) {
* light.direction.dot(&info.normal) Some(_) => self.ambient_light,
}) None => {
info.material.bsdf()(info.retro, light.direction, light.colour)
* light.direction.dot(&info.normal)
}
},
)
.fold(self.ambient_light, |a, b| a + b) .fold(self.ambient_light, |a, b| a + b)
} }
} }

View File

@ -4,4 +4,5 @@ pub mod image;
pub mod integrators; pub mod integrators;
pub mod materials; pub mod materials;
pub mod raycasting; pub mod raycasting;
pub mod sampler;
pub mod scene; pub mod scene;

23
src/sampler.rs Normal file
View File

@ -0,0 +1,23 @@
use super::raycasting::{IntersectionInfo, Ray};
use super::scene::Scene;
use nalgebra::RealField;
pub struct Sampler<'a, T: RealField> {
pub scene: &'a Scene<T>,
}
impl<'a, T: RealField> Sampler<'a, T> {
pub fn sample(&self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
self.scene
.objects
.iter()
.flat_map(|object| object.intersect(&ray))
.min_by(
|a, b| match PartialOrd::partial_cmp(&a.distance, &b.distance) {
None => std::cmp::Ordering::Less,
Some(ordering) => ordering,
},
)
}
}