Added Torus and Steiner Surface
This commit is contained in:
241
src/primitive.rs
241
src/primitive.rs
@@ -1,7 +1,7 @@
|
|||||||
use crate::ray::Ray;
|
use crate::ray::Ray;
|
||||||
use crate::{EPSILON, EPSILON_VECTOR, INFINITY};
|
use crate::{EPSILON, EPSILON_VECTOR, INFINITY};
|
||||||
use nalgebra::{distance, Point3, Unit, Vector3};
|
use nalgebra::{distance, Point3, Unit, Vector3};
|
||||||
use roots::{find_roots_quadratic, Roots};
|
use roots::{find_roots_quadratic, find_roots_quartic, Roots};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -876,3 +876,242 @@ impl Primitive for Mesh {
|
|||||||
self.bounding_box.intersect_bounding_box(ray)
|
self.bounding_box.intersect_bounding_box(ray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct SteinerSurface {
|
||||||
|
material: Arc<Material>,
|
||||||
|
bounding_box: BoundingBox,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SteinerSurface {
|
||||||
|
pub fn new(material: Arc<Material>) -> Arc<dyn Primitive> {
|
||||||
|
// I need to find the bounding box for this shape
|
||||||
|
let trf = Point3::new(1.0, 1.0, 1.0);
|
||||||
|
let bln = Point3::new(-1.0, -1.0, -1.0);
|
||||||
|
Arc::new(SteinerSurface {
|
||||||
|
material,
|
||||||
|
bounding_box: BoundingBox { bln, trf },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Primitive for SteinerSurface {
|
||||||
|
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
|
||||||
|
let a = ray.a.x;
|
||||||
|
let b = ray.b.x;
|
||||||
|
let c = ray.a.y;
|
||||||
|
let d = ray.b.y;
|
||||||
|
let e = ray.a.z;
|
||||||
|
let f = ray.b.z;
|
||||||
|
|
||||||
|
let t0 = a.powf(2.0) * c.powf(2.0)
|
||||||
|
+ a.powf(2.0) * e.powf(2.0)
|
||||||
|
+ c.powf(2.0) * e.powf(2.0)
|
||||||
|
+ c * e.powf(2.0);
|
||||||
|
let t1 = 2.0 * a * b * c.powf(2.0)
|
||||||
|
+ 2.0 * a.powf(2.0) * c * d
|
||||||
|
+ 2.0 * a * b * e.powf(2.0)
|
||||||
|
+ 2.0 * c * d * e.powf(2.0)
|
||||||
|
+ 2.0 * a.powf(2.0) * e * f
|
||||||
|
+ 2.0 * c.powf(2.0) * e * f
|
||||||
|
+ d * e.powf(2.0)
|
||||||
|
+ 2.0 * c * e * f.powf(2.0);
|
||||||
|
let t2 = b.powf(2.0) * c.powf(2.0)
|
||||||
|
+ 4.0 * a * b * c * d
|
||||||
|
+ a.powf(2.0) * d.powf(2.0)
|
||||||
|
+ b.powf(2.0) * e.powf(2.0)
|
||||||
|
+ d.powf(2.0) * e.powf(2.0)
|
||||||
|
+ 4.0 * a * b * e * f
|
||||||
|
+ 4.0 * c * d * e * f
|
||||||
|
+ a.powf(2.0) * f.powf(2.0)
|
||||||
|
+ c.powf(2.0) * f.powf(2.0)
|
||||||
|
+ 2.0 * d * e * f
|
||||||
|
+ c * f.powf(2.0);
|
||||||
|
let t3 = 2.0 * b.powf(2.0) * c * d
|
||||||
|
+ 2.0 * a * b * d.powf(2.0)
|
||||||
|
+ 2.0 * b.powf(2.0) * e * f
|
||||||
|
+ 2.0 * d.powf(2.0) * e * f
|
||||||
|
+ 2.0 * a * b * f.powf(2.0)
|
||||||
|
+ 2.0 * c * d * f.powf(2.0)
|
||||||
|
+ d.powf(2.0) * f.powf(2.0);
|
||||||
|
let t4 = b.powf(2.0) * d.powf(2.0) + b.powf(2.0) * f.powf(2.0) + d.powf(2.0) * f.powf(2.0);
|
||||||
|
|
||||||
|
let t = match find_roots_quartic(t4, t3, t2, t1, t0) {
|
||||||
|
Roots::No(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::One(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::Two(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::Three(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::Four(arr) => smallest_non_zero(&arr),
|
||||||
|
};
|
||||||
|
|
||||||
|
let t = match t {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
//Now we have the smallest non-zero t
|
||||||
|
let point = ray.at_t(t);
|
||||||
|
let (x, y, z) = (point.x, point.y, point.z);
|
||||||
|
let normal = Unit::new_normalize(Vector3::new(
|
||||||
|
2.0 * x * y * y + 2.0 * x * z * z + y * z,
|
||||||
|
2.0 * x * x * y + 2.0 * z * z * y + x * z,
|
||||||
|
2.0 * x * x * z + 2.0 * z * y * y + x * y,
|
||||||
|
));
|
||||||
|
|
||||||
|
Some(Intersection {
|
||||||
|
point,
|
||||||
|
normal,
|
||||||
|
incidence: ray.b,
|
||||||
|
material: Arc::clone(&self.material),
|
||||||
|
distance: t,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
|
||||||
|
self.bounding_box.intersect_bounding_box(ray)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_material(&self) -> Arc<Material> {
|
||||||
|
Arc::clone(&self.material)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smallest_non_zero(arr: &[f32]) -> Option<f32> {
|
||||||
|
for &num in arr {
|
||||||
|
if num > 0.0 {
|
||||||
|
return Some(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Torus {
|
||||||
|
inner_rad: f32,
|
||||||
|
outer_rad: f32,
|
||||||
|
material: Arc<Material>,
|
||||||
|
bounding_box: BoundingBox,
|
||||||
|
}
|
||||||
|
impl Torus {
|
||||||
|
pub fn new(inner_rad: f32, outer_rad: f32, material: Arc<Material>) -> Arc<dyn Primitive> {
|
||||||
|
// I need to find the bounding box for this shape
|
||||||
|
let trf = Point3::new(1.0, 1.0, 1.0);
|
||||||
|
let bln = Point3::new(-1.0, -1.0, -1.0);
|
||||||
|
Arc::new(Torus {
|
||||||
|
inner_rad,
|
||||||
|
outer_rad,
|
||||||
|
material,
|
||||||
|
bounding_box: BoundingBox { bln, trf },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Primitive for Torus {
|
||||||
|
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
|
||||||
|
let a = ray.a.x;
|
||||||
|
let b = ray.b.x;
|
||||||
|
let c = ray.a.y;
|
||||||
|
let d = ray.b.y;
|
||||||
|
let e = ray.a.z;
|
||||||
|
let f = ray.b.z;
|
||||||
|
let r = self.inner_rad;
|
||||||
|
let R = self.outer_rad;
|
||||||
|
let t0 = R.powf(2.0).powf(2.0) - 2.0 * R.powf(2.0) * a.powf(2.0) + a.powf(2.0).powf(2.0)
|
||||||
|
- 2.0 * R.powf(2.0) * c.powf(2.0)
|
||||||
|
+ 2.0 * a.powf(2.0) * c.powf(2.0)
|
||||||
|
+ c.powf(2.0).powf(2.0)
|
||||||
|
+ 2.0 * R.powf(2.0) * e.powf(2.0)
|
||||||
|
+ 2.0 * a.powf(2.0) * e.powf(2.0)
|
||||||
|
+ 2.0 * c.powf(2.0) * e.powf(2.0)
|
||||||
|
+ e.powf(2.0).powf(2.0)
|
||||||
|
- 2.0 * R.powf(2.0) * r.powf(2.0)
|
||||||
|
- 2.0 * a.powf(2.0) * r.powf(2.0)
|
||||||
|
- 2.0 * c.powf(2.0) * r.powf(2.0)
|
||||||
|
- 2.0 * e.powf(2.0) * r.powf(2.0)
|
||||||
|
+ r.powf(2.0).powf(2.0);
|
||||||
|
let t1 = -4.0 * R.powf(2.0) * a * b + 4.0 * a.powf(3.0) * b + 4.0 * a * b * c.powf(2.0)
|
||||||
|
- 4.0 * R.powf(2.0) * c * d
|
||||||
|
+ 4.0 * a.powf(2.0) * c * d
|
||||||
|
+ 4.0 * c.powf(3.0) * d
|
||||||
|
+ 4.0 * a * b * e.powf(2.0)
|
||||||
|
+ 4.0 * c * d * e.powf(2.0)
|
||||||
|
+ 4.0 * R.powf(2.0) * e * f
|
||||||
|
+ 4.0 * a.powf(2.0) * e * f
|
||||||
|
+ 4.0 * c.powf(2.0) * e * f
|
||||||
|
+ 4.0 * e.powf(3.0) * f
|
||||||
|
- 4.0 * a * b * r.powf(2.0)
|
||||||
|
- 4.0 * c * d * r.powf(2.0)
|
||||||
|
- 4.0 * e * f * r.powf(2.0);
|
||||||
|
let t2 = -2.0 * R.powf(2.0) * b.powf(2.0)
|
||||||
|
+ 6.0 * a.powf(2.0) * b.powf(2.0)
|
||||||
|
+ 2.0 * b.powf(2.0) * c.powf(2.0)
|
||||||
|
+ 8.0 * a * b * c * d
|
||||||
|
- 2.0 * R.powf(2.0) * d.powf(2.0)
|
||||||
|
+ 2.0 * a.powf(2.0) * d.powf(2.0)
|
||||||
|
+ 6.0 * c.powf(2.0) * d.powf(2.0)
|
||||||
|
+ 2.0 * b.powf(2.0) * e.powf(2.0)
|
||||||
|
+ 2.0 * d.powf(2.0) * e.powf(2.0)
|
||||||
|
+ 8.0 * a * b * e * f
|
||||||
|
+ 8.0 * c * d * e * f
|
||||||
|
+ 2.0 * R.powf(2.0) * f.powf(2.0)
|
||||||
|
+ 2.0 * a.powf(2.0) * f.powf(2.0)
|
||||||
|
+ 2.0 * c.powf(2.0) * f.powf(2.0)
|
||||||
|
+ 6.0 * e.powf(2.0) * f.powf(2.0)
|
||||||
|
- 2.0 * b.powf(2.0) * r.powf(2.0)
|
||||||
|
- 2.0 * d.powf(2.0) * r.powf(2.0)
|
||||||
|
- 2.0 * f.powf(2.0) * r.powf(2.0);
|
||||||
|
let t3 = 4.0 * a * b.powf(3.0)
|
||||||
|
+ 4.0 * b.powf(2.0) * c * d
|
||||||
|
+ 4.0 * a * b * d.powf(2.0)
|
||||||
|
+ 4.0 * c * d.powf(3.0)
|
||||||
|
+ 4.0 * b.powf(2.0) * e * f
|
||||||
|
+ 4.0 * d.powf(2.0) * e * f
|
||||||
|
+ 4.0 * a * b * f.powf(2.0)
|
||||||
|
+ 4.0 * c * d * f.powf(2.0)
|
||||||
|
+ 4.0 * e * f.powf(3.0);
|
||||||
|
let t4 = b.powf(4.0)
|
||||||
|
+ 2.0 * b.powf(2.0) * d.powf(2.0)
|
||||||
|
+ d.powf(4.0)
|
||||||
|
+ 2.0 * b.powf(2.0) * f.powf(2.0)
|
||||||
|
+ 2.0 * d.powf(2.0) * f.powf(2.0)
|
||||||
|
+ f.powf(4.0);
|
||||||
|
|
||||||
|
let t = match find_roots_quartic(t4, t3, t2, t1, t0) {
|
||||||
|
Roots::No(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::One(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::Two(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::Three(arr) => smallest_non_zero(&arr),
|
||||||
|
Roots::Four(arr) => smallest_non_zero(&arr),
|
||||||
|
};
|
||||||
|
|
||||||
|
let t = match t {
|
||||||
|
Some(t) => t,
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
|
||||||
|
//Now we have the smallest non-zero t
|
||||||
|
let point = ray.at_t(t);
|
||||||
|
let (x, y, z) = (point.x, point.y, point.z);
|
||||||
|
let dx = 4.0 * (R.powf(2.0) - r.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * R
|
||||||
|
- 8.0 * (x.powf(2.0) + y.powf(2.0)) * R;
|
||||||
|
let dy = -4.0 * (R.powf(2.0) - r.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r;
|
||||||
|
let dz = -8.0 * R.powf(2.0) * x
|
||||||
|
+ 4.0 * (R.powf(2.0) - r.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * x;
|
||||||
|
let normal = Unit::new_normalize(Vector3::new(dx, dy, dz));
|
||||||
|
|
||||||
|
Some(Intersection {
|
||||||
|
point,
|
||||||
|
normal,
|
||||||
|
incidence: ray.b,
|
||||||
|
material: Arc::clone(&self.material),
|
||||||
|
distance: t,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
|
||||||
|
self.bounding_box.intersect_bounding_box(ray)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_material(&self) -> Arc<Material> {
|
||||||
|
Arc::clone(&self.material)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user