Added all new primitives

This commit is contained in:
STP
2023-11-27 21:37:00 -05:00
parent 5aa73bcc1a
commit 2757ce9730
7 changed files with 674 additions and 147 deletions

35
rhai/cow.rhai Normal file
View File

@@ -0,0 +1,35 @@
let scene = Scene();
let distance = 3.0;
let falloff = V(0.0,0.0,0.1);
let camera = Camera( P(0.0,0.0,distance), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("+Z Cam", camera);
let camera = Camera( P(0.0,distance,0.1), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("+Y Cam", camera);
let camera = Camera( P(distance,0.0,0.0), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("+X Cam", camera);
let camera = Camera( P(0.0,0.0,-distance), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("-Z Cam", camera);
let camera = Camera( P(0.0,-distance,0.1), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("-Y Cam", camera);
let camera = Camera( P(-distance,0.0,0.0), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("-X Cam", camera);
let height = 4.0;
let spacing = 13.0;
let light = Light(P(0.0,height,spacing), V(0.0,0.3,0.3), falloff);
scene.addLight("blue", light);
let light = Light(P(0.0,height,0.0), V(0.0,0.6,0.0), falloff);
scene.addLight("green", light);
let light = Light(P(0.0,height,-spacing), V(0.3,0.0,0.0), falloff);
scene.addLight("red", light);
let material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
scene.addMaterial("bluegreen", material);
let mesh = Mesh("obj/cow.obj", material);
let mesh_node = Node(mesh);
scene.addNode("mesh", mesh_node);
scene

View File

@@ -27,7 +27,7 @@ scene.addLight("red", light);
let material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
scene.addMaterial("bluegreen", material);
let sphere = Sphere(P(0.0,0.0,0.0), 1.0, material);
let sphere = Steiner( material);
let sphere_node = Node(sphere);
scene.addNode("sphere", sphere_node);

61
rhai/surfaces.rhai Normal file
View File

@@ -0,0 +1,61 @@
let scene = Scene();
let distance = 3.0;
let falloff = V(0.0,0.0,0.1);
let camera = Camera( P(0.0,0.0,distance), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("+Z Cam", camera);
let camera = Camera( P(0.0,distance,0.1), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("+Y Cam", camera);
let camera = Camera( P(distance,0.0,0.0), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("+X Cam", camera);
let camera = Camera( P(0.0,0.0,-distance), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("-Z Cam", camera);
let camera = Camera( P(0.0,-distance,0.1), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("-Y Cam", camera);
let camera = Camera( P(-distance,0.0,0.0), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("-X Cam", camera);
let height = 4.0;
let spacing = 4.0;
let blue = V(0.0,0.0,0.6);
let light = Light(P(0.0,height,spacing), blue, falloff);
scene.addLight("blue", light);
let green = V(0.0,0.6,0.0);
let light = Light(P(0.0,height,0.0), green, falloff);
scene.addLight("green", light);
let red = V(0.6,0.0,0.0);
let light = Light(P(0.0,height,-spacing), red, falloff);
scene.addLight("red", light);
let material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
scene.addMaterial("bluegreen", material);
let steiner = Steiner( material);
let steiner_node = Node(steiner);
scene.addNode("steiner", steiner_node);
let steiner2 = Steiner2( material);
let steiner2_node = Node(steiner2);
scene.addNode("steiner2", steiner2_node);
let crosscap = CrossCap(material);
let crosscap_node = Node(crosscap);
scene.addNode("crosscap", crosscap_node);
let (p,q) = (1.0,1.0);
let crosscap2 = CrossCap2( material);
let crosscap2_node = Node(crosscap2);
scene.addNode("crosscap2", crosscap2_node);
let k = 1.0;
let roman = Roman(k, material);
let roman_node = Node(roman);
scene.addNode("sphere", roman_node);
let (inner_rad, outer_rad) = (0.5, 0.5);
let torus = Torus(inner_rad, outer_rad, material);
let torus_node = Node(torus);
scene.addNode("sphere", torus_node);
scene

View File

@@ -27,7 +27,7 @@ impl Camera {
/// Create a unit camera with default parameters
pub fn unit() -> Self {
let eye = Point3::new(0.0, 0.0, 2.0);
let eye = Point3::new(2.0, 2.0, 2.0);
let target = Point3::new(0.0, 0.0, 0.0);
let up = Vector3::new(0.0, 1.0, 0.0);
Camera::new(eye, target, up)

View File

@@ -414,14 +414,23 @@ pub fn init_engine() -> Engine {
.register_fn("Cube", Cube::new)
.register_fn("CubeUnit", Cube::unit);
engine
.register_type::<SteinerSurface>()
.register_fn("Steiner", SteinerSurface::new);
.register_type::<Steiner>()
.register_fn("Steiner", Steiner::new);
engine
.register_type::<Steiner2>()
.register_fn("Steiner2", Steiner2::new);
engine
.register_type::<Roman>()
.register_fn("Roman", Roman::new);
engine
.register_type::<CrossCap>()
.register_fn("CrossCap", CrossCap::new);
engine
.register_type::<CrossCap2>()
.register_fn("CrossCap2", CrossCap2::new);
engine
.register_type::<Torus>()
.register_fn("Torus", Torus::new);
engine
.register_type::<Mesh>()
.register_fn("Mesh", Mesh::from_file);
engine
.register_type::<Gnonom>()
.register_fn("Gnonom", Gnonom::new);

View File

@@ -158,7 +158,6 @@ impl Primitive for Sphere {
let dir = &ray.b;
let l = pos - self.position;
let a = dir.dot(dir);
let b = 2.0 * l.dot(dir);
let c = l.dot(&l) - self.radius * self.radius;
@@ -923,116 +922,6 @@ impl Primitive for Mesh {
}
}
// STEINER -----------------------------------------------------------------
#[derive(Clone)]
pub struct SteinerSurface {
material: Rc<Material>,
bounding_box: BoundingBox,
}
impl SteinerSurface {
pub fn new(material: Rc<Material>) -> Rc<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);
Rc::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 = 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,
)
.normalize();
Some(Intersection {
point,
normal,
incidence: ray.b,
material: Rc::clone(&self.material),
distance: t,
})
}
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray)
}
fn get_material(&self) -> Rc<Material> {
Rc::clone(&self.material)
}
}
fn smallest_non_zero(arr: &[f64]) -> Option<f64> {
for &num in arr {
if num >= 0.0 {
return Some(num);
}
}
None
}
// TORUS -----------------------------------------------------------------
#[derive(Clone)]
pub struct Torus {
@@ -1066,19 +955,20 @@ impl Primitive for Torus {
let f = ray.b.z;
let r1 = self.inner_rad;
let r2 = self.outer_rad;
let t0 = r2.powf(2.0).powf(2.0) - 2.0 * r2.powf(2.0) * a.powf(2.0) + a.powf(2.0).powf(2.0)
let t0 = r2.powf(4.0) - 2.0 * r2.powf(2.0) * a.powf(2.0) + a.powf(4.0)
- 2.0 * r2.powf(2.0) * c.powf(2.0)
+ 2.0 * a.powf(2.0) * c.powf(2.0)
+ c.powf(2.0).powf(2.0)
+ c.powf(4.0)
+ 2.0 * r2.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)
+ e.powf(4.0)
- 2.0 * r2.powf(2.0) * r1.powf(2.0)
- 2.0 * a.powf(2.0) * r1.powf(2.0)
- 2.0 * c.powf(2.0) * r1.powf(2.0)
- 2.0 * e.powf(2.0) * r1.powf(2.0)
+ r1.powf(2.0).powf(2.0);
+ r1.powf(4.0);
let t1 = -4.0 * r2.powf(2.0) * a * b + 4.0 * a.powf(3.0) * b + 4.0 * a * b * c.powf(2.0)
- 4.0 * r2.powf(2.0) * c * d
+ 4.0 * a.powf(2.0) * c * d
@@ -1142,12 +1032,11 @@ impl Primitive for Torus {
//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 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r2
- 8.0 * (x.powf(2.0) + y.powf(2.0)) * r2;
let dy =
-4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r1;
let dz = -8.0 * r2.powf(2.0) * x
let dx = -8.0 * r2.powf(2.0) * x
+ 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * x;
let dy = -8.0 * r2.powf(2.0) * y
+ 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * y;
let dz = 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * z;
let normal = Vector3::new(dx, dy, dz).normalize();
Some(Intersection {
@@ -1244,3 +1133,549 @@ impl Primitive for Gnonom {
self.material.clone()
}
}
// CROSS CAP ---------
#[derive(Clone)]
pub struct CrossCap {
material: Rc<Material>,
bounding_box: BoundingBox,
}
impl CrossCap {
pub fn new(material: Rc<Material>) -> Rc<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);
Rc::new(CrossCap {
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
impl Primitive for CrossCap {
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)
- e.powf(4.0)
- 2.0 * a * c.powf(2.0)
- a * e.powf(2.0)
+ c.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 * a.powf(2.0) * e * f
- 4.0 * e.powf(3.0) * f
- 2.0 * b * c.powf(2.0)
- 4.0 * a * c * d
- b * e.powf(2.0)
- 2.0 * a * e * f
+ 2.0 * c * d;
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)
+ 4.0 * a * b * e * f
+ a.powf(2.0) * f.powf(2.0)
- 6.0 * e.powf(2.0) * f.powf(2.0)
- 4.0 * b * c * d
- 2.0 * a * d.powf(2.0)
- 2.0 * b * e * f
- a * f.powf(2.0)
+ d.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 * a * b * f.powf(2.0)
- 4.0 * e * f.powf(3.0)
- 2.0 * b * d.powf(2.0)
- b * f.powf(2.0);
let t4 = b.powf(2.0) * d.powf(2.0) + b.powf(2.0) * f.powf(2.0) - f.powf(4.0);
let t = match 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),
} {
Some(t) => t,
None => return None,
};
let point = ray.at_t(t);
let (x, y, z) = (point.x, point.y, point.z);
let dx = 2.0 * x * y.powf(2.0) + 2.0 * x * z.powf(2.0) - 2.0 * y.powf(2.0) - z.powf(2.0);
let dy = 2.0 * x.powf(2.0) * y - 4.0 * x * y + 2.0 * y;
let dz = 2.0 * x.powf(2.0) * z - 4.0 * z.powf(3.0) - 2.0 * x * z;
let normal = Vector3::new(dx, dy, dz).normalize();
Some(Intersection {
point,
normal,
incidence: ray.b,
material: Rc::clone(&self.material),
distance: t,
})
}
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray)
}
fn get_material(&self) -> Rc<Material> {
Rc::clone(&self.material)
}
}
// CROSS CAP 2 ---------
#[derive(Clone)]
pub struct CrossCap2 {
p: f64,
q: f64,
material: Rc<Material>,
bounding_box: BoundingBox,
}
impl CrossCap2 {
pub fn new(p: f64, q: f64, material: Rc<Material>) -> Rc<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);
Rc::new(CrossCap2 {
p,
q,
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
impl Primitive for CrossCap2 {
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 (p, q) = (self.p, self.q);
let t0 = 2.0 * a * a * e
+ 2.0 * c * c * e
+ a * a * a * a / p
+ a * a * c * c / p
+ a * a * e * e / p
+ a * a * c * c / q
+ c * c * c * c / q
+ c * c * e * e / q;
let t1 = 4.0 * a * b * e
+ 4.0 * c * d * e
+ 2.0 * a * a * f
+ 2.0 * c * c * f
+ 4.0 * a * a * a * b / p
+ 2.0 * a * b * c * c / p
+ 2.0 * a * a * c * d / p
+ 2.0 * a * b * e * e / p
+ 2.0 * a * a * e * f / p
+ 2.0 * a * b * c * c / q
+ 2.0 * a * a * c * d / q
+ 4.0 * c * c * c * d / q
+ 2.0 * c * d * e * e / q
+ 2.0 * c * c * e * f / q;
let t2 = 2.0 * b * b * e
+ 2.0 * d * d * e
+ 4.0 * a * b * f
+ 4.0 * c * d * f
+ 6.0 * a * a * b * b / p
+ b * b * c * c / p
+ 4.0 * a * b * c * d / p
+ a * a * d * d / p
+ b * b * e * e / p
+ 4.0 * a * b * e * f / p
+ a * a * f * f / p
+ b * b * c * c / q
+ 4.0 * a * b * c * d / q
+ a * a * d * d / q
+ 6.0 * c * c * d * d / q
+ d * d * e * e / q
+ 4.0 * c * d * e * f / q
+ c * c * f * f / q;
let t3 = 2.0 * b * b * f
+ 2.0 * d * d * f
+ 4.0 * a * b * b * b / p
+ 2.0 * b * b * c * d / p
+ 2.0 * a * b * d * d / p
+ 2.0 * b * b * e * f / p
+ 2.0 * a * b * f * f / p
+ 2.0 * b * b * c * d / q
+ 2.0 * a * b * d * d / q
+ 4.0 * c * d * d * d / q
+ 2.0 * d * d * e * f / q
+ 2.0 * c * d * f * f / q;
let t4 = b * b * b * b / p
+ b * b * d * d / p
+ b * b * f * f / p
+ b * b * d * d / q
+ d * d * d * d / q
+ d * d * f * f / q;
let t = match 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),
} {
Some(t) => t,
None => return None,
};
let point = ray.at_t(t);
let (x, y, z) = (point.x, point.y, point.z);
let dx =
2.0 * x * (x * (2.0 / p) + y * (2.0 / q)) + 4.0 * x * z + 2.0 * (x * (x + y + z) / p);
let dy =
2.0 * (x * (2.0 / p) + y * (2.0 / q)) * y + 4.0 * y * z + 2.0 * (y * (x + y + z) / q);
let dz = 2.0 * x + 2.0 * y + 2.0 * (x * (2.0 / p) + y * (2.0 / q)) * z;
let normal = Vector3::new(dx, dy, dz).normalize();
Some(Intersection {
point,
normal,
incidence: ray.b,
material: Rc::clone(&self.material),
distance: t,
})
}
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray)
}
fn get_material(&self) -> Rc<Material> {
Rc::clone(&self.material)
}
}
// Steiner ---------
#[derive(Clone)]
pub struct Steiner {
material: Rc<Material>,
bounding_box: BoundingBox,
}
impl Steiner {
pub fn new(material: Rc<Material>) -> Rc<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);
Rc::new(Steiner {
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
impl Primitive for Steiner {
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)
- a * c * e;
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
- b * c * e
- a * d * e
- a * c * f;
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)
- b * d * e
- b * c * f
- a * d * f;
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)
- b * d * f;
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 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),
} {
Some(t) => t,
None => return None,
};
let point = ray.at_t(t);
let (x, y, z) = (point.x, point.y, point.z);
let dx = 2.0 * x * y.powf(2.0) - 2.0 * x * z.powf(2.0) - y * z;
let dy = 2.0 * x.powf(2.0) * y + 2.0 * y * z.powf(2.0) - x * z;
let dz = -2.0 * x.powf(2.0) * z + 2.0 * y.powf(2.0) * z - x * y;
let normal = Vector3::new(dx, dy, dz).normalize();
Some(Intersection {
point,
normal,
incidence: ray.b,
material: Rc::clone(&self.material),
distance: t,
})
}
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray)
}
fn get_material(&self) -> Rc<Material> {
Rc::clone(&self.material)
}
}
// Steiner 2 ---------
#[derive(Clone)]
pub struct Steiner2 {
material: Rc<Material>,
bounding_box: BoundingBox,
}
impl Steiner2 {
pub fn new(material: Rc<Material>) -> Rc<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);
Rc::new(Steiner2 {
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
impl Primitive for Steiner2 {
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.powi(2) * c.powi(2) + a.powi(2) * e.powi(2)
- e.powi(4)
- 2.0 * a * c.powi(2)
- a * e.powi(2)
+ c.powi(2);
let t1 = 2.0 * a * b * c.powi(2)
+ 2.0 * a.powi(2) * c * d
+ 2.0 * a * b * e.powi(2)
+ 2.0 * a.powi(2) * e * f
- 4.0 * e.powi(3) * f
- 2.0 * b * c.powi(2)
- 4.0 * a * c * d
- b * e.powi(2)
- 2.0 * a * e * f
+ 2.0 * c * d;
let t2 = b.powi(2) * c.powi(2)
+ 4.0 * a * b * c * d
+ a.powi(2) * d.powi(2)
+ b.powi(2) * e.powi(2)
+ 4.0 * a * b * e * f
+ a.powi(2) * f.powi(2)
- 6.0 * e.powi(2) * f.powi(2)
- 4.0 * b * c * d
- 2.0 * a * d.powi(2)
- 2.0 * b * e * f
- a * f.powi(2)
+ d.powi(2);
let t3 = 2.0 * b.powi(2) * c * d
+ 2.0 * a * b * d.powi(2)
+ 2.0 * b.powi(2) * e * f
+ 2.0 * a * b * f.powi(2)
- 4.0 * e * f.powi(3)
- 2.0 * b * d.powi(2)
- b * f.powi(2);
let t4 = b.powi(2) * d.powi(2) + b.powi(2) * f.powi(2) - f.powi(4);
let t = match 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),
} {
Some(t) => t,
None => return None,
};
let point = ray.at_t(t);
let (x, y, z) = (point.x, point.y, point.z);
let dx = 2.0 * x * y.powi(2) + 2.0 * x * z.powi(2) - 2.0 * y.powi(2) - z.powi(2);
let dy = 2.0 * x.powi(2) * y - 4.0 * x * y + 2.0 * y;
let dz = 2.0 * x.powi(2) * z - 4.0 * z.powi(3) - 2.0 * x * z;
let normal = Vector3::new(dx, dy, dz).normalize();
Some(Intersection {
point,
normal,
incidence: ray.b,
material: Rc::clone(&self.material),
distance: t,
})
}
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray)
}
fn get_material(&self) -> Rc<Material> {
Rc::clone(&self.material)
}
}
// Roman ---------
#[derive(Clone)]
pub struct Roman {
k: f64,
material: Rc<Material>,
bounding_box: BoundingBox,
}
impl Roman {
pub fn new(k: f64, material: Rc<Material>) -> Rc<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);
Rc::new(Roman {
k,
material,
bounding_box: BoundingBox { bln, trf },
})
}
}
impl Primitive for Roman {
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 k = self.k;
let t0 = a.powf(4.0)
+ 2.0 * a.powf(2.0) * c.powf(2.0)
+ c.powf(4.0)
+ 2.0 * a.powf(2.0) * e.powf(2.0)
+ 2.0 * c.powf(2.0) * e.powf(2.0)
+ e.powf(4.0)
- 2.0 * a.powf(2.0) * k.powf(2.0)
- 2.0 * c.powf(2.0) * k.powf(2.0)
- 2.0 * e.powf(2.0) * k.powf(2.0)
+ k.powf(4.0);
let t1 = 4.0 * a.powf(3.0) * b
+ 4.0 * a * b * c.powf(2.0)
+ 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 * 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 * k.powf(2.0)
- 4.0 * c * d * k.powf(2.0)
- 4.0 * e * f * k.powf(2.0);
let t2 = 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 * 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 * 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) * k.powf(2.0)
- 2.0 * d.powf(2.0) * k.powf(2.0)
- 2.0 * f.powf(2.0) * k.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 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),
} {
Some(t) => t,
None => return None,
};
let point = ray.at_t(t);
let (x, y, z) = (point.x, point.y, point.z);
let dx = -4.0 * (k.powf(2.0) - x.powf(2.0) - y.powf(2.0) - z.powf(2.0)) * x;
let dy = -4.0 * (k.powf(2.0) - x.powf(2.0) - y.powf(2.0) - z.powf(2.0)) * y;
let dz = -4.0 * (k.powf(2.0) - x.powf(2.0) - y.powf(2.0) - z.powf(2.0)) * z;
let normal = Vector3::new(dx, dy, dz).normalize();
Some(Intersection {
point,
normal,
incidence: ray.b,
material: Rc::clone(&self.material),
distance: t,
})
}
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray)
}
fn get_material(&self) -> Rc<Material> {
Rc::clone(&self.material)
}
}
fn smallest_non_zero(arr: &[f64]) -> Option<f64> {
for &num in arr {
if num >= 0.0 {
return Some(num);
}
}
None
}

View File

@@ -224,11 +224,13 @@ pub fn run() -> Result<(), Box<dyn Error>> {
}
match event {
Event::WindowEvent { event, .. } => {
if let Err(_e) = handle_window_event(event, control_flow, &mut state) {
*control_flow = ControlFlow::Exit;
}
}
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(size) => state.resize(&size).expect("Window Resize Error"),
WindowEvent::KeyboardInput { input, .. } => state.keyboard_input(&input),
WindowEvent::MouseInput { button, .. } => state.mouse_input(&button),
_ => {}
},
Event::RedrawRequested(_) => {
if let Err(_e) = state.render() {
@@ -255,18 +257,3 @@ fn create_pixels(window: &Window) -> Pixels {
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, window);
Pixels::new(1, 1, surface_texture).unwrap()
}
fn handle_window_event(
event: WindowEvent,
control_flow: &mut ControlFlow,
state: &mut State,
) -> Result<(), Box<dyn Error>> {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(size) => state.resize(&size)?,
WindowEvent::KeyboardInput { input, .. } => state.keyboard_input(&input),
WindowEvent::MouseInput { button, .. } => state.mouse_input(&button),
_ => {}
};
Ok(())
}