Set up intersection correctly
This commit is contained in:
31
src/gui.rs
31
src/gui.rs
@@ -17,17 +17,17 @@ const BUFFER_PROPORTION_MIN: f32 = 0.1;
|
||||
const BUFFER_PROPORTION_MAX: f32 = 1.0;
|
||||
|
||||
//RAY CONSTANTS
|
||||
const RAYS_INIT: i32 = 7000;
|
||||
const RAYS_INIT: i32 = 100;
|
||||
const RAYS_MIN: i32 = 100;
|
||||
const RAYS_MAX: i32 = 30000;
|
||||
const RAYS_MAX: i32 = 10000;
|
||||
|
||||
//MATERIAL CONSTANTS
|
||||
const MIN_D: f32 = 0.0;
|
||||
const MIN_S: f32 = 0.0;
|
||||
const MIN_SHINE: f32 = 0.0;
|
||||
const MAX_D: f32 = 1.0;
|
||||
const MAX_S: f32 = 1.0;
|
||||
const MAX_SHINE: f32 = 50.0;
|
||||
// const MIN_D: f32 = 0.0;
|
||||
// const MIN_S: f32 = 0.0;
|
||||
// const MIN_SHINE: f32 = 0.0;
|
||||
// const MAX_D: f32 = 1.0;
|
||||
// const MAX_S: f32 = 1.0;
|
||||
// const MAX_SHINE: f32 = 50.0;
|
||||
|
||||
//TRANSFORMATION CONSTANTS
|
||||
const MIN_COLOUR: f32 = 0.0;
|
||||
@@ -310,12 +310,9 @@ impl Gui {
|
||||
//Use different cameras in the scene
|
||||
if let Some(_t) = ui.tree_node("Cameras") {
|
||||
for (label, camera) in &self.scene.cameras {
|
||||
if let Some(_t) = ui.tree_node(label) {
|
||||
if ui.button("Use camera") {
|
||||
self.camera = camera.clone();
|
||||
self.event =
|
||||
Some(GuiEvent::CameraUpdate(camera.clone(), self.camera_fov));
|
||||
}
|
||||
if ui.button(label) {
|
||||
self.camera = camera.clone();
|
||||
self.event = Some(GuiEvent::CameraUpdate(camera.clone(), self.camera_fov));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -413,9 +410,9 @@ pub fn init_engine() -> Engine {
|
||||
.register_fn("Circle", Circle::new)
|
||||
.register_fn("CircleUnit", Circle::unit);
|
||||
engine
|
||||
.register_type::<Rectangle>()
|
||||
.register_fn("Rectangle", Rectangle::new)
|
||||
.register_fn("RectangleUnit", Rectangle::unit);
|
||||
.register_type::<Cube>()
|
||||
.register_fn("Cube", Cube::new)
|
||||
.register_fn("CubeUnit", Cube::unit);
|
||||
engine
|
||||
.register_type::<SteinerSurface>()
|
||||
.register_fn("Steiner", SteinerSurface::new);
|
||||
|
||||
293
src/primitive.rs
293
src/primitive.rs
@@ -5,7 +5,7 @@ use nalgebra::{distance, Matrix4, Point3, Vector3};
|
||||
use roots::{find_roots_quadratic, find_roots_quartic, Roots};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
// MATERIAL -----------------------------------------------------------------
|
||||
#[derive(Clone)]
|
||||
pub struct Material {
|
||||
@@ -15,41 +15,41 @@ pub struct 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 ks = ks.cast();
|
||||
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 ks = Vector3::new(1.0, 0.0, 1.0);
|
||||
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 ks = Vector3::new(0.25, 0.3, 0.7);
|
||||
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 ks = Vector3::new(0.8, 0.3, 0.0);
|
||||
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 ks = Vector3::new(0.3, 0.0, 0.6);
|
||||
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 ks = Vector3::new(0.0, 1.0, 0.0);
|
||||
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 normal: Vector3<f64>,
|
||||
pub incidence: Vector3<f64>,
|
||||
pub material: Arc<Material>,
|
||||
pub material: Rc<Material>,
|
||||
pub distance: f64,
|
||||
}
|
||||
impl Intersection {
|
||||
@@ -76,7 +76,6 @@ impl Intersection {
|
||||
|
||||
// BOUNDING BOX -----------------------------------------------------------------
|
||||
#[derive(Clone)]
|
||||
|
||||
struct BoundingBox {
|
||||
bln: Point3<f64>,
|
||||
trf: Point3<f64>,
|
||||
@@ -88,18 +87,30 @@ impl BoundingBox {
|
||||
let trf = trf - Vector3::new(EPSILON, EPSILON, EPSILON);
|
||||
BoundingBox { bln, trf }
|
||||
}
|
||||
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>> {
|
||||
let t1 = (self.bln - ray.a).component_div(&ray.b);
|
||||
let t2 = (self.trf - ray.a).component_div(&ray.b);
|
||||
fn intersect_bounding_box(&self, ray: &Ray) -> bool {
|
||||
let bln = &self.bln;
|
||||
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 tmax = t1.sup(&t2).max();
|
||||
|
||||
if tmax >= tmin {
|
||||
Some(ray.at_t(tmin))
|
||||
} else {
|
||||
None
|
||||
let intersect = ray.at_t(tmin);
|
||||
|
||||
// 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)]
|
||||
fn get_centroid(&self) -> Point3<f64> {
|
||||
@@ -107,10 +118,10 @@ impl BoundingBox {
|
||||
}
|
||||
}
|
||||
// PRIMITIVE TRAIT -----------------------------------------------------------------
|
||||
pub trait Primitive: Send + Sync {
|
||||
pub trait Primitive {
|
||||
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection>;
|
||||
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f64>>;
|
||||
fn get_material(&self) -> Arc<Material>;
|
||||
fn intersect_bounding_box(&self, ray: &Ray) -> bool;
|
||||
fn get_material(&self) -> Rc<Material>;
|
||||
}
|
||||
|
||||
// SPHERE -----------------------------------------------------------------
|
||||
@@ -119,16 +130,16 @@ pub struct Sphere {
|
||||
position: Point3<f64>,
|
||||
radius: f64,
|
||||
bounding_box: BoundingBox,
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
}
|
||||
|
||||
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 bln = position - radius_vec;
|
||||
let trf = position + radius_vec;
|
||||
let bounding_box = BoundingBox::new(bln, trf);
|
||||
Arc::new(Sphere {
|
||||
Rc::new(Sphere {
|
||||
position,
|
||||
radius,
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -175,16 +186,16 @@ impl Primitive for Sphere {
|
||||
point: intersect,
|
||||
normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: t,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +206,7 @@ pub struct Circle {
|
||||
position: Point3<f64>,
|
||||
radius: f64,
|
||||
normal: Vector3<f64>,
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
@@ -204,13 +215,13 @@ impl Circle {
|
||||
position: Point3<f64>,
|
||||
radius: f64,
|
||||
normal: Vector3<f64>,
|
||||
material: Arc<Material>,
|
||||
) -> Arc<dyn Primitive> {
|
||||
material: Rc<Material>,
|
||||
) -> Rc<dyn Primitive> {
|
||||
let radius_vec = Vector3::new(radius, radius, radius);
|
||||
let bln = position - radius_vec;
|
||||
let trf = position + radius_vec;
|
||||
let bounding_box = BoundingBox::new(bln, trf);
|
||||
Arc::new(Circle {
|
||||
Rc::new(Circle {
|
||||
position,
|
||||
radius,
|
||||
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 normal = Vector3::new(0.0, 1.0, 0.0);
|
||||
let radius = 1.0;
|
||||
@@ -229,7 +240,7 @@ impl Circle {
|
||||
let trf = Point3::new(radius, 0.0, EPSILON);
|
||||
let bounding_box = BoundingBox { bln, trf };
|
||||
|
||||
Arc::new(Circle {
|
||||
Rc::new(Circle {
|
||||
position,
|
||||
normal,
|
||||
radius,
|
||||
@@ -256,18 +267,18 @@ impl Primitive for Circle {
|
||||
point: intersect,
|
||||
normal: self.normal.normalize(),
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: t,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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)
|
||||
}
|
||||
}
|
||||
@@ -277,29 +288,29 @@ impl Primitive for Circle {
|
||||
pub struct Cylinder {
|
||||
radius: f64,
|
||||
height: f64,
|
||||
base_circle: Arc<dyn Primitive>,
|
||||
top_circle: Arc<dyn Primitive>,
|
||||
material: Arc<Material>,
|
||||
base_circle: Rc<dyn Primitive>,
|
||||
top_circle: Rc<dyn Primitive>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
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(
|
||||
Point3::new(0.0, 0.0, 0.0),
|
||||
radius,
|
||||
Vector3::new(0.0, -1.0, 0.0),
|
||||
Arc::clone(&material),
|
||||
Rc::clone(&material),
|
||||
);
|
||||
let top_circle = Circle::new(
|
||||
Point3::new(0.0, height, 0.0),
|
||||
radius,
|
||||
Vector3::new(0.0, 1.0, 0.0),
|
||||
Arc::clone(&material),
|
||||
Rc::clone(&material),
|
||||
);
|
||||
let bln = Point3::new(-radius, 0.0, -radius);
|
||||
let trf = Point3::new(radius, height, radius);
|
||||
Arc::new(Cylinder {
|
||||
Rc::new(Cylinder {
|
||||
radius,
|
||||
height,
|
||||
base_circle,
|
||||
@@ -347,7 +358,7 @@ impl Primitive for Cylinder {
|
||||
point: intersect,
|
||||
normal: normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: t,
|
||||
})
|
||||
} else {
|
||||
@@ -390,11 +401,11 @@ impl Primitive for Cylinder {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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)
|
||||
}
|
||||
}
|
||||
@@ -405,22 +416,22 @@ pub struct Cone {
|
||||
radius: f64,
|
||||
base: f64,
|
||||
apex: f64,
|
||||
circle: Arc<dyn Primitive>,
|
||||
material: Arc<Material>,
|
||||
circle: Rc<dyn Primitive>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
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(
|
||||
Point3::new(0.0, base, 0.0),
|
||||
radius,
|
||||
Vector3::new(0.0, 1.0, 0.0),
|
||||
Arc::clone(&material),
|
||||
Rc::clone(&material),
|
||||
);
|
||||
let bln = Point3::new(-radius, base, -radius);
|
||||
let trf = Point3::new(radius, base + apex, radius);
|
||||
Arc::new(Cone {
|
||||
Rc::new(Cone {
|
||||
radius: radius / 2.0,
|
||||
base,
|
||||
apex,
|
||||
@@ -429,7 +440,7 @@ impl Cone {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -480,7 +491,7 @@ impl Primitive for Cone {
|
||||
point: intersect,
|
||||
normal: self.get_normal(intersect),
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: t,
|
||||
}),
|
||||
false => None,
|
||||
@@ -505,11 +516,11 @@ impl Primitive for Cone {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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)
|
||||
}
|
||||
}
|
||||
@@ -520,7 +531,7 @@ pub struct Rectangle {
|
||||
position: Point3<f64>,
|
||||
normal: Vector3<f64>,
|
||||
width_direction: Vector3<f64>,
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
width: f64,
|
||||
height: f64,
|
||||
bounding_box: BoundingBox,
|
||||
@@ -533,14 +544,14 @@ impl Rectangle {
|
||||
width_direction: Vector3<f64>,
|
||||
width: f64,
|
||||
height: f64,
|
||||
material: Arc<Material>,
|
||||
) -> Arc<dyn Primitive> {
|
||||
material: Rc<Material>,
|
||||
) -> Rc<dyn Primitive> {
|
||||
let normal = normal.normalize();
|
||||
let width_direction = width_direction.normalize();
|
||||
let height_direction = width_direction.cross(&normal);
|
||||
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;
|
||||
Arc::new(Rectangle {
|
||||
Rc::new(Rectangle {
|
||||
position,
|
||||
normal: normal.normalize(),
|
||||
width_direction: width_direction.normalize(),
|
||||
@@ -550,7 +561,7 @@ impl Rectangle {
|
||||
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(
|
||||
Point3::new(0.0, 0.0, 0.0),
|
||||
Vector3::new(0.0, 1.0, 0.0),
|
||||
@@ -586,18 +597,18 @@ impl Primitive for Rectangle {
|
||||
point: intersect,
|
||||
normal: self.normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: t,
|
||||
});
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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)
|
||||
}
|
||||
}
|
||||
@@ -607,13 +618,13 @@ impl Primitive for Rectangle {
|
||||
pub struct Cube {
|
||||
bln: Point3<f64>,
|
||||
trf: Point3<f64>,
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
impl Cube {
|
||||
pub fn new(bln: Point3<f64>, trf: Point3<f64>, material: Arc<Material>) -> Arc<dyn Primitive> {
|
||||
Arc::new(Cube {
|
||||
pub fn new(bln: Point3<f64>, trf: Point3<f64>, material: Rc<Material>) -> Rc<dyn Primitive> {
|
||||
Rc::new(Cube {
|
||||
bln,
|
||||
trf,
|
||||
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 trf = Point3::new(1.0, 1.0, 1.0);
|
||||
Cube::new(bln, trf, material)
|
||||
@@ -646,12 +657,12 @@ impl Primitive for Cube {
|
||||
let intersect = ray.at_t(tmin);
|
||||
|
||||
// Check if the intersection is outside the box
|
||||
if intersect.x < bln.x
|
||||
|| intersect.x > trf.x
|
||||
|| intersect.y < bln.y
|
||||
|| intersect.y > trf.y
|
||||
|| intersect.z < bln.z
|
||||
|| intersect.z > trf.z
|
||||
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 None; // Intersection is outside the box
|
||||
}
|
||||
@@ -675,7 +686,7 @@ impl Primitive for Cube {
|
||||
point: intersect,
|
||||
normal: normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: tmin,
|
||||
})
|
||||
} 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)
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<Material> {
|
||||
Rc::clone(&self.material)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -700,7 +711,7 @@ pub struct Triangle {
|
||||
v: Point3<f64>,
|
||||
w: Point3<f64>,
|
||||
normal: Vector3<f64>,
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
@@ -709,15 +720,15 @@ impl Triangle {
|
||||
u: Point3<f64>,
|
||||
v: Point3<f64>,
|
||||
w: Point3<f64>,
|
||||
material: Arc<Material>,
|
||||
) -> Arc<dyn Primitive> {
|
||||
material: Rc<Material>,
|
||||
) -> Rc<dyn Primitive> {
|
||||
let uv = v - u;
|
||||
let uw = w - u;
|
||||
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 };
|
||||
Arc::new(Triangle {
|
||||
Rc::new(Triangle {
|
||||
u,
|
||||
v,
|
||||
w,
|
||||
@@ -727,7 +738,7 @@ impl Triangle {
|
||||
})
|
||||
}
|
||||
#[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 v = Point3::new(0.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,
|
||||
normal: normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
distance: t,
|
||||
})
|
||||
} else {
|
||||
@@ -776,11 +787,11 @@ impl Primitive for Triangle {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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)
|
||||
}
|
||||
}
|
||||
@@ -788,33 +799,29 @@ impl Primitive for Triangle {
|
||||
// MESH -----------------------------------------------------------------
|
||||
#[derive(Clone)]
|
||||
pub struct Mesh {
|
||||
triangles: Vec<Arc<Triangle>>,
|
||||
material: Arc<Material>,
|
||||
triangles: Vec<Triangle>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
impl Mesh {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(triangles: Vec<Arc<Triangle>>, material: Arc<Material>) -> Arc<dyn Primitive> {
|
||||
pub fn new(triangles: Vec<Triangle>, material: Rc<Material>) -> Rc<dyn Primitive> {
|
||||
// Calculate the bounding box for the entire mesh based on the bounding boxes of individual triangles
|
||||
let bounding_box = Mesh::compute_bounding_box(&triangles);
|
||||
|
||||
Arc::new(Mesh {
|
||||
Rc::new(Mesh {
|
||||
triangles,
|
||||
material,
|
||||
bounding_box,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn compute_bounding_box(triangles: &Vec<Arc<Triangle>>) -> BoundingBox {
|
||||
fn compute_bounding_box(triangles: &Vec<Triangle>) -> BoundingBox {
|
||||
let mut bln = Point3::new(INFINITY, INFINITY, INFINITY);
|
||||
let mut trf = -bln;
|
||||
for triangle in triangles {
|
||||
bln = bln.inf(&triangle.u);
|
||||
bln = bln.inf(&triangle.v);
|
||||
bln = bln.inf(&triangle.w);
|
||||
|
||||
trf = trf.sup(&triangle.u);
|
||||
trf = trf.sup(&triangle.v);
|
||||
trf = trf.sup(&triangle.w);
|
||||
@@ -822,8 +829,8 @@ impl Mesh {
|
||||
BoundingBox { bln, trf }
|
||||
}
|
||||
|
||||
pub fn from_file(filename: &str, material: Arc<Material>) -> Arc<dyn Primitive> {
|
||||
let mut triangles: Vec<Arc<dyn Primitive>> = Vec::new();
|
||||
pub fn from_file(filename: &str, material: Rc<Material>) -> Rc<dyn Primitive> {
|
||||
let mut triangles: Vec<Triangle> = Vec::new();
|
||||
let mut vertices: Vec<Point3<f64>> = Vec::new();
|
||||
|
||||
let file = File::open(filename).expect("Failed to open file");
|
||||
@@ -857,10 +864,24 @@ impl Mesh {
|
||||
let v3: usize =
|
||||
v3_str.parse().expect("Failed to parse vertex index");
|
||||
// Indices in OBJ files are 1-based, so subtract 1 to convert to 0-based.
|
||||
let a = vertices[v1 - 1];
|
||||
let b = vertices[v2 - 1];
|
||||
let c = vertices[v3 - 1];
|
||||
triangles.push(Triangle::new(a, b, c, Arc::clone(&material)));
|
||||
let u = vertices[v1 - 1];
|
||||
let v = vertices[v2 - 1];
|
||||
let w = vertices[v3 - 1];
|
||||
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
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<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)
|
||||
}
|
||||
}
|
||||
@@ -905,16 +926,16 @@ impl Primitive for Mesh {
|
||||
// STEINER -----------------------------------------------------------------
|
||||
#[derive(Clone)]
|
||||
pub struct SteinerSurface {
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
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
|
||||
let trf = 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,
|
||||
bounding_box: BoundingBox { bln, trf },
|
||||
})
|
||||
@@ -989,17 +1010,17 @@ impl Primitive for SteinerSurface {
|
||||
point,
|
||||
normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
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)
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<Material> {
|
||||
Rc::clone(&self.material)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,16 +1038,16 @@ fn smallest_non_zero(arr: &[f64]) -> Option<f64> {
|
||||
pub struct Torus {
|
||||
inner_rad: f64,
|
||||
outer_rad: f64,
|
||||
material: Arc<Material>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
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
|
||||
let trf = 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,
|
||||
outer_rad,
|
||||
material,
|
||||
@@ -1133,34 +1154,34 @@ impl Primitive for Torus {
|
||||
point,
|
||||
normal,
|
||||
incidence: ray.b,
|
||||
material: Arc::clone(&self.material),
|
||||
material: Rc::clone(&self.material),
|
||||
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)
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
Arc::clone(&self.material)
|
||||
fn get_material(&self) -> Rc<Material> {
|
||||
Rc::clone(&self.material)
|
||||
}
|
||||
}
|
||||
|
||||
// GNOMON -----------------------------------------------------------------
|
||||
#[derive(Clone)]
|
||||
pub struct Gnonom {
|
||||
x_cube: Arc<dyn Primitive>,
|
||||
y_cube: Arc<dyn Primitive>,
|
||||
z_cube: Arc<dyn Primitive>,
|
||||
material: Arc<Material>,
|
||||
x_cube: Rc<dyn Primitive>,
|
||||
y_cube: Rc<dyn Primitive>,
|
||||
z_cube: Rc<dyn Primitive>,
|
||||
material: Rc<Material>,
|
||||
bounding_box: BoundingBox,
|
||||
}
|
||||
|
||||
impl Gnonom {
|
||||
const GNONOM_WIDTH: f64 = 0.1;
|
||||
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(
|
||||
Point3::new(0.0, -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,
|
||||
),
|
||||
};
|
||||
Arc::new(Gnonom {
|
||||
Rc::new(Gnonom {
|
||||
x_cube,
|
||||
y_cube,
|
||||
z_cube,
|
||||
@@ -1215,11 +1236,11 @@ impl Primitive for Gnonom {
|
||||
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)
|
||||
}
|
||||
|
||||
fn get_material(&self) -> Arc<Material> {
|
||||
fn get_material(&self) -> Rc<Material> {
|
||||
self.material.clone()
|
||||
}
|
||||
}
|
||||
|
||||
44
src/ray.rs
44
src/ray.rs
@@ -1,10 +1,5 @@
|
||||
use crate::{
|
||||
primitive::Intersection,
|
||||
raytracer::phong_shade_point,
|
||||
scene::{Node, Scene},
|
||||
};
|
||||
use crate::{primitive::Intersection, raytracer::phong_shade_point, scene::Scene};
|
||||
use nalgebra::{Matrix4, Point3, Vector3};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
// 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
|
||||
pub fn shade_ray(&self, scene: &Scene) -> Option<Vector3<u8>> {
|
||||
//Get the closest intersection of the ray with the scene
|
||||
let intersect = self.get_closest_intersection(&scene.nodes);
|
||||
//Shade the intersection point if there is one
|
||||
match intersect {
|
||||
Some(intersect) => Some(phong_shade_point(&scene, &intersect)), // If there is an intersection, shade it
|
||||
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;
|
||||
let mut closest_node = None;
|
||||
|
||||
for (_, node) in nodes {
|
||||
// Clone arc to primitive
|
||||
let primitive = node.primitive.clone();
|
||||
for (_, node) in &scene.nodes {
|
||||
// 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() {
|
||||
if node.primitive.intersect_bounding_box(&ray) {
|
||||
// Check primitive intersection
|
||||
if let Some(intersect) = primitive.intersect_ray(&ray) {
|
||||
if let Some(intersect) = node.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);
|
||||
closest_node = Some(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//Return None if we find no intersection, some if we do find one
|
||||
closest_intersect
|
||||
|
||||
//Shade the intersection point if there is one
|
||||
match closest_intersect {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Return a transformed version of the ray
|
||||
pub fn transform(&self, trans: &Matrix4<f64>) -> Ray {
|
||||
Ray {
|
||||
|
||||
@@ -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
|
||||
pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8> {
|
||||
let Intersection {
|
||||
point,
|
||||
normal,
|
||||
incidence,
|
||||
material,
|
||||
..
|
||||
} = intersect;
|
||||
let point = &intersect.point;
|
||||
let material = &intersect.material;
|
||||
let normal = &intersect.normal;
|
||||
let incidence = &intersect.incidence;
|
||||
|
||||
let kd = material.kd;
|
||||
let ks = material.ks;
|
||||
let kd = &material.kd;
|
||||
let ks = &material.ks;
|
||||
let shininess = material.shininess;
|
||||
|
||||
// Point to camera
|
||||
let to_camera = -incidence;
|
||||
|
||||
// Compute the ambient light component and set it as base colour
|
||||
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 to_light = to_light;
|
||||
|
||||
let to_light_ray = Ray::new(point.clone() + normal * EPSILON, to_light);
|
||||
if light_blocked(scene, to_light_ray) {
|
||||
continue;
|
||||
}
|
||||
//let to_light_ray = Ray::new(point.clone() + normal * EPSILON, to_light);
|
||||
// if light_blocked(scene, to_light_ray) {
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// Point to camera
|
||||
let to_camera = -incidence;
|
||||
// Diffuse component
|
||||
let n_dot_l = normal.dot(&to_light).max(0.0) as f32;
|
||||
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();
|
||||
if n_dot_l > 0.0 {
|
||||
// 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;
|
||||
specular = ks * n_dot_h.powf(shininess);
|
||||
}
|
||||
|
||||
// Compute light falloff
|
||||
let falloff = 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 {
|
||||
for (_, node) in &scene.nodes {
|
||||
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() {
|
||||
return true;
|
||||
}
|
||||
|
||||
12
src/scene.rs
12
src/scene.rs
@@ -3,11 +3,11 @@ use crate::light::Light;
|
||||
use crate::primitive::*;
|
||||
use nalgebra::{Matrix4, Vector3};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::rc::Rc;
|
||||
#[derive(Clone)]
|
||||
pub struct Node {
|
||||
//Primitive
|
||||
pub primitive: Arc<dyn Primitive>,
|
||||
pub primitive: Rc<dyn Primitive>,
|
||||
//Transformations
|
||||
pub rotation: [f64; 3],
|
||||
pub scale: [f64; 3],
|
||||
@@ -19,7 +19,7 @@ pub struct Node {
|
||||
|
||||
impl Node {
|
||||
//New node with no transformations
|
||||
pub fn new(primitive: Arc<dyn Primitive>) -> Node {
|
||||
pub fn new(primitive: Rc<dyn Primitive>) -> Node {
|
||||
Node {
|
||||
primitive,
|
||||
rotation: [0.0, 0.0, 0.0],
|
||||
@@ -30,7 +30,7 @@ impl Node {
|
||||
}
|
||||
}
|
||||
//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();
|
||||
child.primitive = primitive;
|
||||
child
|
||||
@@ -90,7 +90,7 @@ impl Node {
|
||||
#[derive(Clone)]
|
||||
pub struct Scene {
|
||||
pub nodes: HashMap<String, Node>,
|
||||
pub materials: HashMap<String, Arc<Material>>,
|
||||
pub materials: HashMap<String, Rc<Material>>,
|
||||
pub lights: HashMap<String, Light>,
|
||||
pub cameras: HashMap<String, Camera>,
|
||||
}
|
||||
@@ -110,7 +110,7 @@ impl Scene {
|
||||
self.nodes.insert(label, node);
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
// Adds a light to the scene
|
||||
|
||||
@@ -23,7 +23,7 @@ const START_HEIGHT: i32 = 700;
|
||||
const COLOUR_CLEAR: [u8; 4] = [0x22, 0x00, 0x11, 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 struct State {
|
||||
@@ -145,6 +145,7 @@ impl State {
|
||||
|
||||
fn draw(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
//Draw ray_num in a block
|
||||
let frame = self.pixels.frame_mut();
|
||||
for _ in 0..self.gui.ray_num {
|
||||
//Get random index from queue
|
||||
let index = match self.ray_queue.pop() {
|
||||
@@ -155,7 +156,6 @@ impl State {
|
||||
let colour = &self.rays[index].shade_ray(&self.scene);
|
||||
//Assign colour to pixel in frame
|
||||
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);
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user