Set up intersection correctly

This commit is contained in:
STP
2023-11-27 16:51:53 -05:00
parent e48bc02daa
commit 5aa73bcc1a
13 changed files with 10723 additions and 280 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
/target /target
/old /old
/help
sagekit.ipynb sagekit.ipynb

10388
obj/cow.obj Normal file

File diff suppressed because it is too large Load Diff

64
rhai/scene.rhai Normal file
View File

@@ -0,0 +1,64 @@
let scene = Scene();
let distance = 10.0;
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 material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
scene.addMaterial("bluegreen", material);
// let light = Light(P(0.0,7.0,0.0), V(0.0,0.0,1.0), V(0.1, 0.01, 0.001));
// scene.addLight("blue", light);
// let light = Light( P(2.0,7.0,0.0), V(0.0,1.0,0.0), V(0.1, 0.01, 0.001));
// scene.addLight("green", light);
let light = Light( P(-2.0,7.0,0.0), V(1.0,0.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight("red", light);
let light = Ambient(V(0.1,0.1,0.1));
scene.addLight("ambient", light);
let sphere = Sphere(P(0.0,0.0,0.0), 1.0, material);
let sphere_node = Node(sphere);
scene.addNode("sphere", sphere_node);
//let mesh = Mesh("obj/cow.obj", material);
//let mesh_node = Node(mesh);
//scene.addNode("mesh", mesh_node);
for i in 0..6 {
let sphere = Sphere(P(0.0,0.0,0.0), 2.0, material);
let sphere_node = Node(sphere);
sphere_node.translate(2.0*cos(i.to_float()), -4.0, 2.0*sin(i.to_float()));
scene.addNode(i.to_string(), sphere_node);
}
// let child = sphere_node.child(sphere);
// child.translate(V(1.0,1.0,1.0));
//scene.addNode(child);
let cube = CubeUnit(material);
let cube_node = Node(cube);
scene.addNode("cube", cube_node);
//let gnonom = Gnonom(material);
//let gnonom_node = Node(gnonom);
//scene.addNode("gnonom", gnonom_node);
//let cylinder = Cylinder(2.0,1.0, material);
//let cylinder_node = Node(cylinder);
//cylinder_node.scale(1.0,1.0,1.0);
//scene.addNode("cylinder",cylinder_node);
scene

34
rhai/sphere.rhai Normal file
View File

@@ -0,0 +1,34 @@
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 sphere = Sphere(P(0.0,0.0,0.0), 1.0, material);
let sphere_node = Node(sphere);
scene.addNode("sphere", sphere_node);
scene

22
rhai/test.rhai Normal file
View File

@@ -0,0 +1,22 @@
let scene = Scene();
let material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
//let ambient = Light(P(10.0,0.0,0.0), V(1.0,1.0,1.0), V(0.0, 0.0, 0.0));
//scene.addLight(ambient);
let light = Light(P(0.0,0.0,2.0), V(0.0,0.0,1.0), V(0.1, 0.01, 0.001));
scene.addLight("blue", light);
let light = Light(P(2.0,0.0,0.0), V(0.0,1.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight("green", light);
let light = Light(P(-2.0,0.0,0.0), V(1.0,0.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight("red", light);
let light = Ambient(V(0.1,0.1,0.1));
scene.addLight("ambient", light);
let stein = Steiner(material);
let stein_node = Node(stein);
scene.addNode("stein", stein_node);
scene

View File

@@ -1,50 +0,0 @@
let scene = Scene();
let camera = Camera( P(0.0,1.0,1.0), P(0.0,0.0,0.0), V(0.0,1.0,0.0));
scene.addCamera("camera", camera);
let material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
scene.addMaterial("bluegreen", material);
let light = Light(P(0.0,7.0,0.0), V(0.0,0.0,1.0), V(0.1, 0.01, 0.001));
scene.addLight("blue", light);
let light = Light( P(2.0,7.0,0.0), V(0.0,1.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight("green", light);
let light = Light( P(-2.0,7.0,0.0), V(1.0,0.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight("red", light);
let light = Ambient(V(0.1,0.1,0.1));
scene.addLight("ambient", light);
let sphere = Sphere(P(0.0,0.0,0.0), 1.0, material);
let sphere_node = Node(sphere);
scene.addNode("sphere", sphere_node);
// for i in 0..6 {
// let sphere = Sphere(P(0.0,0.0,0.0), 2.0, material);
// let sphere_node = Node(sphere);
// sphere_node.translate(2.0*cos(i.to_float()), -4.0, 2.0*sin(i.to_float()));
// scene.addNode(sphere_node);
// }
// let child = sphere_node.child(sphere);
// child.translate(V(1.0,1.0,1.0));
//scene.addNode(child);
// let cube = CubeUnit(material);
// let cube_node = Node(cube);
// scene.addNode(cube_node);
let gnonom = Gnonom(material);
let gnonom_node = Node(gnonom);
scene.addNode("gnonom", gnonom_node);
// let cylinder = Cylinder(10.0,1.0, material);
// let cylinder_node = Node(cylinder);
// //cylinder_node.scale(V(4.0,0.3,0.3));
// cylinder_node.translate(V(0.0,-4.0,0.0));
// scene.addNode(cylinder_node);
scene

View File

@@ -17,17 +17,17 @@ const BUFFER_PROPORTION_MIN: f32 = 0.1;
const BUFFER_PROPORTION_MAX: f32 = 1.0; const BUFFER_PROPORTION_MAX: f32 = 1.0;
//RAY CONSTANTS //RAY CONSTANTS
const RAYS_INIT: i32 = 7000; const RAYS_INIT: i32 = 100;
const RAYS_MIN: i32 = 100; const RAYS_MIN: i32 = 100;
const RAYS_MAX: i32 = 30000; const RAYS_MAX: i32 = 10000;
//MATERIAL CONSTANTS //MATERIAL CONSTANTS
const MIN_D: f32 = 0.0; // const MIN_D: f32 = 0.0;
const MIN_S: f32 = 0.0; // const MIN_S: f32 = 0.0;
const MIN_SHINE: f32 = 0.0; // const MIN_SHINE: f32 = 0.0;
const MAX_D: f32 = 1.0; // const MAX_D: f32 = 1.0;
const MAX_S: f32 = 1.0; // const MAX_S: f32 = 1.0;
const MAX_SHINE: f32 = 50.0; // const MAX_SHINE: f32 = 50.0;
//TRANSFORMATION CONSTANTS //TRANSFORMATION CONSTANTS
const MIN_COLOUR: f32 = 0.0; const MIN_COLOUR: f32 = 0.0;
@@ -310,12 +310,9 @@ impl Gui {
//Use different cameras in the scene //Use different cameras in the scene
if let Some(_t) = ui.tree_node("Cameras") { if let Some(_t) = ui.tree_node("Cameras") {
for (label, camera) in &self.scene.cameras { for (label, camera) in &self.scene.cameras {
if let Some(_t) = ui.tree_node(label) { if ui.button(label) {
if ui.button("Use camera") {
self.camera = camera.clone(); self.camera = camera.clone();
self.event = self.event = Some(GuiEvent::CameraUpdate(camera.clone(), self.camera_fov));
Some(GuiEvent::CameraUpdate(camera.clone(), self.camera_fov));
}
} }
} }
} }
@@ -413,9 +410,9 @@ pub fn init_engine() -> Engine {
.register_fn("Circle", Circle::new) .register_fn("Circle", Circle::new)
.register_fn("CircleUnit", Circle::unit); .register_fn("CircleUnit", Circle::unit);
engine engine
.register_type::<Rectangle>() .register_type::<Cube>()
.register_fn("Rectangle", Rectangle::new) .register_fn("Cube", Cube::new)
.register_fn("RectangleUnit", Rectangle::unit); .register_fn("CubeUnit", Cube::unit);
engine engine
.register_type::<SteinerSurface>() .register_type::<SteinerSurface>()
.register_fn("Steiner", SteinerSurface::new); .register_fn("Steiner", SteinerSurface::new);

View File

@@ -5,7 +5,7 @@ use nalgebra::{distance, Matrix4, Point3, Vector3};
use roots::{find_roots_quadratic, find_roots_quartic, 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::rc::Rc;
// MATERIAL ----------------------------------------------------------------- // MATERIAL -----------------------------------------------------------------
#[derive(Clone)] #[derive(Clone)]
pub struct Material { pub struct Material {
@@ -15,41 +15,41 @@ pub struct Material {
} }
impl Material { impl Material {
pub fn new(kd: Vector3<f64>, ks: Vector3<f64>, shininess: f64) -> Arc<Self> { pub fn new(kd: Vector3<f64>, ks: Vector3<f64>, shininess: f64) -> Rc<Self> {
let kd = kd.cast(); let kd = kd.cast();
let ks = ks.cast(); let ks = ks.cast();
let shininess = shininess as f32; let shininess = shininess as f32;
Arc::new(Material { kd, ks, shininess }) Rc::new(Material { kd, ks, shininess })
} }
pub fn magenta() -> Arc<Self> { pub fn magenta() -> Rc<Self> {
let kd = Vector3::new(1.0, 0.0, 1.0); let kd = Vector3::new(1.0, 0.0, 1.0);
let ks = Vector3::new(1.0, 0.0, 1.0); let ks = Vector3::new(1.0, 0.0, 1.0);
let shininess = 0.5; let shininess = 0.5;
Arc::new(Material { kd, ks, shininess }) Rc::new(Material { kd, ks, shininess })
} }
pub fn turquoise() -> Arc<Self> { pub fn turquoise() -> Rc<Self> {
let kd = Vector3::new(0.25, 0.3, 0.7); let kd = Vector3::new(0.25, 0.3, 0.7);
let ks = Vector3::new(0.25, 0.3, 0.7); let ks = Vector3::new(0.25, 0.3, 0.7);
let shininess = 0.5; let shininess = 0.5;
Arc::new(Material { kd, ks, shininess }) Rc::new(Material { kd, ks, shininess })
} }
pub fn red() -> Arc<Self> { pub fn red() -> Rc<Self> {
let kd = Vector3::new(0.8, 0.0, 0.3); let kd = Vector3::new(0.8, 0.0, 0.3);
let ks = Vector3::new(0.8, 0.3, 0.0); let ks = Vector3::new(0.8, 0.3, 0.0);
let shininess = 0.5; let shininess = 0.5;
Arc::new(Material { kd, ks, shininess }) Rc::new(Material { kd, ks, shininess })
} }
pub fn blue() -> Arc<Self> { pub fn blue() -> Rc<Self> {
let kd = Vector3::new(0.0, 0.3, 0.6); let kd = Vector3::new(0.0, 0.3, 0.6);
let ks = Vector3::new(0.3, 0.0, 0.6); let ks = Vector3::new(0.3, 0.0, 0.6);
let shininess = 0.5; let shininess = 0.5;
Arc::new(Material { kd, ks, shininess }) Rc::new(Material { kd, ks, shininess })
} }
pub fn green() -> Arc<Self> { pub fn green() -> Rc<Self> {
let kd = Vector3::new(0.0, 1.0, 0.0); let kd = Vector3::new(0.0, 1.0, 0.0);
let ks = Vector3::new(0.0, 1.0, 0.0); let ks = Vector3::new(0.0, 1.0, 0.0);
let shininess = 0.5; let shininess = 0.5;
Arc::new(Material { kd, ks, shininess }) Rc::new(Material { kd, ks, shininess })
} }
} }
@@ -59,7 +59,7 @@ pub struct Intersection {
pub point: Point3<f64>, pub point: Point3<f64>,
pub normal: Vector3<f64>, pub normal: Vector3<f64>,
pub incidence: Vector3<f64>, pub incidence: Vector3<f64>,
pub material: Arc<Material>, pub material: Rc<Material>,
pub distance: f64, pub distance: f64,
} }
impl Intersection { impl Intersection {
@@ -76,7 +76,6 @@ impl Intersection {
// BOUNDING BOX ----------------------------------------------------------------- // BOUNDING BOX -----------------------------------------------------------------
#[derive(Clone)] #[derive(Clone)]
struct BoundingBox { struct BoundingBox {
bln: Point3<f64>, bln: Point3<f64>,
trf: Point3<f64>, trf: Point3<f64>,
@@ -88,29 +87,41 @@ impl BoundingBox {
let trf = trf - Vector3::new(EPSILON, EPSILON, EPSILON); let trf = trf - Vector3::new(EPSILON, EPSILON, EPSILON);
BoundingBox { bln, trf } BoundingBox { bln, trf }
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
let t1 = (self.bln - ray.a).component_div(&ray.b); let bln = &self.bln;
let t2 = (self.trf - ray.a).component_div(&ray.b); let trf = &self.trf;
let t1 = (bln - ray.a).component_div(&ray.b);
let t2 = (trf - ray.a).component_div(&ray.b);
let tmin = t1.inf(&t2).min(); let tmin = t1.inf(&t2).min();
let tmax = t1.sup(&t2).max(); let tmax = t1.sup(&t2).max();
if tmax >= tmin { if tmax >= tmin {
Some(ray.at_t(tmin)) let intersect = ray.at_t(tmin);
} else {
None // Check if the intersection is inside the box
if intersect.x > bln.x - EPSILON
|| intersect.x < trf.x + EPSILON
|| intersect.y > bln.y - EPSILON
|| intersect.y < trf.y + EPSILON
|| intersect.z > bln.z - EPSILON
|| intersect.z < trf.z + EPSILON
{
return true; // Intersection is outside the box
} }
} }
false
}
#[allow(dead_code)] #[allow(dead_code)]
fn get_centroid(&self) -> Point3<f64> { fn get_centroid(&self) -> Point3<f64> {
self.bln + (self.trf - self.bln) / 2.0 self.bln + (self.trf - self.bln) / 2.0
} }
} }
// PRIMITIVE TRAIT ----------------------------------------------------------------- // PRIMITIVE TRAIT -----------------------------------------------------------------
pub trait Primitive: Send + Sync { pub trait Primitive {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection>; fn intersect_ray(&self, ray: &Ray) -> Option<Intersection>;
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>>; fn intersect_bounding_box(&self, ray: &Ray) -> bool;
fn get_material(&self) -> Arc<Material>; fn get_material(&self) -> Rc<Material>;
} }
// SPHERE ----------------------------------------------------------------- // SPHERE -----------------------------------------------------------------
@@ -119,16 +130,16 @@ pub struct Sphere {
position: Point3<f64>, position: Point3<f64>,
radius: f64, radius: f64,
bounding_box: BoundingBox, bounding_box: BoundingBox,
material: Arc<Material>, material: Rc<Material>,
} }
impl Sphere { impl Sphere {
pub fn new(position: Point3<f64>, radius: f64, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(position: Point3<f64>, radius: f64, material: Rc<Material>) -> Rc<dyn Primitive> {
let radius_vec = Vector3::new(radius, radius, radius); let radius_vec = Vector3::new(radius, radius, radius);
let bln = position - radius_vec; let bln = position - radius_vec;
let trf = position + radius_vec; let trf = position + radius_vec;
let bounding_box = BoundingBox::new(bln, trf); let bounding_box = BoundingBox::new(bln, trf);
Arc::new(Sphere { Rc::new(Sphere {
position, position,
radius, radius,
bounding_box, bounding_box,
@@ -136,7 +147,7 @@ impl Sphere {
}) })
} }
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn unit(material: Rc<Material>) -> Rc<dyn Primitive> {
Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, material) Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, material)
} }
} }
@@ -175,16 +186,16 @@ impl Primitive for Sphere {
point: intersect, point: intersect,
normal, normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}) })
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
return self.bounding_box.intersect_bounding_box(ray); return self.bounding_box.intersect_bounding_box(ray);
} }
} }
@@ -195,7 +206,7 @@ pub struct Circle {
position: Point3<f64>, position: Point3<f64>,
radius: f64, radius: f64,
normal: Vector3<f64>, normal: Vector3<f64>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
@@ -204,13 +215,13 @@ impl Circle {
position: Point3<f64>, position: Point3<f64>,
radius: f64, radius: f64,
normal: Vector3<f64>, normal: Vector3<f64>,
material: Arc<Material>, material: Rc<Material>,
) -> Arc<dyn Primitive> { ) -> Rc<dyn Primitive> {
let radius_vec = Vector3::new(radius, radius, radius); let radius_vec = Vector3::new(radius, radius, radius);
let bln = position - radius_vec; let bln = position - radius_vec;
let trf = position + radius_vec; let trf = position + radius_vec;
let bounding_box = BoundingBox::new(bln, trf); let bounding_box = BoundingBox::new(bln, trf);
Arc::new(Circle { Rc::new(Circle {
position, position,
radius, radius,
normal: normal.normalize(), normal: normal.normalize(),
@@ -219,7 +230,7 @@ impl Circle {
}) })
} }
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn unit(material: Rc<Material>) -> Rc<dyn Primitive> {
let position = Point3::new(0.0, 0.0, 0.0); 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, 1.0, 0.0);
let radius = 1.0; let radius = 1.0;
@@ -229,7 +240,7 @@ impl Circle {
let trf = Point3::new(radius, 0.0, EPSILON); let trf = Point3::new(radius, 0.0, EPSILON);
let bounding_box = BoundingBox { bln, trf }; let bounding_box = BoundingBox { bln, trf };
Arc::new(Circle { Rc::new(Circle {
position, position,
normal, normal,
radius, radius,
@@ -256,18 +267,18 @@ impl Primitive for Circle {
point: intersect, point: intersect,
normal: self.normal.normalize(), normal: self.normal.normalize(),
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}) })
} }
} }
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
} }
@@ -277,29 +288,29 @@ impl Primitive for Circle {
pub struct Cylinder { pub struct Cylinder {
radius: f64, radius: f64,
height: f64, height: f64,
base_circle: Arc<dyn Primitive>, base_circle: Rc<dyn Primitive>,
top_circle: Arc<dyn Primitive>, top_circle: Rc<dyn Primitive>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl Cylinder { impl Cylinder {
pub fn new(radius: f64, height: f64, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(radius: f64, height: f64, material: Rc<Material>) -> Rc<dyn Primitive> {
let base_circle = Circle::new( let base_circle = Circle::new(
Point3::new(0.0, 0.0, 0.0), Point3::new(0.0, 0.0, 0.0),
radius, radius,
Vector3::new(0.0, -1.0, 0.0), Vector3::new(0.0, -1.0, 0.0),
Arc::clone(&material), Rc::clone(&material),
); );
let top_circle = Circle::new( let top_circle = Circle::new(
Point3::new(0.0, height, 0.0), Point3::new(0.0, height, 0.0),
radius, radius,
Vector3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0),
Arc::clone(&material), Rc::clone(&material),
); );
let bln = Point3::new(-radius, 0.0, -radius); let bln = Point3::new(-radius, 0.0, -radius);
let trf = Point3::new(radius, height, radius); let trf = Point3::new(radius, height, radius);
Arc::new(Cylinder { Rc::new(Cylinder {
radius, radius,
height, height,
base_circle, base_circle,
@@ -347,7 +358,7 @@ impl Primitive for Cylinder {
point: intersect, point: intersect,
normal: normal, normal: normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}) })
} else { } else {
@@ -390,11 +401,11 @@ impl Primitive for Cylinder {
} }
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
} }
@@ -405,22 +416,22 @@ pub struct Cone {
radius: f64, radius: f64,
base: f64, base: f64,
apex: f64, apex: f64,
circle: Arc<dyn Primitive>, circle: Rc<dyn Primitive>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl Cone { impl Cone {
pub fn new(radius: f64, apex: f64, base: f64, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(radius: f64, apex: f64, base: f64, material: Rc<Material>) -> Rc<dyn Primitive> {
let circle = Circle::new( let circle = Circle::new(
Point3::new(0.0, base, 0.0), Point3::new(0.0, base, 0.0),
radius, radius,
Vector3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0),
Arc::clone(&material), Rc::clone(&material),
); );
let bln = Point3::new(-radius, base, -radius); let bln = Point3::new(-radius, base, -radius);
let trf = Point3::new(radius, base + apex, radius); let trf = Point3::new(radius, base + apex, radius);
Arc::new(Cone { Rc::new(Cone {
radius: radius / 2.0, radius: radius / 2.0,
base, base,
apex, apex,
@@ -429,7 +440,7 @@ impl Cone {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
}) })
} }
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn unit(material: Rc<Material>) -> Rc<dyn Primitive> {
Cone::new(1.0, 2.0, -1.0, material) Cone::new(1.0, 2.0, -1.0, material)
} }
@@ -480,7 +491,7 @@ impl Primitive for Cone {
point: intersect, point: intersect,
normal: self.get_normal(intersect), normal: self.get_normal(intersect),
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}), }),
false => None, false => None,
@@ -505,11 +516,11 @@ impl Primitive for Cone {
} }
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
} }
@@ -520,7 +531,7 @@ pub struct Rectangle {
position: Point3<f64>, position: Point3<f64>,
normal: Vector3<f64>, normal: Vector3<f64>,
width_direction: Vector3<f64>, width_direction: Vector3<f64>,
material: Arc<Material>, material: Rc<Material>,
width: f64, width: f64,
height: f64, height: f64,
bounding_box: BoundingBox, bounding_box: BoundingBox,
@@ -533,14 +544,14 @@ impl Rectangle {
width_direction: Vector3<f64>, width_direction: Vector3<f64>,
width: f64, width: f64,
height: f64, height: f64,
material: Arc<Material>, material: Rc<Material>,
) -> Arc<dyn Primitive> { ) -> Rc<dyn Primitive> {
let normal = normal.normalize(); let normal = normal.normalize();
let width_direction = width_direction.normalize(); let width_direction = width_direction.normalize();
let height_direction = width_direction.cross(&normal); let height_direction = width_direction.cross(&normal);
let bln = position - width / 2.0 * width_direction - height / 2.0 * height_direction; let bln = position - width / 2.0 * width_direction - height / 2.0 * height_direction;
let trf = position + width / 2.0 * width_direction + height / 2.0 * height_direction; let trf = position + width / 2.0 * width_direction + height / 2.0 * height_direction;
Arc::new(Rectangle { Rc::new(Rectangle {
position, position,
normal: normal.normalize(), normal: normal.normalize(),
width_direction: width_direction.normalize(), width_direction: width_direction.normalize(),
@@ -550,7 +561,7 @@ impl Rectangle {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
}) })
} }
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn unit(material: Rc<Material>) -> Rc<dyn Primitive> {
Rectangle::new( Rectangle::new(
Point3::new(0.0, 0.0, 0.0), Point3::new(0.0, 0.0, 0.0),
Vector3::new(0.0, 1.0, 0.0), Vector3::new(0.0, 1.0, 0.0),
@@ -586,18 +597,18 @@ impl Primitive for Rectangle {
point: intersect, point: intersect,
normal: self.normal, normal: self.normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}); });
} }
None None
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
} }
@@ -607,13 +618,13 @@ impl Primitive for Rectangle {
pub struct Cube { pub struct Cube {
bln: Point3<f64>, bln: Point3<f64>,
trf: Point3<f64>, trf: Point3<f64>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl Cube { impl Cube {
pub fn new(bln: Point3<f64>, trf: Point3<f64>, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(bln: Point3<f64>, trf: Point3<f64>, material: Rc<Material>) -> Rc<dyn Primitive> {
Arc::new(Cube { Rc::new(Cube {
bln, bln,
trf, trf,
material, material,
@@ -621,7 +632,7 @@ impl Cube {
}) })
} }
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn unit(material: Rc<Material>) -> Rc<dyn Primitive> {
let bln = Point3::new(-1.0, -1.0, -1.0); let bln = Point3::new(-1.0, -1.0, -1.0);
let trf = Point3::new(1.0, 1.0, 1.0); let trf = Point3::new(1.0, 1.0, 1.0);
Cube::new(bln, trf, material) Cube::new(bln, trf, material)
@@ -646,12 +657,12 @@ impl Primitive for Cube {
let intersect = ray.at_t(tmin); let intersect = ray.at_t(tmin);
// Check if the intersection is outside the box // Check if the intersection is outside the box
if intersect.x < bln.x if intersect.x < bln.x - EPSILON
|| intersect.x > trf.x || intersect.x > trf.x + EPSILON
|| intersect.y < bln.y || intersect.y < bln.y - EPSILON
|| intersect.y > trf.y || intersect.y > trf.y + EPSILON
|| intersect.z < bln.z || intersect.z < bln.z - EPSILON
|| intersect.z > trf.z || intersect.z > trf.z + EPSILON
{ {
return None; // Intersection is outside the box return None; // Intersection is outside the box
} }
@@ -675,7 +686,7 @@ impl Primitive for Cube {
point: intersect, point: intersect,
normal: normal, normal: normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: tmin, distance: tmin,
}) })
} else { } else {
@@ -683,12 +694,12 @@ impl Primitive for Cube {
} }
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
} }
@@ -700,7 +711,7 @@ pub struct Triangle {
v: Point3<f64>, v: Point3<f64>,
w: Point3<f64>, w: Point3<f64>,
normal: Vector3<f64>, normal: Vector3<f64>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
@@ -709,15 +720,15 @@ impl Triangle {
u: Point3<f64>, u: Point3<f64>,
v: Point3<f64>, v: Point3<f64>,
w: Point3<f64>, w: Point3<f64>,
material: Arc<Material>, material: Rc<Material>,
) -> Arc<dyn Primitive> { ) -> Rc<dyn Primitive> {
let uv = v - u; let uv = v - u;
let uw = w - u; let uw = w - u;
let normal = uv.cross(&uw).normalize(); let normal = uv.cross(&uw).normalize();
let bln = u.inf(&v).inf(&w); let bln = u.inf(&v).inf(&w);
let trf = u.sup(&v).sup(&w); let trf = u.sup(&v).sup(&w);
let bounding_box = BoundingBox { bln, trf }; let bounding_box = BoundingBox { bln, trf };
Arc::new(Triangle { Rc::new(Triangle {
u, u,
v, v,
w, w,
@@ -727,7 +738,7 @@ impl Triangle {
}) })
} }
#[allow(dead_code)] #[allow(dead_code)]
pub fn unit(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn unit(material: Rc<Material>) -> Rc<dyn Primitive> {
let u = Point3::new(-1.0, 0.0, -1.0); let u = Point3::new(-1.0, 0.0, -1.0);
let v = Point3::new(0.0, 0.0, 1.0); let v = Point3::new(0.0, 0.0, 1.0);
let w = Point3::new(1.0, 0.0, -1.0); let w = Point3::new(1.0, 0.0, -1.0);
@@ -768,7 +779,7 @@ impl Primitive for Triangle {
point: intersect, point: intersect,
normal: normal, normal: normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}) })
} else { } else {
@@ -776,11 +787,11 @@ impl Primitive for Triangle {
} }
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
} }
@@ -788,33 +799,29 @@ impl Primitive for Triangle {
// MESH ----------------------------------------------------------------- // MESH -----------------------------------------------------------------
#[derive(Clone)] #[derive(Clone)]
pub struct Mesh { pub struct Mesh {
triangles: Vec<Arc<Triangle>>, triangles: Vec<Triangle>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl Mesh { impl Mesh {
#[allow(dead_code)] pub fn new(triangles: Vec<Triangle>, material: Rc<Material>) -> Rc<dyn Primitive> {
pub fn new(triangles: Vec<Arc<Triangle>>, material: Arc<Material>) -> Arc<dyn Primitive> {
// Calculate the bounding box for the entire mesh based on the bounding boxes of individual triangles // Calculate the bounding box for the entire mesh based on the bounding boxes of individual triangles
let bounding_box = Mesh::compute_bounding_box(&triangles); let bounding_box = Mesh::compute_bounding_box(&triangles);
Rc::new(Mesh {
Arc::new(Mesh {
triangles, triangles,
material, material,
bounding_box, bounding_box,
}) })
} }
#[allow(dead_code)] fn compute_bounding_box(triangles: &Vec<Triangle>) -> BoundingBox {
fn compute_bounding_box(triangles: &Vec<Arc<Triangle>>) -> BoundingBox {
let mut bln = Point3::new(INFINITY, INFINITY, INFINITY); let mut bln = Point3::new(INFINITY, INFINITY, INFINITY);
let mut trf = -bln; let mut trf = -bln;
for triangle in triangles { for triangle in triangles {
bln = bln.inf(&triangle.u); bln = bln.inf(&triangle.u);
bln = bln.inf(&triangle.v); bln = bln.inf(&triangle.v);
bln = bln.inf(&triangle.w); bln = bln.inf(&triangle.w);
trf = trf.sup(&triangle.u); trf = trf.sup(&triangle.u);
trf = trf.sup(&triangle.v); trf = trf.sup(&triangle.v);
trf = trf.sup(&triangle.w); trf = trf.sup(&triangle.w);
@@ -822,8 +829,8 @@ impl Mesh {
BoundingBox { bln, trf } BoundingBox { bln, trf }
} }
pub fn from_file(filename: &str, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn from_file(filename: &str, material: Rc<Material>) -> Rc<dyn Primitive> {
let mut triangles: Vec<Arc<dyn Primitive>> = Vec::new(); let mut triangles: Vec<Triangle> = Vec::new();
let mut vertices: Vec<Point3<f64>> = Vec::new(); let mut vertices: Vec<Point3<f64>> = Vec::new();
let file = File::open(filename).expect("Failed to open file"); let file = File::open(filename).expect("Failed to open file");
@@ -857,10 +864,24 @@ impl Mesh {
let v3: usize = let v3: usize =
v3_str.parse().expect("Failed to parse vertex index"); v3_str.parse().expect("Failed to parse vertex index");
// Indices in OBJ files are 1-based, so subtract 1 to convert to 0-based. // Indices in OBJ files are 1-based, so subtract 1 to convert to 0-based.
let a = vertices[v1 - 1]; let u = vertices[v1 - 1];
let b = vertices[v2 - 1]; let v = vertices[v2 - 1];
let c = vertices[v3 - 1]; let w = vertices[v3 - 1];
triangles.push(Triangle::new(a, b, c, Arc::clone(&material))); let uv = u - v;
let uw = w - v;
let normal = uv.cross(&uw).normalize();
let bln = u.inf(&v).inf(&w);
let trf = u.sup(&v).sup(&w);
let bounding_box = BoundingBox { bln, trf };
let material = material.clone();
triangles.push(Triangle {
u,
v,
w,
normal,
material,
bounding_box,
});
} }
} }
_ => {} _ => {}
@@ -868,7 +889,7 @@ impl Mesh {
} }
} }
} }
todo!(); Mesh::new(triangles, material)
} }
} }
@@ -893,11 +914,11 @@ impl Primitive for Mesh {
closest_intersect closest_intersect
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
} }
@@ -905,16 +926,16 @@ impl Primitive for Mesh {
// STEINER ----------------------------------------------------------------- // STEINER -----------------------------------------------------------------
#[derive(Clone)] #[derive(Clone)]
pub struct SteinerSurface { pub struct SteinerSurface {
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl SteinerSurface { impl SteinerSurface {
pub fn new(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(material: Rc<Material>) -> Rc<dyn Primitive> {
// I need to find the bounding box for this shape // I need to find the bounding box for this shape
let trf = Point3::new(1.0, 1.0, 1.0); let trf = Point3::new(1.0, 1.0, 1.0);
let bln = Point3::new(-1.0, -1.0, -1.0); let bln = Point3::new(-1.0, -1.0, -1.0);
Arc::new(SteinerSurface { Rc::new(SteinerSurface {
material, material,
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
}) })
@@ -989,17 +1010,17 @@ impl Primitive for SteinerSurface {
point, point,
normal, normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}) })
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
} }
@@ -1017,16 +1038,16 @@ fn smallest_non_zero(arr: &[f64]) -> Option<f64> {
pub struct Torus { pub struct Torus {
inner_rad: f64, inner_rad: f64,
outer_rad: f64, outer_rad: f64,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl Torus { impl Torus {
pub fn new(inner_rad: f64, outer_rad: f64, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(inner_rad: f64, outer_rad: f64, material: Rc<Material>) -> Rc<dyn Primitive> {
// I need to find the bounding box for this shape // I need to find the bounding box for this shape
let trf = Point3::new(1.0, 1.0, 1.0); let trf = Point3::new(1.0, 1.0, 1.0);
let bln = Point3::new(-1.0, -1.0, -1.0); let bln = Point3::new(-1.0, -1.0, -1.0);
Arc::new(Torus { Rc::new(Torus {
inner_rad, inner_rad,
outer_rad, outer_rad,
material, material,
@@ -1133,34 +1154,34 @@ impl Primitive for Torus {
point, point,
normal, normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material), material: Rc::clone(&self.material),
distance: t, distance: t,
}) })
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
Arc::clone(&self.material) Rc::clone(&self.material)
} }
} }
// GNOMON ----------------------------------------------------------------- // GNOMON -----------------------------------------------------------------
#[derive(Clone)] #[derive(Clone)]
pub struct Gnonom { pub struct Gnonom {
x_cube: Arc<dyn Primitive>, x_cube: Rc<dyn Primitive>,
y_cube: Arc<dyn Primitive>, y_cube: Rc<dyn Primitive>,
z_cube: Arc<dyn Primitive>, z_cube: Rc<dyn Primitive>,
material: Arc<Material>, material: Rc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl Gnonom { impl Gnonom {
const GNONOM_WIDTH: f64 = 0.1; const GNONOM_WIDTH: f64 = 0.1;
const GNONOM_LENGTH: f64 = 2.0; const GNONOM_LENGTH: f64 = 2.0;
pub fn new(material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(material: Rc<Material>) -> Rc<dyn Primitive> {
let x_cube = Cube::new( let x_cube = Cube::new(
Point3::new(0.0, -Self::GNONOM_WIDTH, -Self::GNONOM_WIDTH), Point3::new(0.0, -Self::GNONOM_WIDTH, -Self::GNONOM_WIDTH),
Point3::new(Self::GNONOM_LENGTH, Self::GNONOM_WIDTH, Self::GNONOM_WIDTH), Point3::new(Self::GNONOM_LENGTH, Self::GNONOM_WIDTH, Self::GNONOM_WIDTH),
@@ -1188,7 +1209,7 @@ impl Gnonom {
Self::GNONOM_LENGTH, Self::GNONOM_LENGTH,
), ),
}; };
Arc::new(Gnonom { Rc::new(Gnonom {
x_cube, x_cube,
y_cube, y_cube,
z_cube, z_cube,
@@ -1215,11 +1236,11 @@ impl Primitive for Gnonom {
None None
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> { fn intersect_bounding_box(&self, ray: &Ray) -> bool {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
fn get_material(&self) -> Arc<Material> { fn get_material(&self) -> Rc<Material> {
self.material.clone() self.material.clone()
} }
} }

View File

@@ -1,10 +1,5 @@
use crate::{ use crate::{primitive::Intersection, raytracer::phong_shade_point, scene::Scene};
primitive::Intersection,
raytracer::phong_shade_point,
scene::{Node, Scene},
};
use nalgebra::{Matrix4, Point3, Vector3}; use nalgebra::{Matrix4, Point3, Vector3};
use std::collections::HashMap;
#[derive(Clone)] #[derive(Clone)]
// Ray struct represents a ray in 3D space with a starting point 'a' and a direction 'b' // Ray struct represents a ray in 3D space with a starting point 'a' and a direction 'b'
@@ -35,42 +30,39 @@ impl Ray {
// This function takes a scene and returns the color of the point where the ray intersects the scene // This function takes a scene and returns the color of the point where the ray intersects the scene
pub fn shade_ray(&self, scene: &Scene) -> Option<Vector3<u8>> { pub fn shade_ray(&self, scene: &Scene) -> Option<Vector3<u8>> {
//Get the closest intersection of the ray with the scene //Get the closest intersection of the ray with the scene
let intersect = self.get_closest_intersection(&scene.nodes); let mut closest_distance = f64::MAX;
let mut closest_intersect: Option<Intersection> = None;
let mut closest_node = None;
for (_, node) in &scene.nodes {
// Transform ray into local model cordinates
let ray = self.transform(&node.inv_model);
// Check bounding box intersection
if node.primitive.intersect_bounding_box(&ray) {
// Check primitive intersection
if let Some(intersect) = node.primitive.intersect_ray(&ray) {
// Check for closest distance
if intersect.distance < closest_distance {
closest_distance = intersect.distance;
closest_intersect = Some(intersect);
closest_node = Some(node);
}
}
}
}
//Shade the intersection point if there is one //Shade the intersection point if there is one
match intersect { match closest_intersect {
Some(intersect) => Some(phong_shade_point(&scene, &intersect)), // If there is an intersection, shade it Some(intersect) => {
//Inverse transform back to world coords
let node = closest_node.unwrap();
let intersect = intersect.transform(&node.model, &node.inv_model);
Some(phong_shade_point(&scene, &intersect)) // If there is an intersection, shade it
}
None => None, // If there is no intersection, return None None => None, // If there is no intersection, return None
} }
} }
// Find the closest intersection
pub fn get_closest_intersection(&self, nodes: &HashMap<String, Node>) -> Option<Intersection> {
//Assign no intersection
let mut closest_distance = f64::MAX;
let mut closest_intersect: Option<Intersection> = None;
for (_, node) in nodes {
// Clone arc to primitive
let primitive = node.primitive.clone();
// Transform ray into local model cordinates
let ray = self.transform(&node.inv_model);
// Check bounding box intersection
if primitive.intersect_bounding_box(&ray).is_some() {
// Check primitive intersection
if let Some(intersect) = primitive.intersect_ray(&ray) {
// Check for closest distance
if intersect.distance < closest_distance {
closest_distance = intersect.distance;
//Convert back to world coords
let intersect = intersect.transform(&node.model, &node.inv_model);
closest_intersect = Some(intersect);
}
}
}
}
//Return None if we find no intersection, some if we do find one
closest_intersect
}
// Return a transformed version of the ray // Return a transformed version of the ray
pub fn transform(&self, trans: &Matrix4<f64>) -> Ray { pub fn transform(&self, trans: &Matrix4<f64>) -> Ray {
Ray { Ray {

View File

@@ -1,21 +1,21 @@
use crate::{light::Light, primitive::Intersection, ray::Ray, scene::*, EPSILON}; use crate::{light::Light, primitive::Intersection, ray::Ray, scene::*};
use nalgebra::{Unit, Vector3}; use nalgebra::Vector3;
// Function to shade a point in the scene using Phong shading model // Function to shade a point in the scene using Phong shading model
pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8> { pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8> {
let Intersection { let point = &intersect.point;
point, let material = &intersect.material;
normal, let normal = &intersect.normal;
incidence, let incidence = &intersect.incidence;
material,
..
} = intersect;
let kd = material.kd; let kd = &material.kd;
let ks = material.ks; let ks = &material.ks;
let shininess = material.shininess; let shininess = material.shininess;
// Point to camera
let to_camera = -incidence;
// Compute the ambient light component and set it as base colour // Compute the ambient light component and set it as base colour
let mut colour = Vector3::zeros(); let mut colour = Vector3::zeros();
@@ -37,13 +37,11 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
let light_distance = to_light.norm() as f32; let light_distance = to_light.norm() as f32;
let to_light = to_light; let to_light = to_light;
let to_light_ray = Ray::new(point.clone() + normal * EPSILON, to_light); //let to_light_ray = Ray::new(point.clone() + normal * EPSILON, to_light);
if light_blocked(scene, to_light_ray) { // if light_blocked(scene, to_light_ray) {
continue; // continue;
} // }
// Point to camera
let to_camera = -incidence;
// Diffuse component // Diffuse component
let n_dot_l = normal.dot(&to_light).max(0.0) as f32; let n_dot_l = normal.dot(&to_light).max(0.0) as f32;
let diffuse = n_dot_l * kd; let diffuse = n_dot_l * kd;
@@ -51,11 +49,10 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
let mut specular = Vector3::zeros(); let mut specular = Vector3::zeros();
if n_dot_l > 0.0 { if n_dot_l > 0.0 {
// Halfway vector. // Halfway vector.
let h = Unit::new_normalize(to_camera.lerp(&to_light, 0.5)); let h = to_camera + to_light.normalize();
let n_dot_h = normal.dot(&h).max(0.0) as f32; let n_dot_h = normal.dot(&h).max(0.0) as f32;
specular = ks * n_dot_h.powf(shininess); specular = ks * n_dot_h.powf(shininess);
} }
// Compute light falloff // Compute light falloff
let falloff = 1.0 let falloff = 1.0
/ (1.0 / (1.0
@@ -75,7 +72,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
fn light_blocked(scene: &Scene, ray: Ray) -> bool { fn light_blocked(scene: &Scene, ray: Ray) -> bool {
for (_, node) in &scene.nodes { for (_, node) in &scene.nodes {
let ray = ray.transform(&node.inv_model); let ray = ray.transform(&node.inv_model);
if node.primitive.intersect_bounding_box(&ray).is_some() { if node.primitive.intersect_bounding_box(&ray) {
if node.primitive.intersect_ray(&ray).is_some() { if node.primitive.intersect_ray(&ray).is_some() {
return true; return true;
} }

View File

@@ -3,11 +3,11 @@ use crate::light::Light;
use crate::primitive::*; use crate::primitive::*;
use nalgebra::{Matrix4, Vector3}; use nalgebra::{Matrix4, Vector3};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
pub struct Node { pub struct Node {
//Primitive //Primitive
pub primitive: Arc<dyn Primitive>, pub primitive: Rc<dyn Primitive>,
//Transformations //Transformations
pub rotation: [f64; 3], pub rotation: [f64; 3],
pub scale: [f64; 3], pub scale: [f64; 3],
@@ -19,7 +19,7 @@ pub struct Node {
impl Node { impl Node {
//New node with no transformations //New node with no transformations
pub fn new(primitive: Arc<dyn Primitive>) -> Node { pub fn new(primitive: Rc<dyn Primitive>) -> Node {
Node { Node {
primitive, primitive,
rotation: [0.0, 0.0, 0.0], rotation: [0.0, 0.0, 0.0],
@@ -30,7 +30,7 @@ impl Node {
} }
} }
//New node with parent transformations //New node with parent transformations
pub fn child(self, primitive: Arc<dyn Primitive>) -> Node { pub fn child(self, primitive: Rc<dyn Primitive>) -> Node {
let mut child = self.clone(); let mut child = self.clone();
child.primitive = primitive; child.primitive = primitive;
child child
@@ -90,7 +90,7 @@ impl Node {
#[derive(Clone)] #[derive(Clone)]
pub struct Scene { pub struct Scene {
pub nodes: HashMap<String, Node>, pub nodes: HashMap<String, Node>,
pub materials: HashMap<String, Arc<Material>>, pub materials: HashMap<String, Rc<Material>>,
pub lights: HashMap<String, Light>, pub lights: HashMap<String, Light>,
pub cameras: HashMap<String, Camera>, pub cameras: HashMap<String, Camera>,
} }
@@ -110,7 +110,7 @@ impl Scene {
self.nodes.insert(label, node); self.nodes.insert(label, node);
} }
// Adds a material to the scene // Adds a material to the scene
pub fn add_material(&mut self, label: String, material: Arc<Material>) { pub fn add_material(&mut self, label: String, material: Rc<Material>) {
self.materials.insert(label, material); self.materials.insert(label, material);
} }
// Adds a light to the scene // Adds a light to the scene

View File

@@ -23,7 +23,7 @@ const START_HEIGHT: i32 = 700;
const COLOUR_CLEAR: [u8; 4] = [0x22, 0x00, 0x11, 0xff]; const COLOUR_CLEAR: [u8; 4] = [0x22, 0x00, 0x11, 0xff];
const PIXEL_CLEAR: [u8; 4] = [0x55, 0x00, 0x22, 0xff]; const PIXEL_CLEAR: [u8; 4] = [0x55, 0x00, 0x22, 0xff];
pub const INIT_FILE: &str = "scene.rhai"; pub const INIT_FILE: &str = "rhai/scene.rhai";
pub const SAVE_FILE: &str = "img.png"; pub const SAVE_FILE: &str = "img.png";
pub struct State { pub struct State {
@@ -145,6 +145,7 @@ impl State {
fn draw(&mut self) -> Result<(), Box<dyn Error>> { fn draw(&mut self) -> Result<(), Box<dyn Error>> {
//Draw ray_num in a block //Draw ray_num in a block
let frame = self.pixels.frame_mut();
for _ in 0..self.gui.ray_num { for _ in 0..self.gui.ray_num {
//Get random index from queue //Get random index from queue
let index = match self.ray_queue.pop() { let index = match self.ray_queue.pop() {
@@ -155,7 +156,6 @@ impl State {
let colour = &self.rays[index].shade_ray(&self.scene); let colour = &self.rays[index].shade_ray(&self.scene);
//Assign colour to pixel in frame //Assign colour to pixel in frame
let rgba = colour.map_or(PIXEL_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]); let rgba = colour.map_or(PIXEL_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]);
let frame = self.pixels.frame_mut();
frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba); frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba);
} }
Ok(()) Ok(())

View File

@@ -1,22 +0,0 @@
let scene = Scene();
let material = Material(V(0.2,0.2,0.2), V(0.2, 0.8, 0.8), 10.0);
//let ambient = Light(P(10.0,0.0,0.0), V(1.0,1.0,1.0), V(0.0, 0.0, 0.0));
//scene.addLight(ambient);
let light = Light(P(0.0,7.0,0.0), V(0.0,0.0,1.0), V(0.1, 0.01, 0.001));
scene.addLight(light);
let light = Light(P(2.0,7.0,0.0), V(0.0,1.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight(light);
let light = Light(P(-2.0,7.0,0.0), V(1.0,0.0,0.0), V(0.1, 0.01, 0.001));
scene.addLight(light);
let light = Ambient(V(0.1,0.1,0.1));
scene.addLight(light);
let sphere = Stein(material);
let sphere_node = Node(sphere);
scene.addNode(sphere_node);
scene