Working realtime tracing

This commit is contained in:
STP
2023-11-16 17:14:24 -05:00
parent a80da71455
commit 9383ef5bbf
7 changed files with 182 additions and 248 deletions

99
Cargo.lock generated
View File

@@ -657,12 +657,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.3" version = "0.3.3"
@@ -755,12 +749,6 @@ dependencies = [
"hashbrown 0.14.2", "hashbrown 0.14.2",
] ]
[[package]]
name = "indoc"
version = "2.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
[[package]] [[package]]
name = "instant" name = "instant"
version = "0.1.12" version = "0.1.12"
@@ -907,15 +895,6 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "memoffset"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "metal" name = "metal"
version = "0.24.0" version = "0.24.0"
@@ -1078,7 +1057,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"cfg-if", "cfg-if",
"libc", "libc",
"memoffset 0.6.5", "memoffset",
] ]
[[package]] [[package]]
@@ -1091,7 +1070,7 @@ dependencies = [
"bitflags 1.3.2", "bitflags 1.3.2",
"cfg-if", "cfg-if",
"libc", "libc",
"memoffset 0.6.5", "memoffset",
] ]
[[package]] [[package]]
@@ -1297,67 +1276,6 @@ version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f89dff0959d98c9758c88826cc002e2c3d0b9dfac4139711d1f30de442f1139b" checksum = "f89dff0959d98c9758c88826cc002e2c3d0b9dfac4139711d1f30de442f1139b"
[[package]]
name = "pyo3"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e8453b658fe480c3e70c8ed4e3d3ec33eb74988bd186561b0cc66b85c3bc4b"
dependencies = [
"cfg-if",
"indoc",
"libc",
"memoffset 0.9.0",
"parking_lot",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96fe70b176a89cff78f2fa7b3c930081e163d5379b4dcdf993e3ae29ca662e5"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "214929900fd25e6604661ed9cf349727c8920d47deff196c4e28165a6ef2a96b"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac53072f717aa1bfa4db832b39de8c875b7c7af4f4a6fe93cdbf9264cf8383b"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn 2.0.39",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7774b5a8282bd4f25f803b1f0d945120be959a36c72e08e7cd031c792fdfd424"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.33" version = "1.0.33"
@@ -1459,7 +1377,6 @@ dependencies = [
"nalgebra", "nalgebra",
"pixels", "pixels",
"pollster", "pollster",
"pyo3",
"roots", "roots",
"winit", "winit",
"winit_input_helper", "winit_input_helper",
@@ -1670,12 +1587,6 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "target-lexicon"
version = "0.12.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
[[package]] [[package]]
name = "termcolor" name = "termcolor"
version = "1.4.0" version = "1.4.0"
@@ -1780,12 +1691,6 @@ version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "unindent"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
[[package]] [[package]]
name = "vec_map" name = "vec_map"
version = "0.8.2" version = "0.8.2"

View File

@@ -12,7 +12,6 @@ pollster = "0.3"
anyhow = "1.0" anyhow = "1.0"
nalgebra = "0.32.3" nalgebra = "0.32.3"
roots = "0.0.8" roots = "0.0.8"
pyo3 = "0.20.0"
imgui = "0.11" imgui = "0.11"
imgui-wgpu = "0.23" imgui-wgpu = "0.23"

View File

@@ -1,9 +1,12 @@
use crate::ray::Ray; use crate::ray::Ray;
use crate::{EPSILON, INFINITY}; use crate::{EPSILON, INFINITY};
use log::error;
use nalgebra as nm; use nalgebra as nm;
use nalgebra::Matrix4; use nalgebra::Matrix4;
use nalgebra::Perspective3;
use nalgebra::Point3; use nalgebra::Point3;
use nalgebra::Vector3; use nalgebra::Vector3;
use std::env;
#[rustfmt::skip] #[rustfmt::skip]
pub const OPENGL_TO_WGPU_MATRIX: Matrix4<f32> = Matrix4::new( pub const OPENGL_TO_WGPU_MATRIX: Matrix4<f32> = Matrix4::new(
@@ -35,8 +38,8 @@ impl Camera {
) -> Self { ) -> Self {
let znear = EPSILON; let znear = EPSILON;
let zfar = INFINITY; let zfar = INFINITY;
let matrix = self.build_view_projection_matrix(eye, target, up, aspect, fovy, znear, zfar); let (matrix, inverse) =
let inverse = self.build_inverse_view_projection_matrix(eye, target, up, aspect, fovy, znear, zfar); Camera::build_matrix_and_inverse(&eye, &target, &up, aspect, fovy, znear, zfar);
Camera { Camera {
eye, eye,
target, target,
@@ -45,42 +48,73 @@ impl Camera {
aspect, aspect,
znear, znear,
zfar, zfar,
matrix,
inverse,
} }
} }
pub fn build_view_projection_matrix(eye: Point3<f32>, target: Point3<f32>, up: Vector3<f32>, aspect: f32, fovy: f32, znear: f32, zfar: f32) -> Matrix4<f32> { pub fn build_matrix_and_inverse(
eye: &Point3<f32>,
target: &Point3<f32>,
up: &Vector3<f32>,
aspect: f32,
fovy: f32,
znear: f32,
zfar: f32,
) -> (Matrix4<f32>, Matrix4<f32>) {
let view = Matrix4::look_at_lh(eye, target, up); let view = Matrix4::look_at_lh(eye, target, up);
let proj = Matrix4::new_perspective(aspect, fovy,znear, zfar); let proj = Perspective3::new(aspect, fovy, znear, zfar);
proj * view let matrix = proj.as_matrix() * view;
let inverse = view.try_inverse().expect("No view") * proj.inverse();
(matrix, inverse)
} }
pub fn build_inverse_view_projection_matrix(eye: Point3<f32>, target: Point3<f32>, up: Vector3<f32>, aspect: f32, fovy: f32, znear: f32, zfar: f32) -> Matrix4<f32> { pub fn cast_rays(&self, width: i32, height: i32) -> Vec<Ray> {
let view_proj = self.build_view_projection_matrix(eye, target, up, aspect, fovy, znear, zfar); let aspect = width as f64 / height as f64;
view_proj.try_inverse().expect("Cannot invert!") let fovy_radians = (self.fovy as f64).to_radians();
} let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan();
pub fn cast_rays(&self, width: u32, height: u32) -> Vec<Ray> { let view_direction = (self.target - self.eye).normalize(); // Normalize the view direction vector
let inverse_matrix = self.build_inverse_view_projection_matrix(); let hor = view_direction.cross(&self.up).normalize(); // pointing right
let vert = view_direction.cross(&hor).normalize(); // pointing up
let dx = 2.0 / width as f32; let h_width = 2.0 * (fovh_radians / 2.0).tan();
let dy = 2.0 / height as f32; let v_height = 2.0 * (fovy_radians / 2.0).tan();
let d_hor_vec = hor * (h_width / width as f64) as f32;
let d_vert_vec = vert * (v_height / height as f64) as f32;
let mut rays = Vec::with_capacity(width as usize * height as usize); let mut rays = Vec::with_capacity(width as usize * height as usize);
for i in 0..width { for j in 0..height {
for j in 0..height { for i in 0..width {
let x = -1.0 + i as f32 * dx; let horizontal = (i as f32 - width as f32 / 2.0) * d_hor_vec;
let y = 1.0 - j as f32 * dy; let vertical = (j as f32 - height as f32 / 2.0) * d_vert_vec;
let direction = view_direction + horizontal + vertical;
let a = inverse_matrix.transform_point(&Point3::new(x, y, -1.0)); let ray = Ray::new(self.eye, direction);
let b = inverse_matrix.transform_vector(&Vector3::new(0.0, 0.0, 1.0));
let ray = Ray { a, b };
rays.push(ray); rays.push(ray);
} }
} }
rays rays
} }
pub fn cast_ray(&self, width: u32, height: u32, x: u32, y: u32) -> Ray {
pub fn cast_ray(&self, width: i32, height: i32, x: i32, y: i32) -> Ray {
let aspect = width as f64 / height as f64;
let fovy_radians = (self.fovy as f64).to_radians();
let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan();
let view_direction = (self.target - self.eye).normalize(); // Normalize the view direction vector
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;
let hor = view_direction.cross(&self.up).normalize(); // pointing right
let vert = view_direction.cross(&hor).normalize(); // pointing up
let h_width = 2.0 * (fovh_radians / 2.0).tan();
let v_height = 2.0 * (fovy_radians / 2.0).tan();
let d_hor_vec = hor * (h_width / width as f64) as f32;
let d_vert_vec = vert * (v_height / height as f64) as f32;
// Calculate the offsets for the pixel's position on the image plane
let horizontal = ((x as f32 / width as f32) - 0.5) * h_width as f32;
let vertical = ((y as f32 / height as f32) - 0.5) * v_height as f32;
// Calculate the ray direction by summing up the components
let direction = view_direction + (horizontal * d_hor_vec) + (vertical * d_vert_vec);
Ray::new(self.eye, direction)
} }
} }

View File

@@ -9,6 +9,8 @@ pub(crate) struct Gui {
last_frame: Instant, last_frame: Instant,
last_cursor: Option<imgui::MouseCursor>, last_cursor: Option<imgui::MouseCursor>,
about_open: bool, about_open: bool,
pub num_rays: i32,
} }
impl Gui { impl Gui {
@@ -58,6 +60,7 @@ impl Gui {
last_frame: Instant::now(), last_frame: Instant::now(),
last_cursor: None, last_cursor: None,
about_open: true, about_open: true,
num_rays: 8,
} }
} }
@@ -93,17 +96,11 @@ impl Gui {
// Draw windows and GUI elements here // Draw windows and GUI elements here
let mut about_open = false; let mut about_open = false;
ui.main_menu_bar(|| { ui.main_menu_bar(|| {
ui.menu("Help", || { ui.menu("Options", || {
about_open = ui.menu_item("About..."); about_open = ui.menu_item("About...");
}); });
}); });
if about_open { ui.slider("Num rays", 1, 100, &mut self.num_rays);
self.about_open = true;
}
if self.about_open {
ui.show_about_window(&mut self.about_open);
}
// Render Dear ImGui with WGPU // Render Dear ImGui with WGPU
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {

View File

@@ -5,16 +5,13 @@
//Cameras //Cameras
use crate::camera::Camera; use crate::{camera::Camera, gui::Gui, light::Light, primitive::*, ray::Ray, scene::Scene};
use crate::gui::Gui; use log::error;
use crate::light::Light;
use crate::primitive::*;
use crate::scene::Scene;
use error_iter::ErrorIter as _; use error_iter::ErrorIter as _;
use log::error;
use nalgebra::{Point3, Vector3}; use nalgebra::{Point3, Vector3};
use pixels::{Error, Pixels, SurfaceTexture}; use pixels::{Error, Pixels, SurfaceTexture};
use std::env;
use std::sync::Arc; use std::sync::Arc;
use winit::dpi::LogicalSize; use winit::dpi::LogicalSize;
use winit::event::{Event, VirtualKeyCode}; use winit::event::{Event, VirtualKeyCode};
@@ -30,8 +27,8 @@ mod ray;
mod raytracer; mod raytracer;
mod scene; mod scene;
const START_WIDTH: u32 = 640; const START_WIDTH: i32 = 600;
const START_HEIGHT: u32 = 480; const START_HEIGHT: i32 = 555;
const BOX_SIZE: i16 = 64; const BOX_SIZE: i16 = 64;
const EPSILON: f32 = 1e-7; const EPSILON: f32 = 1e-7;
@@ -39,12 +36,16 @@ const INFINITY: f32 = 1e7;
struct State { struct State {
scene: Scene, scene: Scene,
width: u32, camera: Camera,
height: u32, rays: Vec<Ray>,
index: usize,
width: i32,
height: i32,
} }
fn main() -> Result<(), Error> { fn main() -> Result<(), Error> {
env_logger::init(); env_logger::init();
//Window
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let mut input = WinitInputHelper::new(); let mut input = WinitInputHelper::new();
let window = { let window = {
@@ -56,22 +57,56 @@ fn main() -> Result<(), Error> {
.build(&event_loop) .build(&event_loop)
.unwrap() .unwrap()
}; };
//Pixel surface
let mut pixels = { let mut pixels = {
let window_size = window.inner_size(); let window_size = window.inner_size();
let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window); let surface_texture = SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(START_WIDTH, START_HEIGHT, surface_texture)? Pixels::new(START_WIDTH as u32, START_HEIGHT as u32, surface_texture)?
}; };
let mut state = State::new(START_WIDTH, START_HEIGHT); //Camera
let eye = Point3::new(0.0, 0.0, 3.0);
let target = Point3::new(0.0, 0.0, 0.0);
let up = Vector3::new(0.0, 1.0, 0.0);
let arc_camera = Arc::new(Camera::new(
eye,
target,
up,
180.0,
(START_WIDTH as f32 / START_HEIGHT as f32) as f32,
));
let camera = Camera::new(
eye,
target,
up,
180.0,
(START_WIDTH as f32 / START_HEIGHT as f32) as f32,
);
let cameras: Vec<Arc<Camera>> = vec![arc_camera.clone()];
//Primitive
let arc_material = Arc::new(Material::magenta());
let mut primitives: Vec<Arc<dyn Primitive>> = Vec::new();
let arc_sphere = Arc::new(Sphere::unit(arc_material.clone()));
let arc_cone = Arc::new(Cone::unit(arc_material.clone()));
primitives.push(arc_sphere.clone());
primitives.push(arc_cone.clone());
//Lights
let light: Arc<Light>;
let light = Arc::new(Light::white());
let lights = vec![light];
let ambient_light = Arc::new(Vector3::new(1.0, 1.0, 0.0));
//State
let scene = Scene::new(primitives, lights, cameras, ambient_light);
let mut state = State::new(START_WIDTH, START_HEIGHT, scene, camera);
// Set up Dear ImGui // Set up Dear ImGui
let mut gui = Gui::new(&window, &pixels); let mut gui = Gui::new(&window, &pixels);
event_loop.run(move |event, _, control_flow| { event_loop.run(move |event, _, control_flow| {
// Draw the current frame // Draw the current frame
if let Event::RedrawRequested(_) = event { if let Event::RedrawRequested(_) = event {
for i in 0..gui.num_rays {
state.draw(pixels.frame_mut());
}
// Draw the world // Draw the world
state.draw(pixels.frame_mut());
// Prepare Dear ImGui // Prepare Dear ImGui
gui.prepare(&window).expect("gui.prepare() failed"); gui.prepare(&window).expect("gui.prepare() failed");
// Render everything together // Render everything together
@@ -80,6 +115,7 @@ fn main() -> Result<(), Error> {
context.scaling_renderer.render(encoder, render_target); context.scaling_renderer.render(encoder, render_target);
// Render Dear ImGui // Render Dear ImGui
gui.render(&window, encoder, render_target, context)?; gui.render(&window, encoder, render_target, context)?;
// *control_flow = ControlFlow::Exit;
Ok(()) Ok(())
}); });
// Basic error handling // Basic error handling
@@ -98,6 +134,7 @@ fn main() -> Result<(), Error> {
*control_flow = ControlFlow::Exit; *control_flow = ControlFlow::Exit;
return; return;
} }
if input.key_pressed(VirtualKeyCode::A) {}
// Resize the window // Resize the window
if let Some(size) = input.window_resized() { if let Some(size) = input.window_resized() {
if size.width > 0 && size.height > 0 { if size.width > 0 && size.height > 0 {
@@ -108,13 +145,7 @@ fn main() -> Result<(), Error> {
return; return;
} }
// Resize the world state.resize(size.width as i32, size.height as i32);
state.resize(size.width, size.height);
if let Err(err) = pixels.resize_buffer(size.width, size.height) {
log_error("pixels.resize_buffer", err);
*control_flow = ControlFlow::Exit;
return;
}
} }
} }
@@ -134,12 +165,16 @@ fn log_error<E: std::error::Error + 'static>(method_name: &str, err: E) {
impl State { impl State {
/// Create a new `World` instance that can draw a moving box. /// Create a new `World` instance that can draw a moving box.
fn new(width: u32, height: u32) -> Self { fn new(width: i32, height: i32, scene: Scene, camera: Camera) -> Self {
let scene = Scene::empty(); let index = 0;
let rays = camera.cast_rays(width, height);
Self { Self {
width, width,
height, height,
index,
rays,
scene, scene,
camera,
} }
} }
@@ -147,7 +182,7 @@ impl State {
fn update(&mut self) {} fn update(&mut self) {}
/// Resize the world /// Resize the world
fn resize(&mut self, width: u32, height: u32) { fn resize(&mut self, width: i32, height: i32) {
self.width = width; self.width = width;
self.height = height; self.height = height;
} }
@@ -155,61 +190,23 @@ impl State {
/// Draw the `World` state to the frame buffer. /// Draw the `World` state to the frame buffer.
/// ///
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb` /// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
fn draw(&self, frame: &mut [u8]) { fn draw(&mut self, frame: &mut [u8]) {
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() { let ray = &self.rays[self.index];
let x = (i % self.width as usize) as i16; let colour = raytracer::shade_ray(&self.scene, &ray);
let y = (i / self.width as usize) as i16; let pixel = &mut frame[self.index * 4..(self.index + 1) * 4]
.copy_from_slice(&[colour.x, colour.y, colour.z, 255]);
self.index += 1;
}
//Create our scene fn draw_all(&mut self, frame: &mut [u8]) {
let eye = Point3::new(0.0, 0.0, -1.0); let rays = self.camera.cast_rays(self.width, self.height);
let target = Point3::new(0.0, 0.0, 0.0); let colours = raytracer::shade_rays(&self.scene, &rays, self.width, self.height);
let up = Vector3::new(0.0, 1.0, 0.0); for (i, colour) in colours.iter().enumerate() {
let arc_camera = Arc::new(Camera::new( let colour = colours[i];
eye, // pixel[0] = colour.x;
target, // pixel[1] = colour.y;
up, // pixel[2] = colour.z;
90.0, // pixel[3] = 255;
(self.width / self.height) as f32,
));
let cameras: Vec<Arc<Camera>> = vec![arc_camera.clone()];
let arc_material = Arc::new(Material::magenta());
let arc_cone = Arc::new(Cone::unit(arc_material));
let primitives: Vec<Arc<dyn Primitive>> = vec![arc_cone]
.into_iter()
.map(|arc| arc as Arc<dyn Primitive>)
.collect();
let light: Arc<Light>;
let light = Arc::new(Light::white());
let lights = vec![light];
let ambient_light = Arc::new(Vector3::new(1.0, 1.0, 1.0));
let scene = Scene::new(primitives, lights, cameras, ambient_light);
let rays = arc_camera.as_ref().cast_rays(self.width, self.height);
let colours = raytracer::shade_rays(&scene, &rays, self.width, self.height);
println!("{}", colours.len());
//
// let pixels = pixels.frame().chunks_exact_mut(4);
// for (i, colour) in colours.iter().enumerate() {
// let colour = colours[i];
// let pixel = &mut pixels[i];
// pixel[0] = colour.x;
// pixel[1] = colour.y;
// pixel[2] = colour.z;
// }
//
// // Render the frame
// if pixels.render().is_err() {
// eprintln!("Failed to render frame");
// }
let rgba = [0x48, 0xb2, 0xe8, 0xff];
pixel.copy_from_slice(&rgba);
} }
} }
} }

View File

@@ -82,7 +82,7 @@ pub trait Primitive {
} }
// SPHERE ----------------------------------------------------------------- // SPHERE -----------------------------------------------------------------
struct Sphere { pub struct Sphere {
position: Point3<f32>, position: Point3<f32>,
radius: f32, radius: f32,
bounding_box: BoundingBox, bounding_box: BoundingBox,
@@ -103,7 +103,7 @@ impl Sphere {
} }
} }
fn unit(material: Arc<Material>) -> Self { pub fn unit(material: Arc<Material>) -> Self {
Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, material) Sphere::new(Point3::new(0.0, 0.0, 0.0), 1.0, material)
} }
} }
@@ -185,7 +185,7 @@ impl Circle {
} }
} }
fn unit(material: Arc<Material>) -> Self { pub 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;
@@ -413,7 +413,7 @@ impl Rectangle {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
} }
} }
fn unit(material: Arc<Material>) -> Self { pub 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),
@@ -466,7 +466,7 @@ impl Primitive for Rectangle {
} }
// BOX ----------------------------------------------------------------- // BOX -----------------------------------------------------------------
struct Box { pub struct Box {
width: f32, width: f32,
height: f32, height: f32,
depth: f32, depth: f32,
@@ -486,7 +486,7 @@ impl Box {
bounding_box: BoundingBox { bln, trf }, bounding_box: BoundingBox { bln, trf },
} }
} }
fn unit(material: Arc<Material>) -> Self { pub fn unit(material: Arc<Material>) -> Self {
Box::new(2.0, 2.0, 2.0, material) Box::new(2.0, 2.0, 2.0, material)
} }
} }
@@ -580,7 +580,7 @@ impl Triangle {
bounding_box, bounding_box,
} }
} }
fn unit(material: Arc<Material>) -> Self { pub 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);

View File

@@ -8,57 +8,59 @@ use crate::{
use std::sync::Arc; use std::sync::Arc;
use nalgebra::{distance, Matrix4, Point3, Vector3, Vector4}; use nalgebra::{distance, Matrix4, Point3, Vector3, Vector4};
static ZERO_VECTOR: Vector3<f32> = Vector3::new(0.0, 0.0, 0.0);
static ONE_VECTOR: Vector3<f32> = Vector3::new(1.0, 1.0, 1.0);
pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: u32, height: u32) -> Vec<Vector3<u8>> { pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: i32, height: i32) -> Vec<Vector3<u8>> {
let mut pixel_data = vec![]; let mut pixel_data = vec![Vector3::new(0, 0, 0); (width * height) as usize];
for ray in rays { for (pixel_index, ray) in rays.iter().enumerate() {
let intersect = get_closest_intersection(scene, ray); let intersect = get_closest_intersection(scene.primitives.clone(), ray);
match intersect { let colour = match intersect {
Some(interect) => { Some(intersect) => phong_shade_point(scene, &intersect),
let colour = phong_shade_point(scene, &interect);
pixel_data.push(colour);
}
None => { None => {
let colour = Vector3::new(0, 0, 0); // Handle rays that miss objects (e.g., use a background color or environment map)
pixel_data.push(colour); Vector3::new(0, 0, 0)
} }
} };
pixel_data[pixel_index] = colour;
} }
pixel_data pixel_data
} }
//Shade a single ray
pub fn shade_ray(scene: &Scene, ray: &Ray) -> Vector3<u8> {
let intersect = get_closest_intersection(scene.primitives.clone(), ray);
match intersect {
Some(intersect) => phong_shade_point(&scene, &intersect),
None => Vector3::new(0, 0, 0),
}
}
// Find the closest intersection, given a ray in world coordinates // Find the closest intersection, given a ray in world coordinates
pub fn get_closest_intersection(scene: &Scene, ray: &Ray) -> Option<Intersection> { pub fn get_closest_intersection(
primitives: Vec<Arc<dyn Primitive>>,
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 arc_primitive in &scene.primitives {
for arc_primitive in primitives {
let primitive = arc_primitive.clone(); let primitive = arc_primitive.clone();
if primitive.intersect_ray(ray).is_none() { if let Some(intersect) = primitive.intersect_ray(ray) {
continue; if intersect.distance < closest_distance {
}; closest_distance = intersect.distance;
closest_intersect = Some(intersect);
let intersect = primitive.intersect_ray(ray); }
if intersect.is_none() {
continue;
};
let intersect = intersect.unwrap();
if intersect.distance < closest_distance {
closest_distance = intersect.distance;
closest_intersect = Some(intersect);
} }
} }
closest_intersect closest_intersect
} }
// We want to shade a point placed in our scene // We want to shade a point placed in our scene
pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8> { 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 one_vector = Vector3::new(1.0, 1.0, 1.0);
//Unpack the intersection data //Unpack the intersection data
let Intersection { let Intersection {
point, point,
@@ -102,7 +104,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
let diffuse = if n_dot_l > 0.0 { let diffuse = if n_dot_l > 0.0 {
kd * n_dot_l kd * n_dot_l
} else { } else {
zero_vector ZERO_VECTOR
}; };
// Compute specular // Compute specular
@@ -111,7 +113,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
let specular = if n_dot_h > 0.0 { let specular = if n_dot_h > 0.0 {
ks * n_dot_h.powf(shininess) ks * n_dot_h.powf(shininess)
} else { } else {
zero_vector ZERO_VECTOR
}; };
colour += light_colour.component_mul(&((diffuse + specular) * falloff)); colour += light_colour.component_mul(&((diffuse + specular) * falloff));