BVH and rays complete
This commit is contained in:
@@ -10,18 +10,20 @@ scene.addCamera("Cam", camera);
|
|||||||
|
|
||||||
let falloff = V(0.0,0.0,0.0);
|
let falloff = V(0.0,0.0,0.0);
|
||||||
let light = Light(P(6.0,6.0,6.0), V(0.4,0.4,0.4), falloff);
|
let light = Light(P(6.0,6.0,6.0), V(0.4,0.4,0.4), falloff);
|
||||||
light.active(false);
|
light.active(true);
|
||||||
scene.addLight("white", light);
|
scene.addLight("white", 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));
|
let light = Light(P(2.0,0.0,0.0), V(1.0,1.0,0.0), falloff);
|
||||||
light.active(false);
|
light.active(false);
|
||||||
scene.addLight("green", light);
|
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));
|
let light = Light(P(-2.0,0.0,0.0), V(1.0,0.0,0.0), falloff);
|
||||||
light.active(false);
|
light.active(false);
|
||||||
scene.addLight("red", light);
|
scene.addLight("red", light);
|
||||||
|
|
||||||
let light = Ambient(V(0.3,0.3,0.3));
|
let light = Ambient(V(0.3,0.3,0.3));
|
||||||
|
light.active(false);
|
||||||
scene.addLight("ambient", light);
|
scene.addLight("ambient", light);
|
||||||
|
|
||||||
|
|
||||||
let tri = TriangleUnit();
|
let tri = TriangleUnit();
|
||||||
let tri_node = Node(tri, material);
|
let tri_node = Node(tri, material);
|
||||||
tri_node.active(false);
|
tri_node.active(false);
|
||||||
@@ -39,7 +41,7 @@ scene.addNode("cone", cone_node);
|
|||||||
|
|
||||||
let torus = Torus(0.5, 1.5);
|
let torus = Torus(0.5, 1.5);
|
||||||
let torus_node = Node(torus, material);
|
let torus_node = Node(torus, material);
|
||||||
torus_node.active(true);
|
torus_node.active(false);
|
||||||
scene.addNode("torus", torus_node);
|
scene.addNode("torus", torus_node);
|
||||||
|
|
||||||
|
|
||||||
@@ -59,7 +61,8 @@ scene.addNode("ground", ground_node);
|
|||||||
|
|
||||||
let mesh = Mesh("obj/cat.obj");
|
let mesh = Mesh("obj/cat.obj");
|
||||||
let mesh_node = Node(mesh, material);
|
let mesh_node = Node(mesh, material);
|
||||||
mesh_node.active(false);
|
mesh_node.active(true);
|
||||||
|
mesh_node.rotate(0.0,90.0,90.0);
|
||||||
scene.addNode("mesh", mesh_node);
|
scene.addNode("mesh", mesh_node);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,46 +16,46 @@ scene.addCamera("-X Cam", camera);
|
|||||||
|
|
||||||
let material = Material(V(0.2,0.9,0.8), V(0.3, 0.8, 0.8), 10.0);
|
let material = Material(V(0.2,0.9,0.8), V(0.3, 0.8, 0.8), 10.0);
|
||||||
scene.addMaterial("bluegreen", material);
|
scene.addMaterial("bluegreen", material);
|
||||||
|
let material2 = Material(V(0.2,0.9,0.8), V(0.3, 0.8, 0.8), 25.0);
|
||||||
|
scene.addMaterial("bluegreen2", 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));
|
let light = Light(P(0.0,7.0,0.0), V(0.0,0.0,1.0), V(0.1, 0.01, 0.001));
|
||||||
light.active(false);
|
light.active(false);
|
||||||
scene.addLight("blue", light);
|
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));
|
let light = Light( P(2.0,7.0,0.0), V(0.0,1.0,0.0), V(0.1, 0.01, 0.001));
|
||||||
// light.active(false);
|
light.active(false);
|
||||||
// scene.addLight("green", light);
|
scene.addLight("green", light);
|
||||||
|
|
||||||
// let light = Light( P(2.0,7.0,2.0), V(1.0,0.5,0.5), V(0.0, 0.00, 0.001));
|
let light = Light( P(2.0,7.0,2.0), V(1.0,0.5,0.5), V(0.0, 0.00, 0.001));
|
||||||
// scene.addLight("red", light);
|
scene.addLight("red", light);
|
||||||
|
|
||||||
let light = Ambient(V(0.1,0.1,0.1));
|
let light = Ambient(V(0.5,0.5,0.5));
|
||||||
scene.addLight("ambient", light);
|
scene.addLight("ambient", light);
|
||||||
|
|
||||||
|
|
||||||
// let sphere = Sphere(P(0.0,0.0,0.0), 1.0 );
|
let sphere = Sphere(P(0.0,-10.0,0.0), 10.0 );
|
||||||
// let sphere_node = Node( sphere, material);
|
let sphere_node = Node( sphere, material);
|
||||||
// scene.addNode("sphere",sphere_node);
|
scene.addNode("sphere",sphere_node);
|
||||||
|
|
||||||
//let mesh = Mesh("obj/cow.obj" );
|
//let mesh = Mesh("obj/cow.obj" );
|
||||||
//let mesh_node = Node(mesh);
|
//let mesh_node = Node(mesh);
|
||||||
//scene.addNode("mesh", mesh_node);
|
//scene.addNode("mesh", mesh_node);
|
||||||
|
|
||||||
for i in 0..6 {
|
|
||||||
let sphere = Sphere(P(0.0,0.0,0.0), 2.0 );
|
|
||||||
let sphere_node = Node( sphere, material);
|
|
||||||
sphere_node.translate(4.0*cos(i.to_float()), -4.0, 4.0*sin(i.to_float()));
|
|
||||||
scene.addNode(i.to_string(), sphere_node);
|
|
||||||
}
|
|
||||||
// let child = sphere_node.child(sphere);
|
// let child = sphere_node.child(sphere);
|
||||||
// child.translate(V(1.0,1.0,1.0));
|
// child.translate(V(1.0,1.0,1.0));
|
||||||
//scene.addNode(child);
|
//scene.addNode(child);
|
||||||
|
|
||||||
let cube = CubeUnit();
|
let cube = CubeUnit();
|
||||||
let cube_node = Node( cube, material);
|
let cube_node = Node( cube, material2);
|
||||||
|
cube_node.rotate(0.1,0.1,45.0);
|
||||||
|
cube_node.translate(0.0,1.0,0.0);
|
||||||
scene.addNode("cube", cube_node);
|
scene.addNode("cube", cube_node);
|
||||||
|
|
||||||
//let gnonom = Gnonom();
|
//let gnonom = Gnonom();
|
||||||
//let gnonom_node = Node(gnonom);
|
//let gnonom_node = Node(gnonom, material);
|
||||||
//scene.addNode("gnonom", gnonom_node);
|
//scene.addNode("gnonom", gnonom_node);
|
||||||
|
|
||||||
//let cylinder = Cylinder(2.0,1.0 );
|
//let cylinder = Cylinder(2.0,1.0 );
|
||||||
|
|||||||
11
src/bvh.rs
11
src/bvh.rs
@@ -260,9 +260,7 @@ impl BVH {
|
|||||||
|
|
||||||
for i in 0..prim_count {
|
for i in 0..prim_count {
|
||||||
let node = &self.nodes[first_prim + i]; //Get the node from the Vec<Node>
|
let node = &self.nodes[first_prim + i]; //Get the node from the Vec<Node>
|
||||||
let mut node_aabb = node.primitive.get_aabb(); //Get the primitive's AABB
|
bvh_node_aabb.join_mut(&node.aabb); //Join it with the BVH node's AABB
|
||||||
node_aabb.transform_mut(&node.model); //Transform the AABB to world coordinates
|
|
||||||
bvh_node_aabb.join_mut(&node_aabb); //Join it with the BVH node's AABB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unsafe {
|
// unsafe {
|
||||||
@@ -310,9 +308,7 @@ impl BVH {
|
|||||||
// for i in 0..self.bvh_nodes[index].prim_count {
|
// for i in 0..self.bvh_nodes[index].prim_count {
|
||||||
// let node = &self.nodes[first_prim_idx + i];
|
// let node = &self.nodes[first_prim_idx + i];
|
||||||
// //Get the centroid of the bounding box
|
// //Get the centroid of the bounding box
|
||||||
// let centroid = node.primitive.get_aabb().get_centroid();
|
// let centroid = node.aabb.get_centroid();
|
||||||
// //Place the centroid into world coordinates
|
|
||||||
// let world_centroid = node.model.transform_point(¢roid);
|
|
||||||
// //Get the candidate position
|
// //Get the candidate position
|
||||||
// let candidate_pos = world_centroid[axis];
|
// let candidate_pos = world_centroid[axis];
|
||||||
// let cost = self.evaluate_sah(&self.bvh_nodes[index], axis, candidate_pos);
|
// let cost = self.evaluate_sah(&self.bvh_nodes[index], axis, candidate_pos);
|
||||||
@@ -340,8 +336,7 @@ impl BVH {
|
|||||||
while i <= j {
|
while i <= j {
|
||||||
//Perform a quicksort dependent on location
|
//Perform a quicksort dependent on location
|
||||||
let node = &self.nodes[i]; // Node we would like to sort
|
let node = &self.nodes[i]; // Node we would like to sort
|
||||||
let centroid = node.primitive.get_aabb().get_centroid(); //Centroid of node we would like to sort
|
let centroid = node.aabb.get_centroid(); //Centroid of node we would like to sort
|
||||||
let centroid = node.model.transform_point(¢roid); //Transform to world coordinates
|
|
||||||
if centroid[axis] < split_pos {
|
if centroid[axis] < split_pos {
|
||||||
i += 1; // On Left-Hand-Side
|
i += 1; // On Left-Hand-Side
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ impl Gui {
|
|||||||
"Rays Per Pass",
|
"Rays Per Pass",
|
||||||
RAYS_MIN,
|
RAYS_MIN,
|
||||||
RAYS_MAX,
|
RAYS_MAX,
|
||||||
&mut self.raytracing_option.rays_per_pass,
|
&mut self.raytracing_option.pixels_per_pass,
|
||||||
);
|
);
|
||||||
// Proportion of the window the buffer occupies
|
// Proportion of the window the buffer occupies
|
||||||
ui.slider(
|
ui.slider(
|
||||||
|
|||||||
14
src/node.rs
14
src/node.rs
@@ -1,12 +1,13 @@
|
|||||||
use crate::{material::Material, primitive::*};
|
use crate::{bvh::AABB, material::Material, primitive::*};
|
||||||
use nalgebra::{Matrix4, Vector3};
|
use nalgebra::{Matrix4, Vector3};
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
//Primitive
|
//Primitive
|
||||||
pub primitive: Rc<dyn Primitive>,
|
pub primitive: Arc<dyn Primitive>,
|
||||||
pub material: Material,
|
pub material: Material,
|
||||||
|
pub aabb: AABB,
|
||||||
//Transformations
|
//Transformations
|
||||||
pub rotation: [f64; 3],
|
pub rotation: [f64; 3],
|
||||||
pub scale: [f64; 3],
|
pub scale: [f64; 3],
|
||||||
@@ -20,10 +21,12 @@ pub struct Node {
|
|||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
//New node with no transformations
|
//New node with no transformations
|
||||||
pub fn new(primitive: Rc<dyn Primitive>, material: Material) -> Node {
|
pub fn new(primitive: Arc<dyn Primitive>, material: Material) -> Node {
|
||||||
|
let aabb = primitive.get_aabb();
|
||||||
Node {
|
Node {
|
||||||
primitive,
|
primitive,
|
||||||
material,
|
material,
|
||||||
|
aabb,
|
||||||
rotation: [0.0, 0.0, 0.0],
|
rotation: [0.0, 0.0, 0.0],
|
||||||
scale: [1.0, 1.0, 1.0],
|
scale: [1.0, 1.0, 1.0],
|
||||||
translation: [0.0, 0.0, 0.0],
|
translation: [0.0, 0.0, 0.0],
|
||||||
@@ -34,7 +37,7 @@ impl Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//New node with parent transformations
|
//New node with parent transformations
|
||||||
pub fn child(self, primitive: Rc<dyn Primitive>) -> Node {
|
pub fn child(self, primitive: Arc<dyn Primitive>) -> Node {
|
||||||
let mut child = self.clone();
|
let mut child = self.clone();
|
||||||
child.primitive = primitive;
|
child.primitive = primitive;
|
||||||
child
|
child
|
||||||
@@ -93,5 +96,6 @@ impl Node {
|
|||||||
self.model = (translation_matrix * rotation_matrix * scale_matrix).cast();
|
self.model = (translation_matrix * rotation_matrix * scale_matrix).cast();
|
||||||
// Compute the inverse model matrix by inverting the model matrix
|
// Compute the inverse model matrix by inverting the model matrix
|
||||||
self.inv_model = self.model.try_inverse().unwrap();
|
self.inv_model = self.model.try_inverse().unwrap();
|
||||||
|
self.aabb.transform_mut(&self.model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
131
src/primitive.rs
131
src/primitive.rs
@@ -9,9 +9,9 @@ use nalgebra::{distance, 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::rc::Rc;
|
use std::sync::Arc;
|
||||||
// PRIMITIVE TRAIT -----------------------------------------------------------------
|
// PRIMITIVE TRAIT -----------------------------------------------------------------
|
||||||
pub trait Primitive {
|
pub trait Primitive: Send + Sync {
|
||||||
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection>;
|
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection>;
|
||||||
fn get_aabb(&self) -> AABB;
|
fn get_aabb(&self) -> AABB;
|
||||||
}
|
}
|
||||||
@@ -24,11 +24,11 @@ pub struct Sphere {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Sphere {
|
impl Sphere {
|
||||||
pub fn new(position: Point3<f64>, radius: f64) -> Rc<dyn Primitive> {
|
pub fn new(position: Point3<f64>, radius: f64) -> Arc<dyn Primitive> {
|
||||||
Rc::new(Sphere { position, radius })
|
Arc::new(Sphere { position, radius })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unit() -> Rc<dyn Primitive> {
|
pub fn unit() -> Arc<dyn Primitive> {
|
||||||
Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0)
|
Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,10 +88,10 @@ pub struct Circle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Circle {
|
impl Circle {
|
||||||
pub fn new(position: Point3<f64>, radius: f64, normal: Vector3<f64>) -> Rc<dyn Primitive> {
|
pub fn new(position: Point3<f64>, radius: f64, normal: Vector3<f64>) -> Arc<dyn Primitive> {
|
||||||
let normal = normal.normalize();
|
let normal = normal.normalize();
|
||||||
let constant = normal.dot(&position.coords);
|
let constant = normal.dot(&position.coords);
|
||||||
Rc::new(Circle {
|
Arc::new(Circle {
|
||||||
position,
|
position,
|
||||||
radius,
|
radius,
|
||||||
normal,
|
normal,
|
||||||
@@ -99,7 +99,18 @@ impl Circle {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unit() -> Rc<dyn Primitive> {
|
pub fn new_unboxed(position: Point3<f64>, radius: f64, normal: Vector3<f64>) -> Circle {
|
||||||
|
let normal = normal.normalize();
|
||||||
|
let constant = normal.dot(&position.coords);
|
||||||
|
Circle {
|
||||||
|
position,
|
||||||
|
radius,
|
||||||
|
normal,
|
||||||
|
constant,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unit() -> Arc<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, 0.0, -1.0);
|
let normal = Vector3::new(0.0, 0.0, -1.0);
|
||||||
let radius = 1.0;
|
let radius = 1.0;
|
||||||
@@ -147,23 +158,23 @@ impl Primitive for Circle {
|
|||||||
pub struct Cylinder {
|
pub struct Cylinder {
|
||||||
radius: f64,
|
radius: f64,
|
||||||
height: f64,
|
height: f64,
|
||||||
base_circle: Rc<dyn Primitive>,
|
base_circle: Circle,
|
||||||
top_circle: Rc<dyn Primitive>,
|
top_circle: Circle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cylinder {
|
impl Cylinder {
|
||||||
pub fn new(radius: f64, height: f64) -> Rc<dyn Primitive> {
|
pub fn new(radius: f64, height: f64) -> Arc<dyn Primitive> {
|
||||||
let base_circle = Circle::new(
|
let base_circle = Circle::new_unboxed(
|
||||||
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),
|
||||||
);
|
);
|
||||||
let top_circle = Circle::new(
|
let top_circle = Circle::new_unboxed(
|
||||||
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),
|
||||||
);
|
);
|
||||||
Rc::new(Cylinder {
|
Arc::new(Cylinder {
|
||||||
radius,
|
radius,
|
||||||
height,
|
height,
|
||||||
base_circle,
|
base_circle,
|
||||||
@@ -264,24 +275,24 @@ impl Primitive for Cylinder {
|
|||||||
pub struct Cone {
|
pub struct Cone {
|
||||||
height: f64,
|
height: f64,
|
||||||
constant: f64,
|
constant: f64,
|
||||||
circle: Rc<dyn Primitive>,
|
circle: Circle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Cone {
|
impl Cone {
|
||||||
pub fn new(radius: f64, height: f64) -> Rc<dyn Primitive> {
|
pub fn new(radius: f64, height: f64) -> Arc<dyn Primitive> {
|
||||||
let circle = Circle::new(
|
let circle = Circle::new_unboxed(
|
||||||
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),
|
||||||
);
|
);
|
||||||
let constant = radius * radius / (height * height);
|
let constant = radius * radius / (height * height);
|
||||||
Rc::new(Cone {
|
Arc::new(Cone {
|
||||||
height,
|
height,
|
||||||
constant,
|
constant,
|
||||||
circle,
|
circle,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
pub fn unit() -> Rc<dyn Primitive> {
|
pub fn unit() -> Arc<dyn Primitive> {
|
||||||
Cone::new(0.5, 1.0)
|
Cone::new(0.5, 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,11 +389,11 @@ impl Primitive for Cone {
|
|||||||
// width_direction: Vector3<f64>,
|
// width_direction: Vector3<f64>,
|
||||||
// width: f64,
|
// width: f64,
|
||||||
// height: f64,
|
// height: f64,
|
||||||
// ) -> Rc<dyn Primitive> {
|
// ) -> Arc<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);
|
||||||
// Rc::new(Rectangle {
|
// Arc::new(Rectangle {
|
||||||
// position,
|
// position,
|
||||||
// normal: normal.normalize(),
|
// normal: normal.normalize(),
|
||||||
// width_direction: width_direction.normalize(),
|
// width_direction: width_direction.normalize(),
|
||||||
@@ -390,7 +401,7 @@ impl Primitive for Cone {
|
|||||||
// height,
|
// height,
|
||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
// pub fn unit() -> Rc<dyn Primitive> {
|
// pub fn unit() -> Arc<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),
|
||||||
@@ -450,11 +461,15 @@ pub struct Cube {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Cube {
|
impl Cube {
|
||||||
pub fn new(bln: Point3<f64>, trf: Point3<f64>) -> Rc<dyn Primitive> {
|
pub fn new(bln: Point3<f64>, trf: Point3<f64>) -> Arc<dyn Primitive> {
|
||||||
Rc::new(Cube { bln, trf })
|
Arc::new(Cube { bln, trf })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unit() -> Rc<dyn Primitive> {
|
pub fn new_unboxed(bln: Point3<f64>, trf: Point3<f64>) -> Cube {
|
||||||
|
Cube { bln, trf }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unit() -> Arc<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)
|
Cube::new(bln, trf)
|
||||||
@@ -479,12 +494,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
|
||||||
}
|
}
|
||||||
@@ -507,7 +522,7 @@ impl Primitive for Cube {
|
|||||||
|
|
||||||
Some(Intersection {
|
Some(Intersection {
|
||||||
point: intersect,
|
point: intersect,
|
||||||
normal: normal,
|
normal,
|
||||||
distance: tmin,
|
distance: tmin,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@@ -533,14 +548,14 @@ pub struct Triangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Triangle {
|
impl Triangle {
|
||||||
pub fn new(u: Point3<f64>, v: Point3<f64>, w: Point3<f64>) -> Rc<dyn Primitive> {
|
pub fn new(u: Point3<f64>, v: Point3<f64>, w: Point3<f64>) -> Arc<dyn Primitive> {
|
||||||
let uv = v - u;
|
let uv = v - u;
|
||||||
let uw = w - u;
|
let uw = w - u;
|
||||||
let normal = uw.cross(&uv).normalize();
|
let normal = uw.cross(&uv).normalize();
|
||||||
Rc::new(Triangle { u, v, w, normal })
|
Arc::new(Triangle { u, v, w, normal })
|
||||||
}
|
}
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn unit() -> Rc<dyn Primitive> {
|
pub fn unit() -> Arc<dyn Primitive> {
|
||||||
let u = Point3::new(-1.0, -1.0, 0.0);
|
let u = Point3::new(-1.0, -1.0, 0.0);
|
||||||
let v = Point3::new(0.0, 1.0, 0.0);
|
let v = Point3::new(0.0, 1.0, 0.0);
|
||||||
let w = Point3::new(1.0, -1.0, 0.0);
|
let w = Point3::new(1.0, -1.0, 0.0);
|
||||||
@@ -606,10 +621,10 @@ pub struct Mesh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Mesh {
|
impl Mesh {
|
||||||
pub fn new(triangles: Vec<Triangle>) -> Rc<dyn Primitive> {
|
pub fn new(triangles: Vec<Triangle>) -> 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 { triangles })
|
Arc::new(Mesh { triangles })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_bounding_box(triangles: &Vec<Triangle>) -> AABB {
|
fn compute_bounding_box(triangles: &Vec<Triangle>) -> AABB {
|
||||||
@@ -626,7 +641,7 @@ impl Mesh {
|
|||||||
AABB::new(bln, trf)
|
AABB::new(bln, trf)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file(filename: &str) -> Rc<dyn Primitive> {
|
pub fn from_file(filename: &str) -> Arc<dyn Primitive> {
|
||||||
let mut triangles: Vec<Triangle> = 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();
|
||||||
|
|
||||||
@@ -713,9 +728,9 @@ pub struct Torus {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Torus {
|
impl Torus {
|
||||||
pub fn new(inner_rad: f64, outer_rad: f64) -> Rc<dyn Primitive> {
|
pub fn new(inner_rad: f64, outer_rad: f64) -> Arc<dyn Primitive> {
|
||||||
// I need to find the bounding box for this shape
|
// I need to find the bounding box for this shape
|
||||||
Rc::new(Torus {
|
Arc::new(Torus {
|
||||||
inner_rad,
|
inner_rad,
|
||||||
outer_rad,
|
outer_rad,
|
||||||
})
|
})
|
||||||
@@ -834,28 +849,28 @@ impl Primitive for Torus {
|
|||||||
// GNOMON -----------------------------------------------------------------
|
// GNOMON -----------------------------------------------------------------
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Gnonom {
|
pub struct Gnonom {
|
||||||
x_cube: Rc<dyn Primitive>,
|
x_cube: Cube,
|
||||||
y_cube: Rc<dyn Primitive>,
|
y_cube: Cube,
|
||||||
z_cube: Rc<dyn Primitive>,
|
z_cube: Cube,
|
||||||
}
|
}
|
||||||
|
|
||||||
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() -> Rc<dyn Primitive> {
|
pub fn new() -> Arc<dyn Primitive> {
|
||||||
let x_cube = Cube::new(
|
let x_cube = Cube::new_unboxed(
|
||||||
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),
|
||||||
);
|
);
|
||||||
let y_cube = Cube::new(
|
let y_cube = Cube::new_unboxed(
|
||||||
Point3::new(-Self::GNONOM_WIDTH, 0.0, -Self::GNONOM_WIDTH),
|
Point3::new(-Self::GNONOM_WIDTH, 0.0, -Self::GNONOM_WIDTH),
|
||||||
Point3::new(Self::GNONOM_WIDTH, Self::GNONOM_LENGTH, Self::GNONOM_WIDTH),
|
Point3::new(Self::GNONOM_WIDTH, Self::GNONOM_LENGTH, Self::GNONOM_WIDTH),
|
||||||
);
|
);
|
||||||
let z_cube = Cube::new(
|
let z_cube = Cube::new_unboxed(
|
||||||
Point3::new(-Self::GNONOM_WIDTH, -Self::GNONOM_WIDTH, 0.0),
|
Point3::new(-Self::GNONOM_WIDTH, -Self::GNONOM_WIDTH, 0.0),
|
||||||
Point3::new(Self::GNONOM_WIDTH, Self::GNONOM_WIDTH, Self::GNONOM_LENGTH),
|
Point3::new(Self::GNONOM_WIDTH, Self::GNONOM_WIDTH, Self::GNONOM_LENGTH),
|
||||||
);
|
);
|
||||||
Rc::new(Gnonom {
|
Arc::new(Gnonom {
|
||||||
x_cube,
|
x_cube,
|
||||||
y_cube,
|
y_cube,
|
||||||
z_cube,
|
z_cube,
|
||||||
@@ -901,9 +916,9 @@ impl Primitive for Gnonom {
|
|||||||
pub struct CrossCap {}
|
pub struct CrossCap {}
|
||||||
|
|
||||||
impl CrossCap {
|
impl CrossCap {
|
||||||
pub fn new() -> Rc<dyn Primitive> {
|
pub fn new() -> Arc<dyn Primitive> {
|
||||||
// I need to find the bounding box for this shape
|
// I need to find the bounding box for this shape
|
||||||
Rc::new(CrossCap {})
|
Arc::new(CrossCap {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -992,9 +1007,9 @@ pub struct CrossCap2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CrossCap2 {
|
impl CrossCap2 {
|
||||||
pub fn new(p: f64, q: f64) -> Rc<dyn Primitive> {
|
pub fn new(p: f64, q: f64) -> Arc<dyn Primitive> {
|
||||||
// I need to find the bounding box for this shape
|
// I need to find the bounding box for this shape
|
||||||
Rc::new(CrossCap2 { p, q })
|
Arc::new(CrossCap2 { p, q })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1105,9 +1120,9 @@ impl Primitive for CrossCap2 {
|
|||||||
pub struct Steiner {}
|
pub struct Steiner {}
|
||||||
|
|
||||||
impl Steiner {
|
impl Steiner {
|
||||||
pub fn new() -> Rc<dyn Primitive> {
|
pub fn new() -> Arc<dyn Primitive> {
|
||||||
// I need to find the bounding box for this shape
|
// I need to find the bounding box for this shape
|
||||||
Rc::new(Steiner {})
|
Arc::new(Steiner {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1182,9 +1197,9 @@ impl Primitive for Steiner {
|
|||||||
pub struct Steiner2 {}
|
pub struct Steiner2 {}
|
||||||
|
|
||||||
impl Steiner2 {
|
impl Steiner2 {
|
||||||
pub fn new() -> Rc<dyn Primitive> {
|
pub fn new() -> Arc<dyn Primitive> {
|
||||||
// I need to find the bounding box for this shape
|
// I need to find the bounding box for this shape
|
||||||
Rc::new(Steiner2 {})
|
Arc::new(Steiner2 {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1272,9 +1287,9 @@ pub struct Roman {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Roman {
|
impl Roman {
|
||||||
pub fn new(k: f64) -> Rc<dyn Primitive> {
|
pub fn new(k: f64) -> Arc<dyn Primitive> {
|
||||||
// I need to find the bounding box for this shape
|
// I need to find the bounding box for this shape
|
||||||
Rc::new(Roman { k })
|
Arc::new(Roman { k })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/ray.rs
42
src/ray.rs
@@ -86,6 +86,8 @@ impl Ray {
|
|||||||
if !node.active {
|
if !node.active {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node.aabb.intersect_ray(&self) {
|
||||||
// Transform ray into local model cordinates
|
// Transform ray into local model cordinates
|
||||||
let ray = self.transform(&node.inv_model);
|
let ray = self.transform(&node.inv_model);
|
||||||
// Check primitive intersection
|
// Check primitive intersection
|
||||||
@@ -103,6 +105,7 @@ impl Ray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
closest_intersect
|
closest_intersect
|
||||||
}
|
}
|
||||||
// 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
|
||||||
@@ -113,10 +116,12 @@ impl Ray {
|
|||||||
options: &RaytracingOption,
|
options: &RaytracingOption,
|
||||||
sbvh: &Option<BVH>,
|
sbvh: &Option<BVH>,
|
||||||
) -> Option<Vector3<f32>> {
|
) -> Option<Vector3<f32>> {
|
||||||
|
//If we have exceeded depth then return
|
||||||
if depth == options.ray_depth {
|
if depth == options.ray_depth {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
match sbvh {
|
match sbvh {
|
||||||
|
//We have a bvh so use bvh traversal
|
||||||
Some(bvh) => {
|
Some(bvh) => {
|
||||||
//Intersect the scene with the bvh
|
//Intersect the scene with the bvh
|
||||||
if let Some((node, intersect)) = bvh.traverse(&self, 0) {
|
if let Some((node, intersect)) = bvh.traverse(&self, 0) {
|
||||||
@@ -126,6 +131,7 @@ impl Ray {
|
|||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
//We dont have a bvh so use generic algorithm
|
||||||
None => {
|
None => {
|
||||||
//No BVH given so intersect normally
|
//No BVH given so intersect normally
|
||||||
match self.closest_intersect(scene) {
|
match self.closest_intersect(scene) {
|
||||||
@@ -175,7 +181,7 @@ impl Ray {
|
|||||||
|
|
||||||
//Niave Shadows
|
//Niave Shadows
|
||||||
let to_light_ray = Ray::new(point, to_light);
|
let to_light_ray = Ray::new(point, to_light);
|
||||||
if to_light_ray.light_blocked(scene, node) {
|
if to_light_ray.light_blocked(scene, node, bvh) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,38 +208,56 @@ impl Ray {
|
|||||||
|
|
||||||
//Specular component
|
//Specular component
|
||||||
let mut specular = Vector3::zeros();
|
let mut specular = Vector3::zeros();
|
||||||
if n_dot_l < 0.0 {
|
if n_dot_l > 0.0 {
|
||||||
let h = (to_light - incidence).normalize();
|
let h = (to_light - incidence).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 = material.ks * n_dot_h.powf(material.shininess);
|
specular = material.ks * n_dot_h.powf(material.shininess);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Falloff
|
//Falloff
|
||||||
// let falloff = 1.0
|
let falloff = 1.0
|
||||||
// / (1.0
|
/ ((1.0 + light.falloff[0])
|
||||||
// + light.falloff[0]
|
+ light.falloff[1] * light_distance
|
||||||
// + light.falloff[1] * light_distance
|
+ light.falloff[2] * light_distance * light_distance);
|
||||||
// + light.falloff[2] * light_distance * light_distance);
|
|
||||||
|
|
||||||
let intensity = light.colour.component_mul(&(diffuse + reflect + specular));
|
let intensity = light.colour.component_mul(&(diffuse + reflect + specular)) * falloff;
|
||||||
colour += &intensity;
|
colour += &intensity;
|
||||||
}
|
}
|
||||||
|
|
||||||
colour
|
colour
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn light_blocked(&self, scene: &Scene, _node: &Node) -> bool {
|
pub fn light_blocked(&self, scene: &Scene, _node: &Node, bvh: &Option<BVH>) -> bool {
|
||||||
|
match bvh {
|
||||||
|
Some(bvh) => {
|
||||||
|
//We have a bvh so use bvh traversal
|
||||||
for (_, node) in &scene.nodes {
|
for (_, node) in &scene.nodes {
|
||||||
if !node.active {
|
if !node.active {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
match bvh.traverse(&self, 0) {
|
||||||
|
Some(_) => return true,
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
for (_, node) in &scene.nodes {
|
||||||
|
if !node.active {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if node.aabb.intersect_ray(self) {
|
||||||
let ray = self.transform(&node.inv_model);
|
let ray = self.transform(&node.inv_model);
|
||||||
if node.primitive.intersect_ray(&ray).is_some() {
|
if node.primitive.intersect_ray(&ray).is_some() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
//Cast a set of rays
|
//Cast a set of rays
|
||||||
pub fn cast_rays(
|
pub fn cast_rays(
|
||||||
eye: &Point3<f64>,
|
eye: &Point3<f64>,
|
||||||
|
|||||||
18
src/scene.rs
18
src/scene.rs
@@ -1,5 +1,23 @@
|
|||||||
use crate::{camera::Camera, light::Light, material::*, node::*};
|
use crate::{camera::Camera, light::Light, material::*, node::*};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
// pub struct MultiThreadScene {
|
||||||
|
// pub nodes: Rc<HashMap<String, Node>>,
|
||||||
|
// pub materials: Rc<HashMap<String, Material>>,
|
||||||
|
// pub lights: Rc<HashMap<String, Light>>,
|
||||||
|
// pub cameras: Rc<HashMap<String, Camera>>,
|
||||||
|
// }
|
||||||
|
// impl MultiThreadScene {
|
||||||
|
// pub fn from_scene(scene: &Scene) -> MultiThreadScene {
|
||||||
|
// MultiThreadScene {
|
||||||
|
// nodes: Rc::new(scene.nodes.clone()),
|
||||||
|
// materials: Rc::new(scene.materials.clone()),
|
||||||
|
// lights: Rc::new(scene.lights.clone()),
|
||||||
|
// cameras: Rc::new(scene.cameras.clone()),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scene {
|
pub struct Scene {
|
||||||
|
|||||||
114
src/state.rs
114
src/state.rs
@@ -6,12 +6,15 @@ use crate::ray::Ray;
|
|||||||
use crate::{gui::Gui, scene::Scene};
|
use crate::{gui::Gui, scene::Scene};
|
||||||
use crate::{gui::GuiEvent, log_error};
|
use crate::{gui::GuiEvent, log_error};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
use nalgebra::Vector3;
|
use nalgebra::Vector3;
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::{random, thread_rng};
|
use rand::{random, thread_rng};
|
||||||
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use pixels::{Pixels, SurfaceTexture};
|
use pixels::{Pixels, SurfaceTexture};
|
||||||
@@ -28,11 +31,12 @@ pub const SAVE_FILE: &str = "img.png";
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RaytracingOption {
|
pub struct RaytracingOption {
|
||||||
|
pub threads: u32,
|
||||||
pub ray_samples: u32,
|
pub ray_samples: u32,
|
||||||
pub ray_randomness: f64,
|
pub ray_randomness: f64,
|
||||||
pub clear_color: [u8; 4],
|
pub clear_color: [u8; 4],
|
||||||
pub pixel_clear: [u8; 4],
|
pub pixel_clear: [u8; 4],
|
||||||
pub rays_per_pass: u32,
|
pub pixels_per_pass: u32,
|
||||||
pub buffer_proportion: f32,
|
pub buffer_proportion: f32,
|
||||||
pub buffer_fov: f64,
|
pub buffer_fov: f64,
|
||||||
pub ray_depth: u8,
|
pub ray_depth: u8,
|
||||||
@@ -43,11 +47,12 @@ pub struct RaytracingOption {
|
|||||||
impl RaytracingOption {
|
impl RaytracingOption {
|
||||||
pub fn default() -> RaytracingOption {
|
pub fn default() -> RaytracingOption {
|
||||||
RaytracingOption {
|
RaytracingOption {
|
||||||
|
threads: 12,
|
||||||
ray_samples: 10,
|
ray_samples: 10,
|
||||||
ray_randomness: 100.0,
|
ray_randomness: 100.0,
|
||||||
clear_color: [0x22, 0x00, 0x11, 0x55],
|
clear_color: [0x22, 0x00, 0x11, 0x55],
|
||||||
pixel_clear: [0x55, 0x00, 0x22, 0x55],
|
pixel_clear: [0x55, 0x00, 0x22, 0x55],
|
||||||
rays_per_pass: 200,
|
pixels_per_pass: 200,
|
||||||
buffer_proportion: 1.0,
|
buffer_proportion: 1.0,
|
||||||
buffer_fov: 110.0,
|
buffer_fov: 110.0,
|
||||||
ray_depth: 5,
|
ray_depth: 5,
|
||||||
@@ -59,32 +64,33 @@ impl RaytracingOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
scene: Scene,
|
scene: Arc<Scene>,
|
||||||
bvh: Option<BVH>,
|
bvh: Arc<Option<BVH>>,
|
||||||
camera: Camera,
|
camera: Camera,
|
||||||
window: Window,
|
window: Window,
|
||||||
|
|
||||||
buffer_width: u32,
|
buffer_width: u32,
|
||||||
buffer_height: u32,
|
buffer_height: u32,
|
||||||
|
|
||||||
pixels: Pixels,
|
pixels: Arc<Mutex<Pixels>>,
|
||||||
gui: Gui,
|
gui: Gui,
|
||||||
|
|
||||||
rays: Vec<Ray>,
|
rays: Arc<Vec<Ray>>,
|
||||||
ray_queue: Vec<usize>,
|
ray_queue: Arc<Mutex<Vec<usize>>>,
|
||||||
raytracing_options: RaytracingOption,
|
raytracing_options: Arc<RaytracingOption>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new(window: Window, pixels: Pixels, gui: Gui) -> Self {
|
pub fn new(window: Window, pixels: Pixels, gui: Gui) -> Self {
|
||||||
let scene = Scene::empty();
|
let scene = Arc::new(Scene::empty());
|
||||||
let window_size = window.inner_size();
|
let window_size = window.inner_size();
|
||||||
|
let pixels = Arc::new(Mutex::new(pixels));
|
||||||
let camera = Camera::unit();
|
let camera = Camera::unit();
|
||||||
let rays = Vec::new();
|
let rays = Arc::new(Vec::new());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
scene,
|
scene,
|
||||||
bvh: None,
|
bvh: Arc::new(None),
|
||||||
camera,
|
camera,
|
||||||
window,
|
window,
|
||||||
buffer_width: window_size.width as u32,
|
buffer_width: window_size.width as u32,
|
||||||
@@ -92,8 +98,8 @@ impl State {
|
|||||||
pixels,
|
pixels,
|
||||||
gui,
|
gui,
|
||||||
rays,
|
rays,
|
||||||
ray_queue: Vec::new(),
|
ray_queue: Arc::new(Mutex::new(Vec::new())),
|
||||||
raytracing_options: RaytracingOption::default(),
|
raytracing_options: Arc::new(RaytracingOption::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,33 +107,34 @@ impl State {
|
|||||||
if let Some(event) = self.gui.event.take() {
|
if let Some(event) = self.gui.event.take() {
|
||||||
match event {
|
match event {
|
||||||
GuiEvent::RaytracerOption(options) => {
|
GuiEvent::RaytracerOption(options) => {
|
||||||
self.raytracing_options = options;
|
self.raytracing_options = Arc::new(options);
|
||||||
match self.raytracing_options.bvh_active {
|
match self.raytracing_options.bvh_active {
|
||||||
true => self.bvh = Some(BVH::build(&mut self.scene.nodes)),
|
true => self.bvh = Arc::new(Some(BVH::build(&self.scene.nodes))),
|
||||||
false => self.bvh = None,
|
false => self.bvh = Arc::new(None),
|
||||||
}
|
}
|
||||||
self.resize_buffer()?
|
self.resize_buffer()?
|
||||||
}
|
}
|
||||||
GuiEvent::CameraUpdate(camera) => {
|
GuiEvent::CameraUpdate(camera) => {
|
||||||
self.rays = Ray::cast_rays(
|
self.rays = Arc::new(Ray::cast_rays(
|
||||||
&camera.eye,
|
&camera.eye,
|
||||||
&camera.target,
|
&camera.target,
|
||||||
&camera.up,
|
&camera.up,
|
||||||
self.raytracing_options.buffer_fov,
|
self.raytracing_options.buffer_fov,
|
||||||
self.buffer_width,
|
self.buffer_width,
|
||||||
self.buffer_height,
|
self.buffer_height,
|
||||||
);
|
));
|
||||||
self.camera = camera;
|
self.camera = camera;
|
||||||
self.clear_buffer()?;
|
self.clear_buffer()?;
|
||||||
self.reset_queue();
|
self.reset_queue();
|
||||||
}
|
}
|
||||||
GuiEvent::SceneLoad(scene) => {
|
GuiEvent::SceneLoad(scene) => {
|
||||||
self.scene = scene;
|
self.scene = Arc::new(scene);
|
||||||
self.clear_buffer()?;
|
self.clear_buffer()?;
|
||||||
self.reset_queue();
|
self.reset_queue();
|
||||||
}
|
}
|
||||||
GuiEvent::SaveImage(filename) => {
|
GuiEvent::SaveImage(filename) => {
|
||||||
let frame = self.pixels.frame();
|
let pixels = &self.pixels.as_ref().lock().unwrap();
|
||||||
|
let frame = pixels.frame();
|
||||||
image::save_buffer(
|
image::save_buffer(
|
||||||
Path::new(&filename),
|
Path::new(&filename),
|
||||||
frame,
|
frame,
|
||||||
@@ -154,17 +161,17 @@ impl State {
|
|||||||
self.reset_queue();
|
self.reset_queue();
|
||||||
|
|
||||||
// Recalculate rays with new buffer dimensions
|
// Recalculate rays with new buffer dimensions
|
||||||
self.rays = Ray::cast_rays(
|
self.rays = Arc::new(Ray::cast_rays(
|
||||||
&self.camera.eye,
|
&self.camera.eye,
|
||||||
&self.camera.target,
|
&self.camera.target,
|
||||||
&self.camera.up,
|
&self.camera.up,
|
||||||
fovy,
|
fovy,
|
||||||
self.buffer_width,
|
self.buffer_width,
|
||||||
self.buffer_height,
|
self.buffer_height,
|
||||||
);
|
));
|
||||||
|
|
||||||
// Resize buffer and surface
|
// Resize buffer and surface
|
||||||
let pixels = &mut self.pixels;
|
let pixels = &mut self.pixels.as_ref().lock().unwrap();
|
||||||
pixels.resize_surface(size.width, size.height)?;
|
pixels.resize_surface(size.width, size.height)?;
|
||||||
pixels.resize_buffer(self.buffer_width, self.buffer_height)?;
|
pixels.resize_buffer(self.buffer_width, self.buffer_height)?;
|
||||||
|
|
||||||
@@ -172,7 +179,8 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resize(&mut self, size: &PhysicalSize<u32>) -> Result<(), Box<dyn Error>> {
|
fn resize(&mut self, size: &PhysicalSize<u32>) -> Result<(), Box<dyn Error>> {
|
||||||
self.pixels.resize_surface(size.width, size.height)?;
|
let pixels = &mut self.pixels.as_ref().lock().unwrap();
|
||||||
|
pixels.resize_surface(size.width, size.height)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,20 +196,32 @@ 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();
|
let randomness = self.raytracing_options.ray_randomness;
|
||||||
let randomness = &self.raytracing_options.ray_randomness;
|
let samples = self.raytracing_options.ray_samples;
|
||||||
let samples = &self.raytracing_options.ray_samples;
|
let samples_f32 = samples as f32;
|
||||||
let samples_f32 = *samples as f32;
|
let mut handles = vec![];
|
||||||
for _ in 0..self.raytracing_options.rays_per_pass {
|
|
||||||
|
for _ in 0..self.raytracing_options.pixels_per_pass {
|
||||||
|
for _ in 0..self.raytracing_options.threads {
|
||||||
//Get random index from queue
|
//Get random index from queue
|
||||||
let index = match self.ray_queue.pop() {
|
let queue = &mut self.ray_queue.clone();
|
||||||
|
let index = match queue.lock().unwrap().pop() {
|
||||||
Some(index) => index,
|
Some(index) => index,
|
||||||
None => break,
|
None => break,
|
||||||
};
|
};
|
||||||
|
//Create a nre thread for this pixel
|
||||||
|
let handle = thread::spawn({
|
||||||
|
let rays = self.rays.clone();
|
||||||
|
let scene = self.scene.clone();
|
||||||
|
let options = self.raytracing_options.clone();
|
||||||
|
let bvh = self.bvh.clone();
|
||||||
|
let rays = rays.clone();
|
||||||
|
let pixels_mutex = self.pixels.clone();
|
||||||
|
move || {
|
||||||
//Shade colour for selected ray
|
//Shade colour for selected ray
|
||||||
let mut colour = Vector3::zeros();
|
let mut colour: Vector3<f32> = Vector3::zeros();
|
||||||
for _ in 0..*samples {
|
for _ in 0..samples {
|
||||||
let ray = &self.rays[index];
|
let ray = &rays[index];
|
||||||
let point = ray.a;
|
let point = ray.a;
|
||||||
let dir = ray.b;
|
let dir = ray.b;
|
||||||
let rx = (random::<f64>() - 0.5) / randomness;
|
let rx = (random::<f64>() - 0.5) / randomness;
|
||||||
@@ -213,21 +233,30 @@ impl State {
|
|||||||
|
|
||||||
let rand_ray = Ray::new(point, Vector3::new(nx, ny, nz));
|
let rand_ray = Ray::new(point, Vector3::new(nx, ny, nz));
|
||||||
|
|
||||||
if let Some(ray_colour) =
|
if let Some(ray_colour) = rand_ray.shade_ray(&scene, 0, &options, &bvh)
|
||||||
rand_ray.shade_ray(&self.scene, 0, &self.raytracing_options, &self.bvh)
|
|
||||||
{
|
{
|
||||||
colour += ray_colour;
|
colour += ray_colour;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
colour = (colour / samples_f32) * 255.0;
|
colour = (colour / samples_f32) * 255.0;
|
||||||
let rgba = [colour.x as u8, colour.y as u8, colour.z as u8, 0xff];
|
let rgba = [colour.x as u8, colour.y as u8, colour.z as u8, 0xff];
|
||||||
|
let pixels = &mut pixels_mutex.lock().unwrap();
|
||||||
|
let frame = pixels.frame_mut();
|
||||||
frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba);
|
frame[index * 4..(index + 1) * 4].copy_from_slice(&rgba);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
handles.push(handle);
|
||||||
|
}
|
||||||
|
for handle in handles.drain(..) {
|
||||||
|
handle.join().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_buffer(&mut self) -> Result<(), Box<dyn Error>> {
|
fn clear_buffer(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
let frame = self.pixels.frame_mut();
|
let pixels = &mut self.pixels.as_ref().lock().unwrap();
|
||||||
|
let frame = pixels.frame_mut();
|
||||||
for pixel in frame.chunks_exact_mut(4) {
|
for pixel in frame.chunks_exact_mut(4) {
|
||||||
pixel.copy_from_slice(&self.raytracing_options.pixel_clear);
|
pixel.copy_from_slice(&self.raytracing_options.pixel_clear);
|
||||||
}
|
}
|
||||||
@@ -236,33 +265,32 @@ impl State {
|
|||||||
|
|
||||||
fn reset_queue(&mut self) {
|
fn reset_queue(&mut self) {
|
||||||
match self.raytracing_options.bvh_active {
|
match self.raytracing_options.bvh_active {
|
||||||
true => self.bvh = Some(BVH::build(&mut self.scene.nodes)),
|
true => self.bvh = Arc::new(Some(BVH::build(&self.scene.nodes))),
|
||||||
false => self.bvh = None,
|
false => self.bvh = Arc::new(None),
|
||||||
}
|
}
|
||||||
let size = self.buffer_height as usize * self.buffer_width as usize;
|
let size = self.buffer_height as usize * self.buffer_width as usize;
|
||||||
let mut ray_queue: Vec<usize> = (0..size).collect();
|
let mut ray_queue: Vec<usize> = (0..size).collect();
|
||||||
ray_queue.shuffle(&mut thread_rng());
|
ray_queue.shuffle(&mut thread_rng());
|
||||||
self.ray_queue = ray_queue;
|
self.ray_queue = Arc::new(Mutex::new(ray_queue));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(&mut self) -> Result<(), Box<dyn Error>> {
|
fn render(&mut self) -> Result<(), Box<dyn Error>> {
|
||||||
// Update state
|
// Update state
|
||||||
self.update()?;
|
self.update()?;
|
||||||
// Draw rays if we have remaining rays in queue
|
// Draw rays if we have remaining rays in queue
|
||||||
if !self.ray_queue.is_empty() {
|
|
||||||
match self.draw() {
|
match self.draw() {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("ERROR: {}", e);
|
println!("ERROR: {}", e);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Render Gui
|
// Render Gui
|
||||||
self.gui
|
self.gui
|
||||||
.prepare(&self.window)
|
.prepare(&self.window)
|
||||||
.expect("gui.prepare() failed");
|
.expect("gui.prepare() failed");
|
||||||
// Try to render pixels
|
// Try to render pixels
|
||||||
if let Err(e) = self.pixels.render_with(|encoder, render_target, context| {
|
let pixels = &mut self.pixels.as_ref().lock().unwrap();
|
||||||
|
if let Err(e) = pixels.render_with(|encoder, render_target, context| {
|
||||||
context.scaling_renderer.render(encoder, render_target); // Render pixels
|
context.scaling_renderer.render(encoder, render_target); // Render pixels
|
||||||
self.gui
|
self.gui
|
||||||
.render(&self.window, encoder, render_target, context)?;
|
.render(&self.window, encoder, render_target, context)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user