Added Phong integrator (actually only computing lambertion yet)
This commit is contained in:
parent
4f60719523
commit
d9af6dad94
|
|
@ -1,6 +1,7 @@
|
||||||
use nalgebra::{convert, RealField, Vector3};
|
use nalgebra::{clamp, convert, RealField, Vector3};
|
||||||
|
|
||||||
use super::image::OutputImage;
|
use super::image::OutputImage;
|
||||||
|
use super::integrators::{DirectionalLight, Integrator, PhongIntegrator};
|
||||||
use super::raycasting::Ray;
|
use super::raycasting::Ray;
|
||||||
use super::scene::Scene;
|
use super::scene::Scene;
|
||||||
|
|
||||||
|
|
@ -59,12 +60,22 @@ impl<T: RealField> ImageSampler<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_scene<T: RealField>(output_image: &mut OutputImage, scene: &Scene<T>) {
|
pub fn render_scene<T: RealField>(output_image: &mut OutputImage, scene: &Scene<T>)
|
||||||
|
where
|
||||||
|
f32: From<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(),
|
||||||
scene.camera_location,
|
scene.camera_location,
|
||||||
);
|
);
|
||||||
|
let integrator = PhongIntegrator::<T> {
|
||||||
|
ambient_light: convert(0.1),
|
||||||
|
lights: vec![DirectionalLight {
|
||||||
|
direction: Vector3::new(convert(1.0), convert(1.0), convert(-1.0)).normalize(),
|
||||||
|
intensity: convert(0.3),
|
||||||
|
}],
|
||||||
|
};
|
||||||
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);
|
||||||
|
|
@ -79,9 +90,10 @@ pub fn render_scene<T: RealField>(output_image: &mut OutputImage, scene: &Scene<
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let gray = match hit {
|
let gray = match hit {
|
||||||
None => 0,
|
None => convert(0.0),
|
||||||
Some(_) => 255,
|
Some(intersection_info) => integrator.integrate(&intersection_info),
|
||||||
};
|
};
|
||||||
|
let gray = f32::from(clamp(gray * convert(255.0), convert(0.0), convert(255.0))) as u8;
|
||||||
output_image.set_color(row, column, gray, gray, gray);
|
output_image.set_color(row, column, gray, gray, gray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ pub mod raycasting;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod scene;
|
pub mod scene;
|
||||||
|
pub mod integrators;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ impl<T: RealField> Ray<T> {
|
||||||
pub struct IntersectionInfo<T: RealField> {
|
pub struct IntersectionInfo<T: RealField> {
|
||||||
pub distance: T,
|
pub distance: T,
|
||||||
pub location: Vector3<T>,
|
pub location: Vector3<T>,
|
||||||
|
pub normal: Vector3<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Intersect<T: RealField> {
|
pub trait Intersect<T: RealField> {
|
||||||
|
|
@ -44,15 +45,30 @@ impl<T: RealField> Intersect<T> for Sphere<T> {
|
||||||
fn intersect(&self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
fn intersect(&self, ray: &Ray<T>) -> Option<IntersectionInfo<T>> {
|
||||||
// t0/p0 is the point on the ray that's closest to the centre of the sphere
|
// t0/p0 is the point on the ray that's closest to the centre of the sphere
|
||||||
let t0 = (self.centre - ray.origin).dot(&ray.direction);
|
let t0 = (self.centre - ray.origin).dot(&ray.direction);
|
||||||
let p0 = ray.point_at(t0);
|
let delta_squared =
|
||||||
if (self.centre - p0).norm() <= self.radius {
|
t0 * t0 - ((ray.origin - self.centre).norm_squared() - self.radius * self.radius);
|
||||||
Some(IntersectionInfo {
|
if delta_squared > self.radius {
|
||||||
distance: t0,
|
//No initersection
|
||||||
location: p0,
|
return None;
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
let delta = delta_squared.sqrt();
|
||||||
|
let distance = if (self.centre - ray.origin).norm() <= self.radius {
|
||||||
|
// radius origin is inside sphere
|
||||||
|
t0 + delta
|
||||||
|
} else {
|
||||||
|
t0 - delta
|
||||||
|
};
|
||||||
|
if distance < T::zero() {
|
||||||
|
// Sphere is behind ray origin
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
let location = ray.point_at(distance);
|
||||||
|
let normal = (location - self.centre).normalize();
|
||||||
|
Some(IntersectionInfo {
|
||||||
|
distance,
|
||||||
|
location,
|
||||||
|
normal,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,6 +107,7 @@ impl<T: RealField> Intersect<T> for Plane<T> {
|
||||||
Some(IntersectionInfo {
|
Some(IntersectionInfo {
|
||||||
distance: t,
|
distance: t,
|
||||||
location: ray.point_at(t),
|
location: ray.point_at(t),
|
||||||
|
normal: self.normal,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue