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:
parent
cefbc2873b
commit
77cf877210
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue