From 2757ce9730c3ce18a315125aa367f68dd7b402c2 Mon Sep 17 00:00:00 2001 From: STP Date: Mon, 27 Nov 2023 21:37:00 -0500 Subject: [PATCH] Added all new primitives --- rhai/cow.rhai | 35 +++ rhai/sphere.rhai | 2 +- rhai/surfaces.rhai | 61 ++++ src/camera.rs | 2 +- src/gui.rs | 19 +- src/primitive.rs | 675 +++++++++++++++++++++++++++++++++++++-------- src/state.rs | 27 +- 7 files changed, 674 insertions(+), 147 deletions(-) create mode 100644 rhai/cow.rhai create mode 100644 rhai/surfaces.rhai diff --git a/rhai/cow.rhai b/rhai/cow.rhai new file mode 100644 index 0000000..3cba062 --- /dev/null +++ b/rhai/cow.rhai @@ -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 \ No newline at end of file diff --git a/rhai/sphere.rhai b/rhai/sphere.rhai index 99a19ef..adc337a 100644 --- a/rhai/sphere.rhai +++ b/rhai/sphere.rhai @@ -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); diff --git a/rhai/surfaces.rhai b/rhai/surfaces.rhai new file mode 100644 index 0000000..f353a2d --- /dev/null +++ b/rhai/surfaces.rhai @@ -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 \ No newline at end of file diff --git a/src/camera.rs b/src/camera.rs index 1105200..7098865 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -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) diff --git a/src/gui.rs b/src/gui.rs index 9d00cf8..c145a1f 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -414,14 +414,23 @@ pub fn init_engine() -> Engine { .register_fn("Cube", Cube::new) .register_fn("CubeUnit", Cube::unit); engine - .register_type::() - .register_fn("Steiner", SteinerSurface::new); + .register_type::() + .register_fn("Steiner", Steiner::new); + engine + .register_type::() + .register_fn("Steiner2", Steiner2::new); + engine + .register_type::() + .register_fn("Roman", Roman::new); + engine + .register_type::() + .register_fn("CrossCap", CrossCap::new); + engine + .register_type::() + .register_fn("CrossCap2", CrossCap2::new); engine .register_type::() .register_fn("Torus", Torus::new); - engine - .register_type::() - .register_fn("Mesh", Mesh::from_file); engine .register_type::() .register_fn("Gnonom", Gnonom::new); diff --git a/src/primitive.rs b/src/primitive.rs index 39fdf28..9bbb0f0 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -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, - bounding_box: BoundingBox, -} - -impl SteinerSurface { - pub fn new(material: Rc) -> Rc { - // 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 { - 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 { - Rc::clone(&self.material) - } -} - -fn smallest_non_zero(arr: &[f64]) -> Option { - 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, + bounding_box: BoundingBox, +} + +impl CrossCap { + pub fn new(material: Rc) -> Rc { + // 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 { + 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 { + Rc::clone(&self.material) + } +} + +// CROSS CAP 2 --------- +#[derive(Clone)] +pub struct CrossCap2 { + p: f64, + q: f64, + material: Rc, + bounding_box: BoundingBox, +} + +impl CrossCap2 { + pub fn new(p: f64, q: f64, material: Rc) -> Rc { + // 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 { + 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 { + Rc::clone(&self.material) + } +} + +// Steiner --------- +#[derive(Clone)] +pub struct Steiner { + material: Rc, + bounding_box: BoundingBox, +} + +impl Steiner { + pub fn new(material: Rc) -> Rc { + // 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 { + 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 { + Rc::clone(&self.material) + } +} + +// Steiner 2 --------- +#[derive(Clone)] +pub struct Steiner2 { + material: Rc, + bounding_box: BoundingBox, +} + +impl Steiner2 { + pub fn new(material: Rc) -> Rc { + // 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 { + 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 { + Rc::clone(&self.material) + } +} + +// Roman --------- +#[derive(Clone)] +pub struct Roman { + k: f64, + material: Rc, + bounding_box: BoundingBox, +} + +impl Roman { + pub fn new(k: f64, material: Rc) -> Rc { + // 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 { + 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 { + Rc::clone(&self.material) + } +} + +fn smallest_non_zero(arr: &[f64]) -> Option { + for &num in arr { + if num >= 0.0 { + return Some(num); + } + } + None +} diff --git a/src/state.rs b/src/state.rs index 3998078..e435b97 100644 --- a/src/state.rs +++ b/src/state.rs @@ -224,11 +224,13 @@ pub fn run() -> Result<(), Box> { } 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> { - 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(()) -}