Shapes can now be colours other than gray
This commit is contained in:
parent
f193fbf84b
commit
f13b585bfe
|
|
@ -1,5 +1,6 @@
|
||||||
use nalgebra::{clamp, convert, RealField, Vector3};
|
use nalgebra::{convert, RealField, Vector3};
|
||||||
|
|
||||||
|
use super::colour::{ClampingToneMapper, NamedColour, NormalizedAsByte, ToneMapper};
|
||||||
use super::image::OutputImage;
|
use super::image::OutputImage;
|
||||||
use super::integrators::{DirectionalLight, Integrator, PhongIntegrator};
|
use super::integrators::{DirectionalLight, Integrator, PhongIntegrator};
|
||||||
use super::raycasting::Ray;
|
use super::raycasting::Ray;
|
||||||
|
|
@ -60,8 +61,10 @@ impl<T: RealField> ImageSampler<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_scene<T: RealField>(output_image: &mut OutputImage, scene: &Scene<T>)
|
pub fn render_scene<T: RealField + NormalizedAsByte>(
|
||||||
where
|
output_image: &mut OutputImage,
|
||||||
|
scene: &Scene<T>,
|
||||||
|
) where
|
||||||
f32: From<T>,
|
f32: From<T>,
|
||||||
{
|
{
|
||||||
let image_sampler = ImageSampler::new(
|
let image_sampler = ImageSampler::new(
|
||||||
|
|
@ -76,6 +79,7 @@ where
|
||||||
intensity: convert(0.3),
|
intensity: convert(0.3),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
|
let tone_mapper = ClampingToneMapper {};
|
||||||
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);
|
||||||
|
|
@ -89,12 +93,12 @@ where
|
||||||
Some(ordering) => ordering,
|
Some(ordering) => ordering,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let gray = match hit {
|
let colour = match hit {
|
||||||
None => convert(0.0),
|
None => NamedColour::Black.as_colourrgb(),
|
||||||
Some(intersection_info) => integrator.integrate(&intersection_info),
|
Some(intersection_info) => integrator.integrate(&intersection_info),
|
||||||
};
|
};
|
||||||
let gray = f32::from(clamp(gray * convert(255.0), convert(0.0), convert(255.0))) as u8;
|
let colour = tone_mapper.apply_tone_mapping(&colour);
|
||||||
output_image.set_color(row, column, gray, gray, gray);
|
output_image.set_color(row, column, colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -102,7 +106,9 @@ where
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::materials::Material;
|
||||||
use crate::raycasting::{Intersect, IntersectionInfo, Plane};
|
use crate::raycasting::{Intersect, IntersectionInfo, Plane};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod imagesampler {
|
mod imagesampler {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -123,13 +129,18 @@ mod tests {
|
||||||
fn ray_for_pixel_returns_value_that_intersects_film_plane_at_expected_location() {
|
fn ray_for_pixel_returns_value_that_intersects_film_plane_at_expected_location() {
|
||||||
let target = ImageSampler::new(800, 600, Vector3::new(0.0, 0.0, 0.0));
|
let target = ImageSampler::new(800, 600, Vector3::new(0.0, 0.0, 0.0));
|
||||||
let ray = target.ray_for_pixel(100, 200);
|
let ray = target.ray_for_pixel(100, 200);
|
||||||
let film_plane = Plane::new(Vector3::new(0.0, 0.0, 1.0), target.film_distance);
|
let film_plane = Plane::new(
|
||||||
|
Vector3::new(0.0, 0.0, 1.0),
|
||||||
|
target.film_distance,
|
||||||
|
Material::<f64>::new_dummy(),
|
||||||
|
);
|
||||||
let point_on_film_plane = match film_plane.intersect(&ray) {
|
let point_on_film_plane = match film_plane.intersect(&ray) {
|
||||||
Some(IntersectionInfo {
|
Some(IntersectionInfo {
|
||||||
location,
|
location,
|
||||||
distance: _,
|
distance: _,
|
||||||
normal: _,
|
normal: _,
|
||||||
retro: _,
|
retro: _,
|
||||||
|
material: _,
|
||||||
}) => location,
|
}) => location,
|
||||||
None => panic!(),
|
None => panic!(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use nalgebra::{clamp, convert, RealField, Vector3};
|
use nalgebra::{clamp, convert, RealField, Vector3};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ColourRGB<T: RealField> {
|
pub struct ColourRGB<T: RealField> {
|
||||||
values: Vector3<T>,
|
values: Vector3<T>,
|
||||||
}
|
}
|
||||||
|
|
@ -16,6 +17,10 @@ impl<T: RealField + NormalizedAsByte> ColourRGB<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_vector3(v: &Vector3<T>) -> ColourRGB<T> {
|
||||||
|
ColourRGB { values: *v }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn red(&self) -> T {
|
pub fn red(&self) -> T {
|
||||||
self.values[0]
|
self.values[0]
|
||||||
}
|
}
|
||||||
|
|
@ -83,11 +88,12 @@ pub enum NamedColour {
|
||||||
Navy,
|
Navy,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn named_colour<T: RealField+NormalizedAsByte>(colour: NamedColour) -> ColourRGB<T> {
|
impl NamedColour {
|
||||||
|
pub fn as_colourrgb<T: RealField + NormalizedAsByte>(self) -> ColourRGB<T> {
|
||||||
let zero: T = convert(0.0);
|
let zero: T = convert(0.0);
|
||||||
let half: T = convert(0.5);
|
let half: T = convert(0.5);
|
||||||
let one: T = convert(1.0);
|
let one: T = convert(1.0);
|
||||||
match colour {
|
match self {
|
||||||
NamedColour::Black => ColourRGB::new(zero, zero, zero),
|
NamedColour::Black => ColourRGB::new(zero, zero, zero),
|
||||||
NamedColour::White => ColourRGB::new(one, one, one),
|
NamedColour::White => ColourRGB::new(one, one, one),
|
||||||
NamedColour::Red => ColourRGB::new(one, zero, zero),
|
NamedColour::Red => ColourRGB::new(one, zero, zero),
|
||||||
|
|
@ -99,11 +105,12 @@ pub fn named_colour<T: RealField+NormalizedAsByte>(colour: NamedColour) -> Colou
|
||||||
NamedColour::Gray => ColourRGB::new(half, half, half),
|
NamedColour::Gray => ColourRGB::new(half, half, half),
|
||||||
NamedColour::Maroon => ColourRGB::new(half, zero, zero),
|
NamedColour::Maroon => ColourRGB::new(half, zero, zero),
|
||||||
NamedColour::Olive => ColourRGB::new(half, half, zero),
|
NamedColour::Olive => ColourRGB::new(half, half, zero),
|
||||||
NamedColour::Green => ColourRGB::new(half, half, half),
|
NamedColour::Green => ColourRGB::new(zero, half, zero),
|
||||||
NamedColour::Purple => ColourRGB::new(half, zero, half),
|
NamedColour::Purple => ColourRGB::new(half, zero, half),
|
||||||
NamedColour::Teal => ColourRGB::new(zero, half, half),
|
NamedColour::Teal => ColourRGB::new(zero, half, half),
|
||||||
NamedColour::Navy => ColourRGB::new(zero, zero, half),
|
NamedColour::Navy => ColourRGB::new(zero, zero, half),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NormalizedAsByte for f32 {
|
impl NormalizedAsByte for f32 {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use super::colour::ColourRGB24;
|
||||||
|
|
||||||
pub struct OutputImage {
|
pub struct OutputImage {
|
||||||
pixel_data: Vec<u8>,
|
pixel_data: Vec<u8>,
|
||||||
width: u32,
|
width: u32,
|
||||||
|
|
@ -22,12 +24,10 @@ impl OutputImage {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_color(&mut self, row: u32, column: u32, red: u8, green: u8, blue: u8) {
|
pub fn set_color(&mut self, row: u32, column: u32, colour: ColourRGB24) {
|
||||||
assert!(row < self.height && column < self.width);
|
assert!(row < self.height && column < self.width);
|
||||||
let index = (((self.height - (row + 1)) * self.width + column) * self.channels) as usize;
|
let index = (((self.height - (row + 1)) * self.width + column) * self.channels) as usize;
|
||||||
self.pixel_data[index] = red;
|
self.pixel_data[index..index+3].copy_from_slice(&colour.values[..]);
|
||||||
self.pixel_data[index + 1] = green;
|
|
||||||
self.pixel_data[index + 2] = blue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pixel_data(&self) -> &Vec<u8> {
|
pub fn get_pixel_data(&self) -> &Vec<u8> {
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,28 @@
|
||||||
use nalgebra::{RealField, Vector3};
|
use nalgebra::{RealField, Vector3};
|
||||||
|
|
||||||
|
use super::colour::{ColourRGB, NormalizedAsByte};
|
||||||
use super::raycasting::IntersectionInfo;
|
use super::raycasting::IntersectionInfo;
|
||||||
|
|
||||||
pub trait Integrator<T: RealField> {
|
pub trait Integrator<T: RealField + NormalizedAsByte> {
|
||||||
fn integrate(&self, info: &IntersectionInfo<T>) -> T;
|
fn integrate(&self, info: &IntersectionInfo<T>) -> ColourRGB<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DirectionalLight<T: RealField> {
|
pub struct DirectionalLight<T: RealField + NormalizedAsByte> {
|
||||||
pub direction: Vector3<T>,
|
pub direction: Vector3<T>,
|
||||||
pub intensity: T,
|
pub intensity: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PhongIntegrator<T: RealField> {
|
pub struct PhongIntegrator<T: RealField + NormalizedAsByte> {
|
||||||
pub ambient_light: T,
|
pub ambient_light: T,
|
||||||
pub lights: Vec<DirectionalLight<T>>,
|
pub lights: Vec<DirectionalLight<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RealField> Integrator<T> for PhongIntegrator<T> {
|
impl<T: RealField + NormalizedAsByte> Integrator<T> for PhongIntegrator<T> {
|
||||||
fn integrate(&self, info: &IntersectionInfo<T>) -> T {
|
fn integrate(&self, info: &IntersectionInfo<T>) -> ColourRGB<T> {
|
||||||
self.lights
|
let intensity = self.lights
|
||||||
.iter()
|
.iter()
|
||||||
.map(|light| light.intensity * light.direction.dot(&info.normal))
|
.map(|light| light.intensity * light.direction.dot(&info.normal))
|
||||||
.fold(self.ambient_light, |a, b| a + b)
|
.fold(self.ambient_light, |a, b| a + b);
|
||||||
|
ColourRGB::from_vector3(&(info.material.colour.as_vector3() * intensity))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/main.rs
20
src/main.rs
|
|
@ -7,7 +7,9 @@ use std::time::Duration;
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
|
|
||||||
|
use vanrijn::materials::Material;
|
||||||
use vanrijn::camera::render_scene;
|
use vanrijn::camera::render_scene;
|
||||||
|
use vanrijn::colour::NamedColour;
|
||||||
use vanrijn::image::OutputImage;
|
use vanrijn::image::OutputImage;
|
||||||
use vanrijn::raycasting::{Plane, Sphere};
|
use vanrijn::raycasting::{Plane, Sphere};
|
||||||
use vanrijn::scene::Scene;
|
use vanrijn::scene::Scene;
|
||||||
|
|
@ -56,8 +58,22 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let scene = Scene {
|
let scene = Scene {
|
||||||
camera_location: Vector3::new(0.0, 0.0, 0.0),
|
camera_location: Vector3::new(0.0, 0.0, 0.0),
|
||||||
objects: vec![
|
objects: vec![
|
||||||
Box::new(Plane::new(Vector3::new(0.0, 1.0, 0.0), -2.0)),
|
Box::new(Plane::new(
|
||||||
Box::new(Sphere::new(Vector3::new(0.0, 1.0, 5.0), 1.0)),
|
Vector3::new(0.0, 1.0, 0.0),
|
||||||
|
-2.0,
|
||||||
|
Material {
|
||||||
|
colour: NamedColour::Green.as_colourrgb(),
|
||||||
|
smoothness: 0.0,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Box::new(Sphere::new(
|
||||||
|
Vector3::new(0.0, 1.0, 5.0),
|
||||||
|
1.0,
|
||||||
|
Material {
|
||||||
|
colour: NamedColour::Blue.as_colourrgb(),
|
||||||
|
smoothness: 0.7,
|
||||||
|
},
|
||||||
|
))
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
render_scene(&mut output_image, &scene);
|
render_scene(&mut output_image, &scene);
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,18 @@
|
||||||
use nalgebra::RealField;
|
use nalgebra::RealField;
|
||||||
|
|
||||||
use super::colour::ColourRGB;
|
use super::colour::{ColourRGB, NormalizedAsByte};
|
||||||
|
|
||||||
pub struct PhongMaterial<T: RealField> {
|
#[derive(Debug)]
|
||||||
|
pub struct Material<T: RealField> {
|
||||||
pub colour: ColourRGB<T>,
|
pub colour: ColourRGB<T>,
|
||||||
pub smoothness: T,
|
pub smoothness: T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: RealField+NormalizedAsByte> Material<T> {
|
||||||
|
pub fn new_dummy() -> Material<T> {
|
||||||
|
Material {
|
||||||
|
colour: ColourRGB::new(T::one(), T::one(), T::one()),
|
||||||
|
smoothness: T::zero(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use nalgebra::{convert, RealField, Vector3};
|
use nalgebra::{convert, RealField, Vector3};
|
||||||
|
|
||||||
|
use super::materials::Material;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Ray<T: RealField> {
|
pub struct Ray<T: RealField> {
|
||||||
origin: Vector3<T>,
|
origin: Vector3<T>,
|
||||||
|
|
@ -20,11 +22,12 @@ impl<T: RealField> Ray<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct IntersectionInfo<T: RealField> {
|
pub struct IntersectionInfo<'a, T: RealField> {
|
||||||
pub distance: T,
|
pub distance: T,
|
||||||
pub location: Vector3<T>,
|
pub location: Vector3<T>,
|
||||||
pub normal: Vector3<T>,
|
pub normal: Vector3<T>,
|
||||||
pub retro: Vector3<T>,
|
pub retro: Vector3<T>,
|
||||||
|
pub material: &'a Material<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Intersect<T: RealField> {
|
pub trait Intersect<T: RealField> {
|
||||||
|
|
@ -34,11 +37,16 @@ pub trait Intersect<T: RealField> {
|
||||||
pub struct Sphere<T: RealField> {
|
pub struct Sphere<T: RealField> {
|
||||||
centre: Vector3<T>,
|
centre: Vector3<T>,
|
||||||
radius: T,
|
radius: T,
|
||||||
|
material: Material<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RealField> Sphere<T> {
|
impl<T: RealField> Sphere<T> {
|
||||||
pub fn new(centre: Vector3<T>, radius: T) -> Sphere<T> {
|
pub fn new(centre: Vector3<T>, radius: T, material: Material<T>) -> Sphere<T> {
|
||||||
Sphere { centre, radius }
|
Sphere {
|
||||||
|
centre,
|
||||||
|
radius,
|
||||||
|
material,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +84,7 @@ impl<T: RealField> Intersect<T> for Sphere<T> {
|
||||||
location,
|
location,
|
||||||
normal,
|
normal,
|
||||||
retro,
|
retro,
|
||||||
|
material: &self.material,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -83,14 +92,16 @@ impl<T: RealField> Intersect<T> for Sphere<T> {
|
||||||
pub struct Plane<T: RealField> {
|
pub struct Plane<T: RealField> {
|
||||||
normal: Vector3<T>,
|
normal: Vector3<T>,
|
||||||
distance_from_origin: T,
|
distance_from_origin: T,
|
||||||
|
material: Material<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RealField> Plane<T> {
|
impl<T: RealField> Plane<T> {
|
||||||
pub fn new(normal: Vector3<T>, distance_from_origin: T) -> Plane<T> {
|
pub fn new(normal: Vector3<T>, distance_from_origin: T, material: Material<T>) -> Plane<T> {
|
||||||
normal.normalize();
|
normal.normalize();
|
||||||
Plane {
|
Plane {
|
||||||
normal,
|
normal,
|
||||||
distance_from_origin,
|
distance_from_origin,
|
||||||
|
material,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,6 +128,7 @@ impl<T: RealField> Intersect<T> for Plane<T> {
|
||||||
location: ray.point_at(t),
|
location: ray.point_at(t),
|
||||||
normal: self.normal,
|
normal: self.normal,
|
||||||
retro: -ray.direction,
|
retro: -ray.direction,
|
||||||
|
material: &self.material,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -176,55 +188,56 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_intersects_sphere() {
|
fn ray_intersects_sphere() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
||||||
let s = Sphere::new(Vector3::new(1.5, 1.5, 15.0), 5.0);
|
let s = Sphere::new(Vector3::new(1.5, 1.5, 15.0), 5.0, Material::new_dummy());
|
||||||
assert_matches!(s.intersect(&r), Some(_));
|
assert_matches!(s.intersect(&r), Some(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_does_not_intersect_sphere_when_sphere_is_in_front() {
|
fn ray_does_not_intersect_sphere_when_sphere_is_in_front() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
||||||
let s = Sphere::new(Vector3::new(-5.0, 1.5, 15.0), 5.0);
|
let s = Sphere::new(Vector3::new(-5.0, 1.5, 15.0), 5.0, Material::new_dummy());
|
||||||
assert_matches!(s.intersect(&r), None);
|
assert_matches!(s.intersect(&r), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_does_not_intersect_sphere_when_sphere_is_behind() {
|
fn ray_does_not_intersect_sphere_when_sphere_is_behind() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
||||||
let s = Sphere::new(Vector3::new(1.5, 1.5, -15.0), 5.0);
|
let s = Sphere::new(Vector3::new(1.5, 1.5, -15.0), 5.0, Material::new_dummy());
|
||||||
assert_matches!(s.intersect(&r), None);
|
assert_matches!(s.intersect(&r), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_intersects_sphere_when_origin_is_inside() {
|
fn ray_intersects_sphere_when_origin_is_inside() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(0.0, 0.0, 1.0));
|
||||||
let s = Sphere::new(Vector3::new(1.5, 1.5, 2.0), 5.0);
|
let s = Sphere::new(Vector3::new(1.5, 1.5, 2.0), 5.0, Material::new_dummy());
|
||||||
assert_matches!(s.intersect(&r), Some(_));
|
assert_matches!(s.intersect(&r), Some(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_intersects_plane() {
|
fn ray_intersects_plane() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(-1.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(-1.0, 0.0, 1.0));
|
||||||
let p = Plane::new(Vector3::new(1.0, 0.0, 0.0), -5.0);
|
let p = Plane::new(Vector3::new(1.0, 0.0, 0.0), -5.0, Material::new_dummy());
|
||||||
assert_matches!(p.intersect(&r), Some(_));
|
assert_matches!(p.intersect(&r), Some(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ray_does_not_intersect_plane() {
|
fn ray_does_not_intersect_plane() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(1.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(1.0, 0.0, 1.0));
|
||||||
let p = Plane::new(Vector3::new(1.0, 0.0, 0.0), -5.0);
|
let p = Plane::new(Vector3::new(1.0, 0.0, 0.0), -5.0, Material::new_dummy());
|
||||||
assert_matches!(p.intersect(&r), None);
|
assert_matches!(p.intersect(&r), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn intersection_point_is_on_plane() {
|
fn intersection_point_is_on_plane() {
|
||||||
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(-1.0, 0.0, 1.0));
|
let r = Ray::new(Vector3::new(1.0, 2.0, 3.0), Vector3::new(-1.0, 0.0, 1.0));
|
||||||
let p = Plane::new(Vector3::new(1.0, 0.0, 0.0), -5.0);
|
let p = Plane::new(Vector3::new(1.0, 0.0, 0.0), -5.0, Material::new_dummy());
|
||||||
match p.intersect(&r) {
|
match p.intersect(&r) {
|
||||||
Some(IntersectionInfo {
|
Some(IntersectionInfo {
|
||||||
distance: _,
|
distance: _,
|
||||||
location,
|
location,
|
||||||
normal: _,
|
normal: _,
|
||||||
retro: _,
|
retro: _,
|
||||||
|
material: _,
|
||||||
}) => assert!((location.x - (-5.0f64)).abs() < 0.0000000001),
|
}) => assert!((location.x - (-5.0f64)).abs() < 0.0000000001),
|
||||||
None => panic!(),
|
None => panic!(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue