diff --git a/rhai/mesh.rhai b/rhai/mesh.rhai index 96aaee5..b8c8313 100644 --- a/rhai/mesh.rhai +++ b/rhai/mesh.rhai @@ -21,9 +21,19 @@ scene.addLight("ambient", light); let tri = TriangleUnit(); let tri_node = Node(tri, material); -tri_node.active(true); +tri_node.active(false); scene.addNode("tri", tri_node); +let circle = CircleUnit(); +let circle_node = Node(circle, material); +circle_node.active(false); +scene.addNode("circle", circle_node); + +let cone = ConeUnit(); +let cone_node = Node(cone, material); +cone_node.active(true); +scene.addNode("cone", cone_node); + let sphere = SphereUnit(); let sphere_node = Node(sphere, material); @@ -39,10 +49,10 @@ ground_node.scale(scale,scale,scale); ground_node.active(false); scene.addNode("ground", ground_node); -// let mesh = Mesh("obj/cat.obj"); -// let mesh_node = Node(mesh, material); -// mesh_node.active(false); -// scene.addNode("mesh", mesh_node); +let mesh = Mesh("obj/cat.obj"); +let mesh_node = Node(mesh, material); +mesh_node.active(false); +scene.addNode("mesh", mesh_node); scene \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index cd32429..c5f59a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ use crate::state::run; use error_iter::ErrorIter; const EPSILON: f64 = 1e-8; -const INFINITY: f64 = 1e-10; +const INFINITY: f64 = 1e10; use log::error; use std::env; diff --git a/src/primitive.rs b/src/primitive.rs index b475529..2781c6e 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -6,7 +6,7 @@ use crate::{ #[allow(dead_code)] use nalgebra::{distance, Point3, Vector3}; -use roots::{find_roots_quadratic, find_roots_quartic, Roots}; +use roots::{find_roots_quadratic, find_roots_quartic, FloatType, Roots}; use std::fs::File; use std::io::{BufRead, BufReader}; use std::rc::Rc; @@ -89,6 +89,7 @@ pub struct Circle { position: Point3, radius: f64, normal: Vector3, + constant: f64, bounding_box: BoundingBox, } @@ -98,51 +99,48 @@ impl Circle { let bln = position - radius_vec; let trf = position + radius_vec; let bounding_box = BoundingBox::new(bln, trf); + + let normal = normal.normalize(); + let constant = normal.dot(&position.coords); Rc::new(Circle { position, radius, - normal: normal.normalize(), + normal, + constant, bounding_box, }) } pub fn unit() -> Rc { let position = Point3::new(0.0, 0.0, 0.0); - let normal = Vector3::new(0.0, 1.0, 0.0); + let normal = Vector3::new(0.0, 0.0, -1.0); let radius = 1.0; - - let bln = Point3::new(-radius, 0.0, -EPSILON); - let trf = Point3::new(radius, 0.0, EPSILON); - let bounding_box = BoundingBox { bln, trf }; - - Rc::new(Circle { - position, - normal, - radius, - bounding_box, - }) + Circle::new(position, radius, normal) } } impl Primitive for Circle { fn intersect_ray(&self, ray: &Ray) -> Option { - let constant = self.position.coords.dot(&self.normal); - let denominator = ray.b.dot(&self.normal); - let t = (constant - ray.a.coords.dot(&self.normal)) / denominator; + let n_dot_a = ray.a.coords.dot(&self.normal); + let n_dot_b = ray.b.dot(&self.normal); + let t = (self.constant - n_dot_a) / n_dot_b; + if t > INFINITY { return None; }; + let intersect = ray.at_t(t); - let distance = distance(&intersect, &self.position); - match distance >= self.radius { - true => return None, - false => { + //Distance to center of circle + let distance = distance(&intersect, &self.position).abs(); + match distance <= self.radius { + true => { return Some(Intersection { point: intersect, - normal: self.normal.normalize(), + normal: self.normal, distance: t, }) } + false => return None, } } @@ -271,56 +269,59 @@ impl Primitive for Cylinder { // CONE ----------------------------------------------------------------- #[derive(Clone)] pub struct Cone { - radius: f64, - base: f64, - apex: f64, + height: f64, + constant: f64, circle: Rc, bounding_box: BoundingBox, } impl Cone { - pub fn new(radius: f64, apex: f64, base: f64) -> Rc { + pub fn new(radius: f64, height: f64) -> Rc { let circle = Circle::new( - Point3::new(0.0, base, 0.0), + Point3::new(0.0, 0.0, 0.0), radius, - Vector3::new(0.0, 1.0, 0.0), + Vector3::new(0.0, -1.0, 0.0), ); - let bln = Point3::new(-radius, base, -radius); - let trf = Point3::new(radius, base + apex, radius); + let bln = Point3::new(-radius, 0.0, -radius); + let trf = Point3::new(radius, height, radius); + let constant = radius * radius / (height * height); Rc::new(Cone { - radius: radius / 2.0, - base, - apex, + height, + constant, circle, bounding_box: BoundingBox { bln, trf }, }) } pub fn unit() -> Rc { - Cone::new(1.0, 2.0, -1.0) + Cone::new(0.5, 1.0) } pub fn get_normal(&self, intersect: Point3) -> Vector3 { - let r = self.radius; - let h = self.apex; let (x, y, z) = (intersect.x, intersect.y, intersect.z); - let normal = Vector3::new(2.0 * x, 2.0 * r * r * (h - y), 2.0 * z).normalize(); - normal + let dx = 2.0 * x; + let dy = 2.0 * self.constant * (self.height - y); + let dz = 2.0 * z; + Vector3::new(dx, dy, dz).normalize() } } impl Primitive for Cone { fn intersect_ray(&self, ray: &Ray) -> Option { - let point = &ray.a; - let dir = &ray.b; - let (r, h) = (self.radius, self.apex); - let (a1, a2, a3) = (point.x, point.y, point.z); - let (b1, b2, b3) = (dir.x, dir.y, dir.z); - let r2 = r * r; - let a = b1 * b1 + b3 * b3 - r2 * (b2 * b2); - let b = 2.0 * (a1 * b1 + a3 * b3 + r2 * (h * b2 - a2 * b2)); - let c = a1 * a1 + a3 * a3 + r2 * (2.0 * h * a2 - h * h - a2 * a2); + let k1 = self.constant; + let k2 = self.height; + 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 t = match find_roots_quadratic(a, b, c) { + let t0 = + -c.powf(2.0) * k1 + 2.0 * c * k1 * k2 - k1 * k2.powf(2.0) + a.powf(2.0) + e.powf(2.0); + let t1 = -2.0 * c * d * k1 + 2.0 * d * k1 * k2 + 2.0 * a * b + 2.0 * e * f; + let t2 = -d.powf(2.0) * k1 + b.powf(2.0) + f.powf(2.0); + + let t = match find_roots_quadratic(t2, t1, t0) { Roots::No(_) => None, Roots::One([x1]) => Some(x1), Roots::Two([x1, x2]) => { @@ -341,7 +342,7 @@ impl Primitive for Cone { None => None, Some(t) => { let intersect = ray.at_t(t); - match intersect.y >= self.base && intersect.y <= self.apex { + match intersect.y >= 0.0 && intersect.y <= self.height { true => Some(Intersection { point: intersect, normal: self.get_normal(intersect), @@ -358,14 +359,7 @@ impl Primitive for Cone { (None, None) => None, (Some(cone_intersect), None) => Some(cone_intersect), (None, Some(circle_intersect)) => Some(circle_intersect), - (Some(cone_intersect), Some(circle_intersect)) => { - let circle_distance = distance(&ray.a, &circle_intersect.point); - let cone_distance = distance(&ray.a, &cone_intersect.point); - match cone_distance < circle_distance { - true => Some(cone_intersect), - false => Some(circle_intersect), - } - } + (Some(cone_intersect), Some(_)) => Some(cone_intersect), } } @@ -505,18 +499,19 @@ impl Primitive for Cube { } //Get normal of intersection point + //t1 is bln t2 is trf let normal = if tmin == t1.x { - Vector3::new(1.0, 0.0, 0.0) + Vector3::new(-1.0, 0.0, 0.0) } else if tmin == t1.y { Vector3::new(0.0, -1.0, 0.0) } else if tmin == t1.z { - Vector3::new(0.0, 0.0, 1.0) + Vector3::new(0.0, 0.0, -1.0) } else if tmin == t2.x { - Vector3::new(-1.0, 0.0, 0.0) + Vector3::new(1.0, 0.0, 0.0) } else if tmin == t2.y { Vector3::new(0.0, 1.0, 0.0) } else { - Vector3::new(0.0, 0.0, -1.0) + Vector3::new(0.0, 0.0, 1.0) }; Some(Intersection {