shapes: create generic Shape object with Sphere implementation.
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
7741766635
commit
c0e422a7eb
@ -4,7 +4,7 @@ use rtchallenge::{
|
||||
canvas::Canvas,
|
||||
matrices::Matrix4x4,
|
||||
rays::Ray,
|
||||
spheres::{intersect, Sphere},
|
||||
shapes::{intersect, Shape},
|
||||
tuples::{Color, Tuple},
|
||||
Float,
|
||||
};
|
||||
@ -20,7 +20,7 @@ fn main() -> Result<()> {
|
||||
let pixel_size = wall_size / w as Float;
|
||||
let half = wall_size / 2.;
|
||||
let color = Color::new(1., 0., 0.);
|
||||
let mut shape = Sphere::default();
|
||||
let mut shape = Shape::sphere();
|
||||
shape.set_transform(
|
||||
Matrix4x4::shearing(1., 0., 0., 0., 0., 0.) * Matrix4x4::scaling(0.5, 1., 1.0),
|
||||
);
|
||||
|
||||
@ -5,7 +5,7 @@ use rtchallenge::{
|
||||
lights::PointLight,
|
||||
materials::{lighting, Material},
|
||||
rays::Ray,
|
||||
spheres::{intersect, Sphere},
|
||||
shapes::{intersect, Shape},
|
||||
tuples::{Color, Tuple},
|
||||
Float, WHITE,
|
||||
};
|
||||
@ -20,7 +20,7 @@ fn main() -> Result<()> {
|
||||
let wall_size = 7.;
|
||||
let pixel_size = wall_size / w as Float;
|
||||
let half = wall_size / 2.;
|
||||
let mut shape = Sphere::default();
|
||||
let mut shape = Shape::sphere();
|
||||
shape.material = Material {
|
||||
color: Color::new(1., 0.2, 1.),
|
||||
specular: 0.5,
|
||||
|
||||
@ -9,7 +9,7 @@ use rtchallenge::{
|
||||
lights::PointLight,
|
||||
materials::Material,
|
||||
matrices::Matrix4x4,
|
||||
spheres::Sphere,
|
||||
shapes::Shape,
|
||||
transformations::view_transform,
|
||||
tuples::{Color, Tuple},
|
||||
world::World,
|
||||
@ -39,7 +39,7 @@ fn main() -> Result<()> {
|
||||
camera.set_transform(view_transform(from, to, up));
|
||||
camera.render_strategy = opt.render_strategy;
|
||||
|
||||
let mut floor = Sphere::default();
|
||||
let mut floor = Shape::sphere();
|
||||
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
|
||||
floor.material = Material {
|
||||
color: Color::new(1., 0.9, 0.9),
|
||||
@ -47,7 +47,7 @@ fn main() -> Result<()> {
|
||||
..Material::default()
|
||||
};
|
||||
|
||||
let mut left_wall = Sphere::default();
|
||||
let mut left_wall = Shape::sphere();
|
||||
left_wall.set_transform(
|
||||
Matrix4x4::translation(0., 0., 5.)
|
||||
* Matrix4x4::rotation_y(-PI / 4.)
|
||||
@ -56,7 +56,7 @@ fn main() -> Result<()> {
|
||||
);
|
||||
left_wall.material = floor.material.clone();
|
||||
|
||||
let mut right_wall = Sphere::default();
|
||||
let mut right_wall = Shape::sphere();
|
||||
right_wall.set_transform(
|
||||
Matrix4x4::translation(0., 0., 5.)
|
||||
* Matrix4x4::rotation_y(PI / 4.)
|
||||
@ -65,7 +65,7 @@ fn main() -> Result<()> {
|
||||
);
|
||||
right_wall.material = floor.material.clone();
|
||||
|
||||
let mut middle = Sphere::default();
|
||||
let mut middle = Shape::sphere();
|
||||
middle.set_transform(Matrix4x4::translation(-0.5, 1., 0.5));
|
||||
middle.material = Material {
|
||||
color: Color::new(0.1, 1., 0.5),
|
||||
@ -74,7 +74,7 @@ fn main() -> Result<()> {
|
||||
..Material::default()
|
||||
};
|
||||
|
||||
let mut right = Sphere::default();
|
||||
let mut right = Shape::sphere();
|
||||
right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5));
|
||||
right.material = Material {
|
||||
color: Color::new(0.5, 1., 0.1),
|
||||
@ -83,7 +83,7 @@ fn main() -> Result<()> {
|
||||
..Material::default()
|
||||
};
|
||||
|
||||
let mut left = Sphere::default();
|
||||
let mut left = Shape::sphere();
|
||||
left.set_transform(
|
||||
Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33),
|
||||
);
|
||||
|
||||
@ -9,7 +9,7 @@ use rtchallenge::{
|
||||
lights::PointLight,
|
||||
materials::Material,
|
||||
matrices::Matrix4x4,
|
||||
spheres::Sphere,
|
||||
shapes::Shape,
|
||||
transformations::view_transform,
|
||||
tuples::{Color, Tuple},
|
||||
world::World,
|
||||
@ -51,7 +51,7 @@ fn main() -> Result<()> {
|
||||
camera.render_strategy = opt.render_strategy;
|
||||
camera.samples_per_pixel = opt.samples;
|
||||
|
||||
let mut floor = Sphere::default();
|
||||
let mut floor = Shape::sphere();
|
||||
floor.set_transform(Matrix4x4::scaling(10., 0.01, 10.));
|
||||
floor.material = Material {
|
||||
color: Color::new(1., 0.9, 0.9),
|
||||
@ -59,7 +59,7 @@ fn main() -> Result<()> {
|
||||
..Material::default()
|
||||
};
|
||||
|
||||
let mut left_wall = Sphere::default();
|
||||
let mut left_wall = Shape::sphere();
|
||||
left_wall.set_transform(
|
||||
Matrix4x4::translation(0., 0., 5.)
|
||||
* Matrix4x4::rotation_y(-PI / 4.)
|
||||
@ -68,7 +68,7 @@ fn main() -> Result<()> {
|
||||
);
|
||||
left_wall.material = floor.material.clone();
|
||||
|
||||
let mut right_wall = Sphere::default();
|
||||
let mut right_wall = Shape::sphere();
|
||||
right_wall.set_transform(
|
||||
Matrix4x4::translation(0., 0., 5.)
|
||||
* Matrix4x4::rotation_y(PI / 4.)
|
||||
@ -77,7 +77,7 @@ fn main() -> Result<()> {
|
||||
);
|
||||
right_wall.material = floor.material.clone();
|
||||
|
||||
let mut middle = Sphere::default();
|
||||
let mut middle = Shape::sphere();
|
||||
middle.set_transform(Matrix4x4::translation(-0.5, 1., 0.5));
|
||||
middle.material = Material {
|
||||
color: Color::new(0.1, 1., 0.5),
|
||||
@ -86,7 +86,7 @@ fn main() -> Result<()> {
|
||||
..Material::default()
|
||||
};
|
||||
|
||||
let mut right = Sphere::default();
|
||||
let mut right = Shape::sphere();
|
||||
right.set_transform(Matrix4x4::translation(1.5, 0.5, -0.5) * Matrix4x4::scaling(0.5, 0.5, 0.5));
|
||||
right.material = Material {
|
||||
color: Color::new(1., 1., 1.),
|
||||
@ -95,7 +95,7 @@ fn main() -> Result<()> {
|
||||
..Material::default()
|
||||
};
|
||||
|
||||
let mut left = Sphere::default();
|
||||
let mut left = Shape::sphere();
|
||||
left.set_transform(
|
||||
Matrix4x4::translation(-1.5, 0.33, -0.75) * Matrix4x4::scaling(0.33, 0.33, 0.33),
|
||||
);
|
||||
|
||||
@ -2,7 +2,7 @@ use std::ops::Index;
|
||||
|
||||
use crate::{
|
||||
rays::Ray,
|
||||
spheres::Sphere,
|
||||
shapes::Shape,
|
||||
tuples::{dot, Tuple},
|
||||
Float, EPSILON,
|
||||
};
|
||||
@ -10,7 +10,7 @@ use crate::{
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Intersection<'i> {
|
||||
pub t: Float,
|
||||
pub object: &'i Sphere,
|
||||
pub object: &'i Shape,
|
||||
}
|
||||
|
||||
impl<'i> Intersection<'i> {
|
||||
@ -18,15 +18,15 @@ impl<'i> Intersection<'i> {
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use rtchallenge::{intersections::Intersection, spheres::Sphere};
|
||||
/// use rtchallenge::{intersections::Intersection, shapes::Shape};
|
||||
///
|
||||
/// // An intersection ecapsulates t and object.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let i = Intersection::new(3.5, &s);
|
||||
/// assert_eq!(i.t, 3.5);
|
||||
/// assert_eq!(i.object, &s);
|
||||
/// ```
|
||||
pub fn new(t: Float, object: &Sphere) -> Intersection {
|
||||
pub fn new(t: Float, object: &Shape) -> Intersection {
|
||||
Intersection { t, object }
|
||||
}
|
||||
}
|
||||
@ -38,11 +38,11 @@ impl<'i> Intersection<'i> {
|
||||
/// use rtchallenge::{
|
||||
/// intersections::{Intersection, Intersections},
|
||||
/// rays::Ray,
|
||||
/// spheres::{intersect, Sphere},
|
||||
/// shapes::{intersect, Shape},
|
||||
/// tuples::Tuple,
|
||||
/// };
|
||||
///
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let i1 = Intersection::new(1., &s);
|
||||
/// let i2 = Intersection::new(2., &s);
|
||||
/// let xs = Intersections::new(vec![i1, i2]);
|
||||
@ -73,12 +73,12 @@ impl<'i> Intersections<'i> {
|
||||
/// use rtchallenge::{
|
||||
/// intersections::{Intersection, Intersections},
|
||||
/// rays::Ray,
|
||||
/// spheres::{intersect, Sphere},
|
||||
/// shapes::{intersect, Shape},
|
||||
/// tuples::Tuple,
|
||||
/// };
|
||||
///
|
||||
/// // The hit, when all intersections have positive t.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let i1 = Intersection::new(1., &s);
|
||||
/// let i2 = Intersection::new(2., &s);
|
||||
/// let xs = Intersections::new(vec![i2, i1.clone()]);
|
||||
@ -86,7 +86,7 @@ impl<'i> Intersections<'i> {
|
||||
/// assert_eq!(i, Some(&i1));
|
||||
///
|
||||
/// // The hit, when some intersections have negative t.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let i1 = Intersection::new(-1., &s);
|
||||
/// let i2 = Intersection::new(1., &s);
|
||||
/// let xs = Intersections::new(vec![i2.clone(), i1]);
|
||||
@ -94,7 +94,7 @@ impl<'i> Intersections<'i> {
|
||||
/// assert_eq!(i, Some(&i2));
|
||||
///
|
||||
/// // The hit, when all intersections have negative t.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let i1 = Intersection::new(-2., &s);
|
||||
/// let i2 = Intersection::new(-1., &s);
|
||||
/// let xs = Intersections::new(vec![i2, i1]);
|
||||
@ -102,7 +102,7 @@ impl<'i> Intersections<'i> {
|
||||
/// assert_eq!(i, None);
|
||||
///
|
||||
/// // The hit is always the lowest nonnegative intersection.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let i1 = Intersection::new(5., &s);
|
||||
/// let i2 = Intersection::new(7., &s);
|
||||
/// let i3 = Intersection::new(-3., &s);
|
||||
@ -138,7 +138,7 @@ impl<'i> Index<usize> for Intersections<'i> {
|
||||
#[derive(Debug)]
|
||||
pub struct PrecomputedData<'i> {
|
||||
pub t: Float,
|
||||
pub object: &'i Sphere,
|
||||
pub object: &'i Shape,
|
||||
pub point: Tuple,
|
||||
pub over_point: Tuple,
|
||||
pub eyev: Tuple,
|
||||
@ -154,14 +154,14 @@ pub struct PrecomputedData<'i> {
|
||||
/// intersections::{prepare_computations, Intersection, Intersections},
|
||||
/// rays::Ray,
|
||||
/// matrices::Matrix4x4,
|
||||
/// spheres::{intersect, Sphere},
|
||||
/// shapes::{intersect, Shape},
|
||||
/// tuples::Tuple,
|
||||
/// EPSILON
|
||||
/// };
|
||||
///
|
||||
/// // Precomputing the state of an intersection.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let shape = Sphere::default();
|
||||
/// let shape = Shape::sphere();
|
||||
/// let i = Intersection::new(4., &shape);
|
||||
/// let comps = prepare_computations(&i, &r);
|
||||
/// assert_eq!(comps.t, i.t);
|
||||
@ -172,14 +172,14 @@ pub struct PrecomputedData<'i> {
|
||||
///
|
||||
/// // The hit, when an intersection occurs on the outside.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let shape = Sphere::default();
|
||||
/// let shape = Shape::sphere();
|
||||
/// let i = Intersection::new(4., &shape);
|
||||
/// let comps = prepare_computations(&i, &r);
|
||||
/// assert_eq!(comps.inside, false);
|
||||
///
|
||||
/// // The hit, when an intersection occurs on the inside.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., 0.), Tuple::vector(0., 0., 1.));
|
||||
/// let shape = Sphere::default();
|
||||
/// let shape = Shape::sphere();
|
||||
/// let i = Intersection::new(1., &shape);
|
||||
/// let comps = prepare_computations(&i, &r);
|
||||
/// assert_eq!(comps.point, Tuple::point(0., 0., 1.));
|
||||
@ -190,7 +190,7 @@ pub struct PrecomputedData<'i> {
|
||||
///
|
||||
/// // The hit should offset the point.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let mut shape = Sphere::default();
|
||||
/// let mut shape = Shape::sphere();
|
||||
/// shape .set_transform(Matrix4x4::translation(0.,0.,1.));
|
||||
/// let i = Intersection::new(5., &shape);
|
||||
/// let comps = prepare_computations(&i, &r);
|
||||
|
||||
@ -5,7 +5,7 @@ pub mod lights;
|
||||
pub mod materials;
|
||||
pub mod matrices;
|
||||
pub mod rays;
|
||||
pub mod spheres;
|
||||
pub mod shapes;
|
||||
pub mod transformations;
|
||||
pub mod tuples;
|
||||
pub mod world;
|
||||
|
||||
@ -7,24 +7,33 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
enum Geometry {
|
||||
/// Sphere represents the unit-sphere (radius of unit 1.) at the origin 0., 0., 0.
|
||||
pub struct Sphere {
|
||||
Sphere,
|
||||
}
|
||||
|
||||
/// Shape represents visible objects. A signal instance of Shape can generically represent one of
|
||||
/// many different shapes based on the value of it's geometry field. Users chose the shape by
|
||||
/// calling the appropriate constructor, i.e. [Shape::sphere].
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Shape {
|
||||
transform: Matrix4x4,
|
||||
inverse_transform: Matrix4x4,
|
||||
pub material: Material,
|
||||
geometry: Geometry,
|
||||
}
|
||||
|
||||
impl Default for Sphere {
|
||||
impl Shape {
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use rtchallenge::{materials::Material, matrices::Matrix4x4, spheres::Sphere};
|
||||
/// use rtchallenge::{materials::Material, matrices::Matrix4x4, shapes::Shape};
|
||||
///
|
||||
/// // A sphere's default transform is the identity matrix.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// assert_eq!(s.transform(), Matrix4x4::identity());
|
||||
///
|
||||
/// // It can be changed by directly setting the transform member.
|
||||
/// let mut s = Sphere::default();
|
||||
/// let mut s = Shape::sphere();
|
||||
/// let t = Matrix4x4::translation(2., 3., 4.);
|
||||
/// s.set_transform(t.clone());
|
||||
/// assert_eq!(s.transform(), t);
|
||||
@ -32,46 +41,46 @@ impl Default for Sphere {
|
||||
/// // Default Sphere has the default material.
|
||||
/// assert_eq!(s.material, Material::default());
|
||||
/// // It can be overridden.
|
||||
/// let mut s = Sphere::default();
|
||||
/// let mut s = Shape::sphere();
|
||||
/// let mut m = Material::default();
|
||||
/// m.ambient = 1.;
|
||||
/// s.material = m.clone();
|
||||
/// assert_eq!(s.material, m);
|
||||
|
||||
/// ```
|
||||
fn default() -> Sphere {
|
||||
Sphere {
|
||||
pub fn sphere() -> Shape {
|
||||
Shape {
|
||||
transform: Matrix4x4::identity(),
|
||||
inverse_transform: Matrix4x4::identity(),
|
||||
material: Material::default(),
|
||||
geometry: Geometry::Sphere,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Sphere {
|
||||
/// Find the normal at the point on the sphere.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// use rtchallenge::{matrices::Matrix4x4, spheres::Sphere, tuples::Tuple,Float};
|
||||
/// use rtchallenge::{
|
||||
/// float::consts::PI, materials::Material, matrices::Matrix4x4, shapes::Shape, tuples::Tuple,
|
||||
/// Float,
|
||||
/// };
|
||||
///
|
||||
/// // Normal on X-axis
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let n = s.normal_at(Tuple::point(1., 0., 0.));
|
||||
/// assert_eq!(n, Tuple::vector(1., 0., 0.));
|
||||
///
|
||||
/// // Normal on Y-axis
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let n = s.normal_at(Tuple::point(0., 1., 0.));
|
||||
/// assert_eq!(n, Tuple::vector(0., 1., 0.));
|
||||
///
|
||||
/// // Normal on Z-axis
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let n = s.normal_at(Tuple::point(0., 0., 1.));
|
||||
/// assert_eq!(n, Tuple::vector(0., 0., 1.));
|
||||
///
|
||||
/// // Normal on a sphere at a nonaxial point.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let n = s.normal_at(Tuple::point(
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
@ -79,10 +88,14 @@ impl Sphere {
|
||||
/// ));
|
||||
/// assert_eq!(
|
||||
/// n,
|
||||
/// Tuple::vector((3. as Float).sqrt() / 3., (3. as Float).sqrt() / 3., (3. as Float).sqrt() / 3.,)
|
||||
/// Tuple::vector(
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
/// )
|
||||
/// );
|
||||
/// // Normals returned are normalized.
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let n = s.normal_at(Tuple::point(
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
/// (3. as Float).sqrt() / 3.,
|
||||
@ -91,23 +104,27 @@ impl Sphere {
|
||||
/// assert_eq!(n, n.normalize());
|
||||
///
|
||||
/// // Compute the normal on a translated sphere.
|
||||
/// let mut s = Sphere::default();
|
||||
/// let mut s = Shape::sphere();
|
||||
/// s.set_transform(Matrix4x4::translation(0., 1., 0.));
|
||||
/// let n = s.normal_at(Tuple::point(0., 1.70711, -0.70711));
|
||||
/// assert_eq!(n, Tuple::vector(0., 0.70711, -0.70711));
|
||||
|
||||
/// // Compute the normal on a transformed sphere.
|
||||
/// use rtchallenge::float::consts::PI;
|
||||
///
|
||||
/// let mut s = Sphere::default();
|
||||
/// // Compute the normal on a transformed sphere.
|
||||
/// let mut s = Shape::sphere();
|
||||
/// s.set_transform(Matrix4x4::scaling(1., 0.5, 1.) * Matrix4x4::rotation_z(PI / 5.));
|
||||
/// let n = s.normal_at(Tuple::point(0., (2. as Float).sqrt()/2., -(2. as Float).sqrt()/2.));
|
||||
/// let n = s.normal_at(Tuple::point(
|
||||
/// 0.,
|
||||
/// (2. as Float).sqrt() / 2.,
|
||||
/// -(2. as Float).sqrt() / 2.,
|
||||
/// ));
|
||||
/// assert_eq!(n, Tuple::vector(0., 0.97014, -0.24254));
|
||||
/// ```
|
||||
#[cfg(not(feature = "disable-inverse-cache"))]
|
||||
pub fn normal_at(&self, world_point: Tuple) -> Tuple {
|
||||
let object_point = self.inverse_transform * world_point;
|
||||
let object_normal = object_point - Tuple::point(0., 0., 0.);
|
||||
let object_normal = match self.geometry {
|
||||
Geometry::Sphere => object_point - Tuple::point(0., 0., 0.),
|
||||
};
|
||||
let mut world_normal = self.inverse_transform.transpose() * object_normal;
|
||||
world_normal.w = 0.;
|
||||
world_normal.normalize()
|
||||
@ -115,7 +132,9 @@ impl Sphere {
|
||||
#[cfg(feature = "disable-inverse-cache")]
|
||||
pub fn normal_at(&self, world_point: Tuple) -> Tuple {
|
||||
let object_point = self.transform.inverse() * world_point;
|
||||
let object_normal = object_point - Tuple::point(0., 0., 0.);
|
||||
let object_normal = match self.geometry {
|
||||
Geometry::Sphere => object_point - Tuple::point(0., 0., 0.),
|
||||
};
|
||||
let mut world_normal = self.transform.inverse().transpose() * object_normal;
|
||||
world_normal.w = 0.;
|
||||
world_normal.normalize()
|
||||
@ -124,6 +143,7 @@ impl Sphere {
|
||||
pub fn transform(&self) -> Matrix4x4 {
|
||||
self.transform
|
||||
}
|
||||
|
||||
pub fn set_transform(&mut self, t: Matrix4x4) {
|
||||
self.transform = t;
|
||||
self.inverse_transform = t.inverse();
|
||||
@ -138,13 +158,13 @@ impl Sphere {
|
||||
/// intersections::{Intersection, Intersections},
|
||||
/// matrices::Matrix4x4,
|
||||
/// rays::Ray,
|
||||
/// spheres::{intersect, Sphere},
|
||||
/// shapes::{intersect, Shape},
|
||||
/// tuples::Tuple,
|
||||
/// };
|
||||
///
|
||||
/// // A ray intersects a sphere in two points.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let xs = intersect(&s, &r);
|
||||
/// assert_eq!(
|
||||
/// xs,
|
||||
@ -153,13 +173,13 @@ impl Sphere {
|
||||
///
|
||||
/// // A ray intersects a sphere at a tangent.
|
||||
/// let r = Ray::new(Tuple::point(0., 2., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let xs = intersect(&s, &r);
|
||||
/// assert_eq!(xs, Intersections::default());
|
||||
///
|
||||
/// // A ray originates inside a sphere.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., 0.), Tuple::vector(0., 0., 1.));
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let xs = intersect(&s, &r);
|
||||
/// assert_eq!(
|
||||
/// xs,
|
||||
@ -168,7 +188,7 @@ impl Sphere {
|
||||
///
|
||||
/// // A sphere is behind a ray.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., 5.), Tuple::vector(0., 0., 1.));
|
||||
/// let s = Sphere::default();
|
||||
/// let s = Shape::sphere();
|
||||
/// let xs = intersect(&s, &r);
|
||||
/// assert_eq!(
|
||||
/// xs,
|
||||
@ -177,7 +197,7 @@ impl Sphere {
|
||||
///
|
||||
/// // Intersect a scaled sphere with a ray.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let mut s = Sphere::default();
|
||||
/// let mut s = Shape::sphere();
|
||||
/// s.set_transform(Matrix4x4::scaling(2., 2., 2.));
|
||||
/// let xs = intersect(&s, &r);
|
||||
/// assert_eq!(xs.len(), 2, "xs {:?}", xs);
|
||||
@ -186,17 +206,19 @@ impl Sphere {
|
||||
///
|
||||
/// // Intersect a translated sphere with a ray.
|
||||
/// let r = Ray::new(Tuple::point(0., 0., -5.), Tuple::vector(0., 0., 1.));
|
||||
/// let mut s = Sphere::default();
|
||||
/// let mut s = Shape::sphere();
|
||||
/// s.set_transform(Matrix4x4::translation(5., 0., 0.));
|
||||
/// let xs = intersect(&s, &r);
|
||||
/// assert_eq!(xs.len(), 0);
|
||||
/// ```
|
||||
pub fn intersect<'s>(sphere: &'s Sphere, ray: &Ray) -> Intersections<'s> {
|
||||
intersect_rtc(sphere, ray)
|
||||
pub fn intersect<'s>(shape: &'s Shape, ray: &Ray) -> Intersections<'s> {
|
||||
match shape.geometry {
|
||||
Geometry::Sphere => intersect_rtc(shape, ray),
|
||||
}
|
||||
}
|
||||
|
||||
fn intersect_rtc<'s>(sphere: &'s Sphere, ray: &Ray) -> Intersections<'s> {
|
||||
let ray = ray.transform(sphere.inverse_transform);
|
||||
fn intersect_rtc<'s>(shape: &'s Shape, ray: &Ray) -> Intersections<'s> {
|
||||
let ray = ray.transform(shape.inverse_transform);
|
||||
let sphere_to_ray = ray.origin - Tuple::point(0., 0., 0.);
|
||||
let a = dot(ray.direction, ray.direction);
|
||||
let b = 2. * dot(ray.direction, sphere_to_ray);
|
||||
@ -206,12 +228,12 @@ fn intersect_rtc<'s>(sphere: &'s Sphere, ray: &Ray) -> Intersections<'s> {
|
||||
return Intersections::default();
|
||||
}
|
||||
Intersections::new(vec![
|
||||
Intersection::new((-b - discriminant.sqrt()) / (2. * a), &sphere),
|
||||
Intersection::new((-b + discriminant.sqrt()) / (2. * a), &sphere),
|
||||
Intersection::new((-b - discriminant.sqrt()) / (2. * a), &shape),
|
||||
Intersection::new((-b + discriminant.sqrt()) / (2. * a), &shape),
|
||||
])
|
||||
}
|
||||
fn intersect_rtiow<'s>(sphere: &'s Sphere, ray: &Ray) -> Intersections<'s> {
|
||||
let ray = ray.transform(sphere.inverse_transform);
|
||||
fn intersect_rtiow<'s>(shape: &'s Shape, ray: &Ray) -> Intersections<'s> {
|
||||
let ray = ray.transform(shape.inverse_transform);
|
||||
let oc = ray.origin - Tuple::point(0., 0., 0.);
|
||||
let a = dot(ray.direction, ray.direction);
|
||||
let b = dot(oc, ray.direction);
|
||||
@ -221,7 +243,7 @@ fn intersect_rtiow<'s>(sphere: &'s Sphere, ray: &Ray) -> Intersections<'s> {
|
||||
return Intersections::default();
|
||||
}
|
||||
Intersections::new(vec![
|
||||
Intersection::new((-b - discriminant.sqrt()) / a, &sphere),
|
||||
Intersection::new((-b + discriminant.sqrt()) / a, &sphere),
|
||||
Intersection::new((-b - discriminant.sqrt()) / a, &shape),
|
||||
Intersection::new((-b + discriminant.sqrt()) / a, &shape),
|
||||
])
|
||||
}
|
||||
@ -4,7 +4,7 @@ use crate::{
|
||||
materials::{lighting, Material},
|
||||
matrices::Matrix4x4,
|
||||
rays::Ray,
|
||||
spheres::{intersect, Sphere},
|
||||
shapes::{intersect, Shape},
|
||||
tuples::{Color, Tuple},
|
||||
Float, BLACK, WHITE,
|
||||
};
|
||||
@ -23,7 +23,7 @@ use crate::{
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct World {
|
||||
pub lights: Vec<PointLight>,
|
||||
pub objects: Vec<Sphere>,
|
||||
pub objects: Vec<Shape>,
|
||||
}
|
||||
|
||||
impl World {
|
||||
@ -39,14 +39,14 @@ impl World {
|
||||
/// ```
|
||||
pub fn test_world() -> World {
|
||||
let light = PointLight::new(Tuple::point(-10., 10., -10.), WHITE);
|
||||
let mut s1 = Sphere::default();
|
||||
let mut s1 = Shape::sphere();
|
||||
s1.material = Material {
|
||||
color: Color::new(0.8, 1., 0.6),
|
||||
diffuse: 0.7,
|
||||
specular: 0.2,
|
||||
..Material::default()
|
||||
};
|
||||
let mut s2 = Sphere::default();
|
||||
let mut s2 = Shape::sphere();
|
||||
s2.set_transform(Matrix4x4::scaling(0.5, 0.5, 0.5));
|
||||
World {
|
||||
lights: vec![light],
|
||||
@ -92,7 +92,7 @@ impl World {
|
||||
/// lights::PointLight,
|
||||
/// matrices::Matrix4x4,
|
||||
/// rays::Ray,
|
||||
/// spheres::Sphere,
|
||||
/// shapes::Shape,
|
||||
/// tuples::{Color, Tuple},
|
||||
/// world::World,
|
||||
/// WHITE,
|
||||
@ -120,8 +120,8 @@ impl World {
|
||||
/// // Shading with an intersection in shadow.
|
||||
/// let mut w = World::default();
|
||||
/// w.lights = vec![PointLight::new(Tuple::point(0., 0., -10.), WHITE)];
|
||||
/// let s1 = Sphere::default();
|
||||
/// let mut s2 = Sphere::default();
|
||||
/// let s1 = Shape::sphere();
|
||||
/// let mut s2 = Shape::sphere();
|
||||
/// s2.set_transform(Matrix4x4::translation(0., 0., 10.));
|
||||
/// w.objects = vec![s1, s2.clone()];
|
||||
/// let r = Ray::new(Tuple::point(0., 0., 5.), Tuple::vector(0., 0., 1.));
|
||||
@ -155,6 +155,7 @@ impl World {
|
||||
/// intersections::{prepare_computations, Intersection},
|
||||
/// lights::PointLight,
|
||||
/// rays::Ray,
|
||||
/// shapes::Shape,
|
||||
/// tuples::{Color, Tuple},
|
||||
/// world::World,
|
||||
/// BLACK,
|
||||
@ -176,7 +177,7 @@ impl World {
|
||||
/// let w = {
|
||||
/// let mut w = World::test_world();
|
||||
/// let mut outer = &mut w.objects[0];
|
||||
/// outer.material.ambient = 1.;
|
||||
/// let m = outer.material.ambient = 1.;
|
||||
/// let inner = &mut w.objects[1];
|
||||
/// inner.material.ambient = 1.;
|
||||
/// w
|
||||
@ -202,6 +203,7 @@ impl World {
|
||||
/// ```
|
||||
/// use rtchallenge::{
|
||||
/// tuples::{ Tuple},
|
||||
/// shapes::Shape,
|
||||
/// world::World,
|
||||
/// };
|
||||
///
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user