Removed pixels

Finished raytracer
Reimplementing imgui
This commit is contained in:
STP
2023-11-15 16:56:19 -05:00
parent 2e69164dde
commit 80fcc6c8bc
8 changed files with 1159 additions and 658 deletions

1429
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,25 +4,18 @@ version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies.image]
version = "0.24"
default-features = false
features = ["png", "jpeg"]
[dependencies.winit]
version = "0.27"
features = ["x11"]
[dependencies] [dependencies]
cfg-if = "1" cfg-if = "1"
env_logger = "0.10" env_logger = "0.10"
log = "0.4" log = "0.4"
wgpu = "0.18"
pollster = "0.3" pollster = "0.3"
bytemuck = { version = "1.12", features = [ "derive" ] }
anyhow = "1.0" anyhow = "1.0"
nalgebra = "0.32.3" nalgebra = "0.32.3"
roots = "0.0.8" roots = "0.0.8"
lazy_static = "1.4.0" pyo3 = "0.20.0"
arc = "0.0.1" imgui = "0.11"
pixels = "0.13.0" imgui-wgpu = "0.24"
imgui-winit-support = "0.11"
winit_input_helper = "0.13"
winit = "0.29.3"
wgpu = "0.18.0"

View File

@@ -53,8 +53,9 @@ impl Camera {
let view_proj = self.build_view_projection_matrix(); let view_proj = self.build_view_projection_matrix();
view_proj.try_inverse().expect("Cannot invert!") view_proj.try_inverse().expect("Cannot invert!")
} }
pub fn cast_rays(&self, width: usize, height: usize) -> Vec<Ray> { pub fn cast_rays(&self, width: u32, height: u32) -> Vec<Ray> {
let inverse_matrix = self.build_inverse_view_projection_matrix(); let inverse_matrix = self.build_inverse_view_projection_matrix();
let dx = 2.0 / width as f32; let dx = 2.0 / width as f32;
let dy = 2.0 / height as f32; let dy = 2.0 / height as f32;

View File

@@ -1,79 +0,0 @@
use pixels::{Error, Pixels, SurfaceTexture};
use std::time::Instant;
use winit::{
event::{Event, WindowEvent},
event_loop::{ControlFlow, EventLoop},
window::WindowBuilder,
};
pub fn run() -> Result<(), Error> {
// Create an event loop and window using winit
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
// Create a Pixels instance for drawing
let mut pixels = {
let window_size = window.inner_size();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(800, 600, surface_texture).unwrap()
};
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Poll;
match event {
Event::WindowEvent {
ref event,
window_id,
} if window_id == window.id() => {
match event {
WindowEvent::CloseRequested => *control_flow = ControlFlow::Exit,
WindowEvent::Resized(physical_size) => {
//We want to change the size of the pixel display
pixels
.resize_surface(physical_size.width, physical_size.height)
.expect("Could not resize");
pixels
.resize_buffer(physical_size.width, physical_size.height)
.expect("Could not resize");
}
WindowEvent::ScaleFactorChanged { new_inner_size, .. } => {
//We want to change the size of the pixel display
// new_inner_size is &mut so w have to dereference it twice
pixels
.resize_surface(new_inner_size.width, new_inner_size.height)
.expect("Could not resize!");
pixels
.resize_buffer(new_inner_size.width, new_inner_size.height)
.expect("Could not resize");
}
WindowEvent::KeyboardInput { input, .. } => {
println!("Key input: {}", input.scancode);
}
_ => {}
}
}
Event::RedrawRequested(_) => {
// Draw a pixel at every coordinate
for (i, pixel) in pixels.frame_mut().chunks_exact_mut(4).enumerate() {
let r = (i as u8).wrapping_mul(50);
let g = 43;
let b = 3;
let a = 255;
pixel.copy_from_slice(&[r, g, b, a]);
}
// Render the frame
if pixels.render().is_err() {
eprintln!("Failed to render frame");
}
}
Event::MainEventsCleared => {
// RedrawRequested will only trigger once, unless we manually
// request it.
window.request_redraw();
}
_ => {}
}
});
}

View File

@@ -2,16 +2,16 @@
#![allow(unused_imports)] #![allow(unused_imports)]
#![allow(unused_variables)] #![allow(unused_variables)]
//Use linear algebra module //Use linear algebra module
use display::run; use window::run;
//Cameras //Cameras
mod camera; mod camera;
mod display;
mod light; mod light;
mod primitive; mod primitive;
mod ray; mod ray;
mod raytracer; mod raytracer;
mod scene; mod scene;
mod window;
// mod state; // mod state;
// mod texture; // mod texture;
// mod vertex; // mod vertex;
@@ -20,5 +20,5 @@ const EPSILON: f32 = 1e-7;
const INFINITY: f32 = 1e7; const INFINITY: f32 = 1e7;
fn main() { fn main() {
run().expect(""); run().expect("YEY");
} }

View File

@@ -5,12 +5,7 @@ use roots::{find_roots_quadratic, Roots};
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::path::Path; use std::path::Path;
use std::sync::Arc;
use lazy_static::lazy_static;
lazy_static! {
static ref MAGENTA_MATERIAL: Material = Material::magenta();
}
// MATERIAL ----------------------------------------------------------------- // MATERIAL -----------------------------------------------------------------
pub struct Material { pub struct Material {
@@ -30,27 +25,27 @@ impl Material {
} }
} }
// INTERSECTION ----------------------------------------------------------------- // INTERSECTION -----------------------------------------------------------------
pub struct Intersection<'a> { pub struct Intersection {
// Information about an intersection // Information about an intersection
pub primitive: &'a dyn Primitive<'a>,
pub point: Point3<f32>, pub point: Point3<f32>,
pub normal: Vector3<f32>, pub normal: Vector3<f32>,
pub incidence: Vector3<f32>, pub incidence: Vector3<f32>,
pub material: Arc<Material>,
pub distance: f32, pub distance: f32,
} }
impl<'a> Intersection<'a> { impl Intersection {
pub fn new( pub fn new(
primitive: &'a dyn Primitive<'a>,
point: Point3<f32>, point: Point3<f32>,
normal: Vector3<f32>, normal: Vector3<f32>,
incidence: Vector3<f32>, incidence: Vector3<f32>,
material: Arc<Material>,
t: f32, t: f32,
) -> Self { ) -> Self {
Intersection { Intersection {
primitive,
point, point,
normal, normal,
incidence, incidence,
material,
distance: t, distance: t,
} }
} }
@@ -80,22 +75,22 @@ impl BoundingBox {
} }
} }
// PRIMITIVE TRAIT ----------------------------------------------------------------- // PRIMITIVE TRAIT -----------------------------------------------------------------
pub trait Primitive<'a> { 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<f32>>; fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>>;
fn get_material(&self) -> &'a Material; fn get_material(&self) -> Arc<Material>;
} }
// SPHERE ----------------------------------------------------------------- // SPHERE -----------------------------------------------------------------
struct Sphere<'a> { struct Sphere {
position: Point3<f32>, position: Point3<f32>,
radius: f32, radius: f32,
material: &'a Material,
bounding_box: BoundingBox, bounding_box: BoundingBox,
material: Arc<Material>,
} }
impl<'a> Sphere<'a> { impl Sphere {
fn new(position: Point3<f32>, radius: f32, material: &'a Material) -> Self { fn new(position: Point3<f32>, radius: f32, material: Arc<Material>) -> Self {
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;
@@ -103,17 +98,17 @@ impl<'a> Sphere<'a> {
Sphere { Sphere {
position, position,
radius, radius,
material,
bounding_box, bounding_box,
material,
} }
} }
fn unit() -> Self { fn unit(material: Arc<Material>) -> Self {
Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, &MAGENTA_MATERIAL) Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, material)
} }
} }
impl<'a> Primitive<'a> for Sphere<'a> { impl Primitive for Sphere {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let pos = &ray.a; let pos = &ray.a;
let dir = &ray.b; let dir = &ray.b;
@@ -144,16 +139,16 @@ impl<'a> Primitive<'a> for Sphere<'a> {
let intersect = ray.at_t(t); let intersect = ray.at_t(t);
let normal = (intersect - self.position).normalize(); let normal = (intersect - self.position).normalize();
Some(Intersection { Some(Intersection {
primitive: self,
point: intersect, point: intersect,
normal, normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material),
distance: t, distance: t,
}) })
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> { fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
@@ -162,20 +157,20 @@ impl<'a> Primitive<'a> for Sphere<'a> {
} }
// CIRCLE ----------------------------------------------------------------- // CIRCLE -----------------------------------------------------------------
struct Circle<'a> { struct Circle {
position: Point3<f32>, position: Point3<f32>,
radius: f32, radius: f32,
normal: Vector3<f32>, normal: Vector3<f32>,
material: &'a Material, material: Arc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl<'a> Circle<'a> { impl Circle {
fn new( fn new(
position: Point3<f32>, position: Point3<f32>,
radius: f32, radius: f32,
normal: Vector3<f32>, normal: Vector3<f32>,
material: &'a Material, material: Arc<Material>,
) -> Self { ) -> Self {
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;
@@ -190,11 +185,11 @@ impl<'a> Circle<'a> {
} }
} }
fn unit() -> Self { fn unit(material: Arc<Material>) -> Self {
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;
let material = &MAGENTA_MATERIAL; let material = material;
let bln = Point3::new(-radius, 0.0, -EPSILON); let bln = Point3::new(-radius, 0.0, -EPSILON);
let trf = Point3::new(radius, 0.0, EPSILON); let trf = Point3::new(radius, 0.0, EPSILON);
@@ -210,7 +205,7 @@ impl<'a> Circle<'a> {
} }
} }
impl<'a> Primitive<'a> for Circle<'a> { impl Primitive for Circle {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let constant = self.position.coords.dot(&self.normal); let constant = self.position.coords.dot(&self.normal);
let denominator = ray.b.dot(&self.normal); let denominator = ray.b.dot(&self.normal);
@@ -224,18 +219,18 @@ impl<'a> Primitive<'a> for Circle<'a> {
true => return None, true => return None,
false => { false => {
return Some(Intersection { return Some(Intersection {
primitive: self,
point: intersect, point: intersect,
normal: self.normal, normal: self.normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material),
distance: t, distance: t,
}) })
} }
} }
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> { fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
@@ -244,23 +239,23 @@ impl<'a> Primitive<'a> for Circle<'a> {
} }
// CYLINDER ----------------------------------------------------------------- // CYLINDER -----------------------------------------------------------------
struct Cylinder<'a> { struct Cylinder {
radius: f32, radius: f32,
base: f32, base: f32,
height: f32, height: f32,
base_circle: &'a Circle<'a>, base_circle: Circle,
height_circle: &'a Circle<'a>, height_circle: Circle,
material: &'a Material, material: Arc<Material>,
} }
impl<'a> Cylinder<'a> {} impl Cylinder {}
impl<'a> Primitive<'a> for Cylinder<'a> { impl Primitive for Cylinder {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
todo!() todo!()
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
todo!() todo!()
} }
@@ -270,22 +265,22 @@ impl<'a> Primitive<'a> for Cylinder<'a> {
} }
// CONE ----------------------------------------------------------------- // CONE -----------------------------------------------------------------
struct Cone<'a> { pub struct Cone {
radius: f32, radius: f32,
base: f32, base: f32,
height: f32, height: f32,
circle: Circle<'a>, circle: Circle,
material: &'a Material, material: Arc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl<'a> Cone<'a> { impl Cone {
fn new(radius: f32, height: f32, base: f32, material: &'a Material) -> Self { pub fn new(radius: f32, height: f32, base: f32, material: Arc<Material>) -> Self {
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),
&material, Arc::clone(&material),
); );
let bln = Point3::new(-radius, base, -radius); let bln = Point3::new(-radius, base, -radius);
let trf = Point3::new(radius, base + height, radius); let trf = Point3::new(radius, base + height, radius);
@@ -298,11 +293,11 @@ impl<'a> Cone<'a> {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
} }
} }
fn unit() -> Self { pub fn unit(material: Arc<Material>) -> Self {
Cone::new(1.0, 2.0, -1.0, &MAGENTA_MATERIAL) Cone::new(1.0, 2.0, -1.0, material)
} }
fn get_normal(&self, intersect: Point3<f32>) -> Vector3<f32> { pub fn get_normal(&self, intersect: Point3<f32>) -> Vector3<f32> {
let r = self.radius; let r = self.radius;
let h = self.height; let h = self.height;
let (x, y, z) = (intersect.x, intersect.y, intersect.z); let (x, y, z) = (intersect.x, intersect.y, intersect.z);
@@ -311,7 +306,7 @@ impl<'a> Cone<'a> {
} }
} }
impl<'a> Primitive<'a> for Cone<'a> { impl Primitive for Cone {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let point = &ray.a; let point = &ray.a;
let dir = &ray.b; let dir = &ray.b;
@@ -346,9 +341,9 @@ impl<'a> Primitive<'a> for Cone<'a> {
let intersect = ray.at_t(t); let intersect = ray.at_t(t);
match intersect.y >= self.base && intersect.y <= self.height { match intersect.y >= self.base && intersect.y <= self.height {
true => Some(Intersection { true => Some(Intersection {
primitive: self,
point: intersect, point: intersect,
normal: self.get_normal(intersect), normal: self.get_normal(intersect),
material: Arc::clone(&self.material),
incidence: ray.b, incidence: ray.b,
distance: t, distance: t,
}), }),
@@ -374,8 +369,8 @@ impl<'a> Primitive<'a> for Cone<'a> {
} }
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> { fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
@@ -384,24 +379,24 @@ impl<'a> Primitive<'a> for Cone<'a> {
} }
// RECTANGLE ----------------------------------------------------------------- // RECTANGLE -----------------------------------------------------------------
struct Rectangle<'a> { struct Rectangle {
position: Point3<f32>, position: Point3<f32>,
normal: Vector3<f32>, normal: Vector3<f32>,
width_direction: Vector3<f32>, width_direction: Vector3<f32>,
material: &'a Material, material: Arc<Material>,
width: f32, width: f32,
height: f32, height: f32,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl<'a> Rectangle<'a> { impl Rectangle {
fn new( fn new(
position: Point3<f32>, position: Point3<f32>,
normal: Vector3<f32>, normal: Vector3<f32>,
width_direction: Vector3<f32>, width_direction: Vector3<f32>,
width: f32, width: f32,
height: f32, height: f32,
material: &'a Material, material: Arc<Material>,
) -> Self { ) -> Self {
let normal = normal.normalize(); let normal = normal.normalize();
let width_direction = width_direction.normalize(); let width_direction = width_direction.normalize();
@@ -418,19 +413,19 @@ impl<'a> Rectangle<'a> {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
} }
} }
fn unit() -> Self { fn unit(material: Arc<Material>) -> Self {
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),
Vector3::new(1.0, 0.0, 0.0), Vector3::new(1.0, 0.0, 0.0),
2.0, 2.0,
2.0, 2.0,
&MAGENTA_MATERIAL, material,
) )
} }
} }
impl<'a> Primitive<'a> for Rectangle<'a> { impl Primitive for Rectangle {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let constant = self.position.coords.dot(&self.normal); let constant = self.position.coords.dot(&self.normal);
let denominator = ray.b.dot(&self.normal); let denominator = ray.b.dot(&self.normal);
@@ -451,18 +446,18 @@ impl<'a> Primitive<'a> for Rectangle<'a> {
if pi_dot_r1 >= -w2 && pi_dot_r1 <= w2 && pi_dot_r2 >= -h2 && pi_dot_r2 <= h2 { if pi_dot_r1 >= -w2 && pi_dot_r1 <= w2 && pi_dot_r2 >= -h2 && pi_dot_r2 <= h2 {
return Some(Intersection { return Some(Intersection {
primitive: self,
point: intersect, point: intersect,
normal: self.normal, normal: self.normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material),
distance: t, distance: t,
}); });
} }
None None
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> { fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
@@ -471,16 +466,16 @@ impl<'a> Primitive<'a> for Rectangle<'a> {
} }
// BOX ----------------------------------------------------------------- // BOX -----------------------------------------------------------------
struct Box<'a> { struct Box {
width: f32, width: f32,
height: f32, height: f32,
depth: f32, depth: f32,
material: &'a Material, material: Arc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl<'a> Box<'a> { impl Box {
fn new(width: f32, height: f32, depth: f32, material: &'a Material) -> Self { fn new(width: f32, height: f32, depth: f32, material: Arc<Material>) -> Self {
let trf = Point3::new(width / 2.0, height / 2.0, depth / 2.0); let trf = Point3::new(width / 2.0, height / 2.0, depth / 2.0);
let bln = Point3::new(-width / 2.0, -height / 2.0, -depth / 2.0); let bln = Point3::new(-width / 2.0, -height / 2.0, -depth / 2.0);
Box { Box {
@@ -491,12 +486,12 @@ impl<'a> Box<'a> {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
} }
} }
fn unit() -> Self { fn unit(material: Arc<Material>) -> Self {
Box::new(2.0, 2.0, 2.0, &MAGENTA_MATERIAL) Box::new(2.0, 2.0, 2.0, material)
} }
} }
impl<'a> Primitive<'a> for Box<'a> { impl Primitive for Box {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
// Compute the minimum and maximum t-values for each axis of the bounding box // Compute the minimum and maximum t-values for each axis of the bounding box
let t1 = (self.bounding_box.bln - ray.a).component_div(&ray.b); let t1 = (self.bounding_box.bln - ray.a).component_div(&ray.b);
@@ -538,10 +533,10 @@ impl<'a> Primitive<'a> for Box<'a> {
}; };
Some(Intersection { Some(Intersection {
primitive: self,
point: intersect, point: intersect,
normal, normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material),
distance: tmin, distance: tmin,
}) })
} else { } else {
@@ -553,23 +548,23 @@ impl<'a> Primitive<'a> for Box<'a> {
self.bounding_box.intersect_bounding_box(ray) self.bounding_box.intersect_bounding_box(ray)
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
} }
// TRIANGLE ----------------------------------------------------------------- // TRIANGLE -----------------------------------------------------------------
struct Triangle<'a> { struct Triangle {
u: Point3<f32>, u: Point3<f32>,
v: Point3<f32>, v: Point3<f32>,
w: Point3<f32>, w: Point3<f32>,
normal: Vector3<f32>, normal: Vector3<f32>,
material: &'a Material, material: Arc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl<'a> Triangle<'a> { impl Triangle {
fn new(u: Point3<f32>, v: Point3<f32>, w: Point3<f32>, material: &'a Material) -> Self { fn new(u: Point3<f32>, v: Point3<f32>, w: Point3<f32>, material: Arc<Material>) -> Self {
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();
@@ -585,16 +580,16 @@ impl<'a> Triangle<'a> {
bounding_box, bounding_box,
} }
} }
fn unit() -> Self { fn unit(material: Arc<Material>) -> Self {
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);
let material = &MAGENTA_MATERIAL; let material = material;
Triangle::new(u, v, w, material) Triangle::new(u, v, w, material)
} }
} }
impl<'a> Primitive<'a> for Triangle<'a> { impl Primitive for Triangle {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let constant = self.u.coords.dot(&self.normal); let constant = self.u.coords.dot(&self.normal);
let denominator = ray.b.dot(&self.normal); let denominator = ray.b.dot(&self.normal);
@@ -623,10 +618,10 @@ impl<'a> Primitive<'a> for Triangle<'a> {
if u_cross.dot(&normal) >= 0.0 && v_cross.dot(&normal) >= 0.0 && w_cross.dot(&normal) >= 0.0 if u_cross.dot(&normal) >= 0.0 && v_cross.dot(&normal) >= 0.0 && w_cross.dot(&normal) >= 0.0
{ {
Some(Intersection { Some(Intersection {
primitive: self,
point: intersect, point: intersect,
normal, normal,
incidence: ray.b, incidence: ray.b,
material: Arc::clone(&self.material),
distance: t, distance: t,
}) })
} else { } else {
@@ -634,8 +629,8 @@ impl<'a> Primitive<'a> for Triangle<'a> {
} }
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> { fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {
@@ -644,14 +639,14 @@ impl<'a> Primitive<'a> for Triangle<'a> {
} }
// MESH ----------------------------------------------------------------- // MESH -----------------------------------------------------------------
struct Mesh<'a> { struct Mesh {
triangles: Vec<Triangle<'a>>, triangles: Vec<Triangle>,
material: &'a Material, material: Arc<Material>,
bounding_box: BoundingBox, bounding_box: BoundingBox,
} }
impl<'a> Mesh<'a> { impl Mesh {
fn new(triangles: Vec<Triangle<'a>>, material: &'a Material) -> Self { fn new(triangles: Vec<Triangle>, material: Arc<Material>) -> Self {
// 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);
@@ -662,7 +657,7 @@ impl<'a> Mesh<'a> {
} }
} }
fn compute_bounding_box(triangles: &Vec<Triangle<'a>>) -> BoundingBox { fn compute_bounding_box(triangles: &Vec<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 {
@@ -677,7 +672,7 @@ impl<'a> Mesh<'a> {
BoundingBox { bln, trf } BoundingBox { bln, trf }
} }
fn from_file(filename: &str, material: &'a Material) -> Self { fn from_file(filename: &str, material: Arc<Material>) -> Self {
let mut triangles: Vec<Triangle> = Vec::new(); let mut triangles: Vec<Triangle> = Vec::new();
let mut vertices: Vec<Point3<f32>> = Vec::new(); let mut vertices: Vec<Point3<f32>> = Vec::new();
@@ -715,7 +710,7 @@ impl<'a> Mesh<'a> {
let a = vertices[v1 - 1]; let a = vertices[v1 - 1];
let b = vertices[v2 - 1]; let b = vertices[v2 - 1];
let c = vertices[v3 - 1]; let c = vertices[v3 - 1];
triangles.push(Triangle::new(a, b, c, material)); triangles.push(Triangle::new(a, b, c, Arc::clone(&material)));
} }
} }
_ => {} _ => {}
@@ -727,7 +722,7 @@ impl<'a> Mesh<'a> {
} }
} }
impl<'a> Primitive<'a> for Mesh<'a> { impl Primitive for Mesh {
fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> { fn intersect_ray(&self, ray: &Ray) -> Option<Intersection> {
let mut closest_distance = INFINITY; let mut closest_distance = INFINITY;
let mut closest_intersect: Option<Intersection> = None; let mut closest_intersect: Option<Intersection> = None;
@@ -748,8 +743,8 @@ impl<'a> Primitive<'a> for Mesh<'a> {
closest_intersect closest_intersect
} }
fn get_material(&self) -> &'a Material { fn get_material(&self) -> Arc<Material> {
self.material Arc::clone(&self.material)
} }
fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> { fn intersect_bounding_box(&self, ray: &Ray) -> Option<Point3<f32>> {

View File

@@ -5,20 +5,38 @@ use crate::{
scene::Scene, scene::Scene,
INFINITY, INFINITY,
}; };
use lazy_static::lazy_static; use std::sync::Arc;
lazy_static! {
static ref VEC3_ONE: Vector3<f32> = Vector3::new(1.0, 1.0, 1.0);
static ref VEC3_ZERO: Vector3<f32> = Vector3::new(1.0, 1.0, 1.0);
}
use nalgebra::{distance, Matrix4, Point3, Vector3, Vector4}; use nalgebra::{distance, Matrix4, Point3, Vector3, Vector4};
pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: u32, height: u32) -> Vec<Vector3<u8>> {
let mut pixel_data = vec![];
for ray in rays {
let intersect = get_closest_intersection(scene, ray);
match intersect {
Some(interect) => {
let colour = phong_shade_point(scene, &interect);
pixel_data.push(colour);
}
None => {
let colour = Vector3::new(0, 0, 0);
pixel_data.push(colour);
}
}
}
pixel_data
}
// Find the closest intersection, given a ray in world coordinates // Find the closest intersection, given a ray in world coordinates
fn get_closest_intersection<'a>(scene: &'a Scene, ray: &Ray) -> Option<Intersection<'a>> { pub fn get_closest_intersection(scene: &Scene, ray: &Ray) -> Option<Intersection> {
let mut closest_distance = INFINITY; let mut closest_distance = INFINITY;
let mut closest_intersect: Option<Intersection> = None; let mut closest_intersect: Option<Intersection> = None;
for primitive in &scene.primitives { for arc_primitive in &scene.primitives {
if primitive.intersect_bounding_box(ray) == None { let primitive = arc_primitive.clone();
if primitive.intersect_ray(ray).is_none() {
continue; continue;
}; };
@@ -37,34 +55,36 @@ fn get_closest_intersection<'a>(scene: &'a Scene, ray: &Ray) -> Option<Intersect
} }
// We want to shade a point placed in our scene // We want to shade a point placed in our scene
fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<f32> { pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8> {
//Useful vectors !!!! CHECK IF WE CAN OPTIMISE //Useful vectors !!!! CHECK IF WE CAN OPTIMISE
let zero_vector = Vector3::new(0.0, 0.0, 0.0); let zero_vector = Vector3::new(0.0, 0.0, 0.0);
let one_vector = Vector3::new(1.0, 1.0, 1.0); let one_vector = Vector3::new(1.0, 1.0, 1.0);
//Unpack the intersection data //Unpack the intersection data
let Intersection { let Intersection {
primitive,
point, point,
normal, normal,
incidence, incidence,
material,
.. ..
} = intersect; } = intersect;
let ambient_light = scene.ambient_light; let binding = scene.ambient_light.clone();
let material = primitive.get_material(); let ambient_light = binding.as_ref();
let kd = material.kd; let kd = material.kd;
let ks = material.ks; let ks = material.ks;
let shininess = material.shininess; let shininess = material.shininess;
// We should now have all the information for our ray-tracer // We should now have all the information for our ray-tracer
// Let us first compute the ambient light component and set it as out base colour // Let us first compute the ambient light component and set it as out base colour
let mut colour = kd.component_mul(&ambient_light); let mut colour = kd.component_mul(ambient_light);
for arc_light in &scene.lights {
let light = arc_light.clone();
for light in &scene.lights {
let Light { let Light {
position: light_position, position: light_position,
colour: light_colour, colour: light_colour,
falloff: light_falloff, falloff: light_falloff,
} = light; } = light.as_ref();
// Get light incidence vector // Get light incidence vector
let to_light = light_position - point; let to_light = light_position - point;
@@ -96,5 +116,9 @@ fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<f32> {
colour += light_colour.component_mul(&((diffuse + specular) * falloff)); colour += light_colour.component_mul(&((diffuse + specular) * falloff));
} }
nalgebra::clamp(colour, zero_vector, one_vector) let r = nalgebra::clamp(colour.x * 255.0, 0.0, 255.0) as u8;
let g = nalgebra::clamp(colour.y * 255.0, 0.0, 255.0) as u8;
let b = nalgebra::clamp(colour.z * 255.0, 0.0, 255.0) as u8;
Vector3::new(r, g, b)
} }

View File

@@ -2,12 +2,38 @@ use crate::camera::Camera;
use crate::light::Light; use crate::light::Light;
use crate::primitive::Primitive; use crate::primitive::Primitive;
use nalgebra::Vector3; use nalgebra::Vector3;
use std::sync::Arc;
pub struct Scene<'a> { pub struct Scene {
pub primitives: Vec<Box<dyn Primitive<'a>>>, pub primitives: Vec<Arc<dyn Primitive>>,
pub lights: Vec<Light>, pub lights: Vec<Arc<Light>>,
pub cameras: Vec<Camera>, pub cameras: Vec<Arc<Camera>>,
pub ambient_light: Vector3<f32>, pub ambient_light: Arc<Vector3<f32>>,
} }
impl<'a> Scene<'a> {} impl Scene {
// Creates a new Scene with given parameters
pub fn new(
primitives: Vec<Arc<dyn Primitive>>,
lights: Vec<Arc<Light>>,
cameras: Vec<Arc<Camera>>,
ambient_light: Arc<Vector3<f32>>,
) -> Self {
Scene {
primitives,
lights,
cameras,
ambient_light,
}
}
// Creates an empty Scene with default values
pub fn empty() -> Self {
Scene {
primitives: Vec::new(),
lights: Vec::new(),
cameras: Vec::new(),
ambient_light: Arc::new(Vector3::new(0.0, 0.0, 0.0)),
}
}
}