From 91bda4a56fd4e40d7c1ee44691c716356812222f Mon Sep 17 00:00:00 2001 From: STP Date: Mon, 20 Nov 2023 21:15:57 -0500 Subject: [PATCH] Added cylinder primitive --- src/gui.rs | 4 +- src/primitive.rs | 126 ++++++++++++++++++++++++++++++++++++++++++----- src/scene.rs | 23 ++++----- 3 files changed, 127 insertions(+), 26 deletions(-) diff --git a/src/gui.rs b/src/gui.rs index f8e5fee..4f8dfcd 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -2,6 +2,8 @@ use nalgebra::Point3; use pixels::{wgpu, PixelsContext}; use std::time::Instant; +const INIT_FILE: &str = "test.rhai"; + const BUFFER_PROPORTION_INIT: f32 = 1.0; const BUFFER_PROPORTION_MIN: f32 = 0.5; const BUFFER_PROPORTION_MAX: f32 = 1.0; @@ -83,7 +85,7 @@ impl Gui { last_frame: Instant::now(), last_cursor: None, event: None, - filename: String::new(), + filename: String::from(INIT_FILE), ray_num: RAYS_INIT, buffer_proportion: BUFFER_PROPORTION_INIT, camera_eye: Point3::new(CAMERA_INIT, CAMERA_INIT, CAMERA_INIT), diff --git a/src/primitive.rs b/src/primitive.rs index ad53352..5948d1e 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -1,4 +1,3 @@ -#[warn(dead_code)] use crate::ray::Ray; use crate::{EPSILON, EPSILON_VECTOR, INFINITY}; use nalgebra::{distance, Point3, Unit, Vector3}; @@ -255,28 +254,130 @@ impl Primitive for Circle { } // CYLINDER ----------------------------------------------------------------- -struct Cylinder { +#[derive(Clone)] +pub struct Cylinder { radius: f32, base: f32, - height: f32, - base_circle: Circle, - height_circle: Circle, + top: f32, + base_circle: Arc, + top_circle: Arc, material: Arc, + bounding_box: BoundingBox, } -impl Cylinder {} +impl Cylinder { + pub fn new(radius: f32, base: f32, top: f32, material: Arc) -> Arc { + let base_circle = Circle::new( + Point3::new(0.0, base, 0.0), + radius, + Vector3::new(0.0, -1.0, 0.0), + Arc::clone(&material), + ); + let top_circle = Circle::new( + Point3::new(0.0, top, 0.0), + radius, + Vector3::new(0.0, 1.0, 0.0), + Arc::clone(&material), + ); + let bln = Point3::new(-radius, base, -radius); + let trf = Point3::new(radius, top, radius); + Arc::new(Cylinder { + radius, + base, + top, + base_circle, + top_circle, + material, + bounding_box: BoundingBox { bln, trf }, + }) + } +} impl Primitive for Cylinder { fn intersect_ray(&self, ray: &Ray) -> Option { - todo!() - } + let point = &ray.a; + let dir = &ray.b; + let (ax, ay, az) = (point.x, point.y, point.z); + let (bx, by, bz) = (dir.x, dir.y, dir.z); + let a = bx * bx + bz * bz; + let b = 2.0 * ax * bx + 2.0 * az * bz; + let c = ax * ax + az * az - self.radius * self.radius; + let t = match find_roots_quadratic(a, b, c) { + Roots::No(_) => return None, + Roots::One([x1]) => Some(x1), + Roots::Two([x1, x2]) => { + if x1 <= 0.0 && x2 <= 0.0 { + return None; + } else { + if x1.abs() < x2.abs() { + Some(x1) + } else { + Some(x2) + } + } + } + _ => return None, + }; + + let cylinder_intersect = match t { + None => None, + Some(t) => { + let intersect = ray.at_t(t); + if intersect.y >= self.base && intersect.y <= self.top { + let normal = Vector3::new(2.0 * intersect.x, 0.0, 2.0 * intersect.z); + Some(Intersection { + point: intersect, + normal: Unit::new_normalize(normal), + material: Arc::clone(&self.material), + incidence: ray.b, + distance: t, + }) + } else { + None + } + } + }; + let base_intersect = self.base_circle.intersect_ray(ray); + let top_intersect = self.top_circle.intersect_ray(ray); + match (cylinder_intersect, base_intersect, top_intersect) { + (None, None, None) => None, + (Some(intersect), None, None) => Some(intersect), + (None, Some(intersect), None) => Some(intersect), + (None, None, Some(intersect)) => Some(intersect), + (Some(intersect), Some(intersect_base), None) => { + let cylinder_distance = distance(&ray.a, &intersect.point); + let base_distance = distance(&ray.a, &intersect_base.point); + match cylinder_distance < base_distance { + true => Some(intersect), + false => Some(intersect_base), + } + } + (Some(intersect), None, Some(intersect_top)) => { + let cylinder_distance = distance(&ray.a, &intersect.point); + let top_distance = distance(&ray.a, &intersect_top.point); + match cylinder_distance < top_distance { + true => Some(intersect), + false => Some(intersect_top), + } + } + (None, Some(intersect_base), Some(intersect_top)) => { + let base_distance = distance(&ray.a, &intersect_base.point); + let top_distance = distance(&ray.a, &intersect_top.point); + match base_distance < top_distance { + true => Some(intersect_base), + false => Some(intersect_top), + } + } + _ => None, + } + } fn get_material(&self) -> Arc { - todo!() + Arc::clone(&self.material) } fn intersect_bounding_box(&self, ray: &Ray) -> Option> { - todo!() + self.bounding_box.intersect_bounding_box(ray) } } @@ -396,7 +497,8 @@ impl Primitive for Cone { } // RECTANGLE ----------------------------------------------------------------- -struct Rectangle { +#[derive(Clone)] +pub struct Rectangle { position: Point3, normal: Vector3, width_direction: Vector3, @@ -407,7 +509,7 @@ struct Rectangle { } impl Rectangle { - fn new( + pub fn new( position: Point3, normal: Vector3, width_direction: Vector3, diff --git a/src/scene.rs b/src/scene.rs index 132ce9f..2b491b0 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -1,12 +1,6 @@ -#![allow(dead_code)] -#![allow(unused_imports)] -#![allow(unused_variables)] - +use crate::camera::Camera; use crate::light::Light; -use crate::primitive::Primitive; use crate::primitive::*; -use crate::state::State; -use crate::{camera::Camera, state}; use nalgebra::{Matrix4, Point3, Vector3}; use rhai::{Engine, EvalAltResult}; use std::sync::Arc; @@ -144,13 +138,16 @@ impl Scene { .register_fn("Cone", Cone::new) .register_fn("ConeUnit", Cone::unit); engine - .register_type::() - .register_fn("Sphere", Sphere::new) - .register_fn("SphereUnit", Sphere::unit); + .register_type::() + .register_fn("Cylinder", Cylinder::new); engine - .register_type::() - .register_fn("Sphere", Sphere::new) - .register_fn("SphereUnit", Sphere::unit); + .register_type::() + .register_fn("Circle", Circle::new) + .register_fn("CircleUnit", Circle::unit); + engine + .register_type::() + .register_fn("Rectangle", Rectangle::new) + .register_fn("RectangleUnit", Rectangle::unit); let scene: Scene = engine.eval_file(filename.into())?; Ok(scene)