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::integrators::{DirectionalLight, Integrator, PhongIntegrator};
|
||||
use super::raycasting::Ray;
|
||||
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(
|
||||
output_image.get_width(),
|
||||
output_image.get_height(),
|
||||
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 row in 0..output_image.get_height() {
|
||||
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 {
|
||||
None => 0,
|
||||
Some(_) => 255,
|
||||
None => convert(0.0),
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,3 +2,4 @@ pub mod raycasting;
|
|||
pub mod image;
|
||||
pub mod camera;
|
||||
pub mod scene;
|
||||
pub mod integrators;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ impl<T: RealField> Ray<T> {
|
|||
pub struct IntersectionInfo<T: RealField> {
|
||||
pub distance: T,
|
||||
pub location: Vector3<T>,
|
||||
pub normal: Vector3<T>,
|
||||
}
|
||||
|
||||
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>> {
|
||||
// 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 p0 = ray.point_at(t0);
|
||||
if (self.centre - p0).norm() <= self.radius {
|
||||
Some(IntersectionInfo {
|
||||
distance: t0,
|
||||
location: p0,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
let delta_squared =
|
||||
t0 * t0 - ((ray.origin - self.centre).norm_squared() - self.radius * self.radius);
|
||||
if delta_squared > self.radius {
|
||||
//No initersection
|
||||
return 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 {
|
||||
distance: t,
|
||||
location: ray.point_at(t),
|
||||
normal: self.normal,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue