Working realtime tracing
This commit is contained in:
99
Cargo.lock
generated
99
Cargo.lock
generated
@@ -657,12 +657,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.3"
|
||||
@@ -755,12 +749,6 @@ dependencies = [
|
||||
"hashbrown 0.14.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "2.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8"
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
@@ -907,15 +895,6 @@ dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.24.0"
|
||||
@@ -1078,7 +1057,7 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1091,7 +1070,7 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"memoffset 0.6.5",
|
||||
"memoffset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1297,67 +1276,6 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "quote"
|
||||
version = "1.0.33"
|
||||
@@ -1459,7 +1377,6 @@ dependencies = [
|
||||
"nalgebra",
|
||||
"pixels",
|
||||
"pollster",
|
||||
"pyo3",
|
||||
"roots",
|
||||
"winit",
|
||||
"winit_input_helper",
|
||||
@@ -1670,12 +1587,6 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.12.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c39fd04924ca3a864207c66fc2cd7d22d7c016007f9ce846cbb9326331930a"
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.4.0"
|
||||
@@ -1780,12 +1691,6 @@ version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
|
||||
@@ -12,7 +12,6 @@ pollster = "0.3"
|
||||
anyhow = "1.0"
|
||||
nalgebra = "0.32.3"
|
||||
roots = "0.0.8"
|
||||
pyo3 = "0.20.0"
|
||||
|
||||
imgui = "0.11"
|
||||
imgui-wgpu = "0.23"
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use crate::ray::Ray;
|
||||
use crate::{EPSILON, INFINITY};
|
||||
use log::error;
|
||||
use nalgebra as nm;
|
||||
use nalgebra::Matrix4;
|
||||
use nalgebra::Perspective3;
|
||||
use nalgebra::Point3;
|
||||
use nalgebra::Vector3;
|
||||
use std::env;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const OPENGL_TO_WGPU_MATRIX: Matrix4<f32> = Matrix4::new(
|
||||
@@ -35,8 +38,8 @@ impl Camera {
|
||||
) -> Self {
|
||||
let znear = EPSILON;
|
||||
let zfar = INFINITY;
|
||||
let matrix = self.build_view_projection_matrix(eye, target, up, aspect, fovy, znear, zfar);
|
||||
let inverse = self.build_inverse_view_projection_matrix(eye, target, up, aspect, fovy, znear, zfar);
|
||||
let (matrix, inverse) =
|
||||
Camera::build_matrix_and_inverse(&eye, &target, &up, aspect, fovy, znear, zfar);
|
||||
Camera {
|
||||
eye,
|
||||
target,
|
||||
@@ -45,42 +48,73 @@ impl Camera {
|
||||
aspect,
|
||||
znear,
|
||||
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 proj = Matrix4::new_perspective(aspect, fovy,znear, zfar);
|
||||
proj * view
|
||||
let proj = Perspective3::new(aspect, fovy, znear, zfar);
|
||||
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> {
|
||||
let view_proj = self.build_view_projection_matrix(eye, target, up, aspect, fovy, znear, zfar);
|
||||
view_proj.try_inverse().expect("Cannot invert!")
|
||||
}
|
||||
pub fn cast_rays(&self, width: u32, height: u32) -> Vec<Ray> {
|
||||
let inverse_matrix = self.build_inverse_view_projection_matrix();
|
||||
|
||||
let dx = 2.0 / width as f32;
|
||||
let dy = 2.0 / height as f32;
|
||||
pub fn cast_rays(&self, width: i32, height: i32) -> Vec<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 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;
|
||||
|
||||
let mut rays = Vec::with_capacity(width as usize * height as usize);
|
||||
|
||||
for i in 0..width {
|
||||
for j in 0..height {
|
||||
let x = -1.0 + i as f32 * dx;
|
||||
let y = 1.0 - j as f32 * dy;
|
||||
|
||||
let a = inverse_matrix.transform_point(&Point3::new(x, y, -1.0));
|
||||
let b = inverse_matrix.transform_vector(&Vector3::new(0.0, 0.0, 1.0));
|
||||
|
||||
let ray = Ray { a, b };
|
||||
for i in 0..width {
|
||||
let horizontal = (i as f32 - width as f32 / 2.0) * d_hor_vec;
|
||||
let vertical = (j as f32 - height as f32 / 2.0) * d_vert_vec;
|
||||
let direction = view_direction + horizontal + vertical;
|
||||
let ray = Ray::new(self.eye, direction);
|
||||
rays.push(ray);
|
||||
}
|
||||
}
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
|
||||
13
src/gui.rs
13
src/gui.rs
@@ -9,6 +9,8 @@ pub(crate) struct Gui {
|
||||
last_frame: Instant,
|
||||
last_cursor: Option<imgui::MouseCursor>,
|
||||
about_open: bool,
|
||||
|
||||
pub num_rays: i32,
|
||||
}
|
||||
|
||||
impl Gui {
|
||||
@@ -58,6 +60,7 @@ impl Gui {
|
||||
last_frame: Instant::now(),
|
||||
last_cursor: None,
|
||||
about_open: true,
|
||||
num_rays: 8,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,17 +96,11 @@ impl Gui {
|
||||
// Draw windows and GUI elements here
|
||||
let mut about_open = false;
|
||||
ui.main_menu_bar(|| {
|
||||
ui.menu("Help", || {
|
||||
ui.menu("Options", || {
|
||||
about_open = ui.menu_item("About...");
|
||||
});
|
||||
});
|
||||
if about_open {
|
||||
self.about_open = true;
|
||||
}
|
||||
|
||||
if self.about_open {
|
||||
ui.show_about_window(&mut self.about_open);
|
||||
}
|
||||
ui.slider("Num rays", 1, 100, &mut self.num_rays);
|
||||
|
||||
// Render Dear ImGui with WGPU
|
||||
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
|
||||
149
src/main.rs
149
src/main.rs
@@ -5,16 +5,13 @@
|
||||
|
||||
//Cameras
|
||||
|
||||
use crate::camera::Camera;
|
||||
use crate::gui::Gui;
|
||||
use crate::light::Light;
|
||||
use crate::primitive::*;
|
||||
use crate::scene::Scene;
|
||||
use crate::{camera::Camera, gui::Gui, light::Light, primitive::*, ray::Ray, scene::Scene};
|
||||
use log::error;
|
||||
|
||||
use error_iter::ErrorIter as _;
|
||||
use log::error;
|
||||
use nalgebra::{Point3, Vector3};
|
||||
use pixels::{Error, Pixels, SurfaceTexture};
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
use winit::dpi::LogicalSize;
|
||||
use winit::event::{Event, VirtualKeyCode};
|
||||
@@ -30,8 +27,8 @@ mod ray;
|
||||
mod raytracer;
|
||||
mod scene;
|
||||
|
||||
const START_WIDTH: u32 = 640;
|
||||
const START_HEIGHT: u32 = 480;
|
||||
const START_WIDTH: i32 = 600;
|
||||
const START_HEIGHT: i32 = 555;
|
||||
const BOX_SIZE: i16 = 64;
|
||||
|
||||
const EPSILON: f32 = 1e-7;
|
||||
@@ -39,12 +36,16 @@ const INFINITY: f32 = 1e7;
|
||||
|
||||
struct State {
|
||||
scene: Scene,
|
||||
width: u32,
|
||||
height: u32,
|
||||
camera: Camera,
|
||||
rays: Vec<Ray>,
|
||||
index: usize,
|
||||
width: i32,
|
||||
height: i32,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
env_logger::init();
|
||||
//Window
|
||||
let event_loop = EventLoop::new();
|
||||
let mut input = WinitInputHelper::new();
|
||||
let window = {
|
||||
@@ -56,22 +57,56 @@ fn main() -> Result<(), Error> {
|
||||
.build(&event_loop)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
//Pixel surface
|
||||
let mut pixels = {
|
||||
let window_size = window.inner_size();
|
||||
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
|
||||
let mut gui = Gui::new(&window, &pixels);
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Draw the current frame
|
||||
if let Event::RedrawRequested(_) = event {
|
||||
// Draw the world
|
||||
for i in 0..gui.num_rays {
|
||||
state.draw(pixels.frame_mut());
|
||||
}
|
||||
// Draw the world
|
||||
// Prepare Dear ImGui
|
||||
gui.prepare(&window).expect("gui.prepare() failed");
|
||||
// Render everything together
|
||||
@@ -80,6 +115,7 @@ fn main() -> Result<(), Error> {
|
||||
context.scaling_renderer.render(encoder, render_target);
|
||||
// Render Dear ImGui
|
||||
gui.render(&window, encoder, render_target, context)?;
|
||||
// *control_flow = ControlFlow::Exit;
|
||||
Ok(())
|
||||
});
|
||||
// Basic error handling
|
||||
@@ -98,6 +134,7 @@ fn main() -> Result<(), Error> {
|
||||
*control_flow = ControlFlow::Exit;
|
||||
return;
|
||||
}
|
||||
if input.key_pressed(VirtualKeyCode::A) {}
|
||||
// Resize the window
|
||||
if let Some(size) = input.window_resized() {
|
||||
if size.width > 0 && size.height > 0 {
|
||||
@@ -108,13 +145,7 @@ fn main() -> Result<(), Error> {
|
||||
return;
|
||||
}
|
||||
|
||||
// Resize the world
|
||||
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;
|
||||
}
|
||||
state.resize(size.width as i32, size.height as i32);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,12 +165,16 @@ fn log_error<E: std::error::Error + 'static>(method_name: &str, err: E) {
|
||||
|
||||
impl State {
|
||||
/// Create a new `World` instance that can draw a moving box.
|
||||
fn new(width: u32, height: u32) -> Self {
|
||||
let scene = Scene::empty();
|
||||
fn new(width: i32, height: i32, scene: Scene, camera: Camera) -> Self {
|
||||
let index = 0;
|
||||
let rays = camera.cast_rays(width, height);
|
||||
Self {
|
||||
width,
|
||||
height,
|
||||
index,
|
||||
rays,
|
||||
scene,
|
||||
camera,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,7 +182,7 @@ impl State {
|
||||
fn update(&mut self) {}
|
||||
|
||||
/// Resize the world
|
||||
fn resize(&mut self, width: u32, height: u32) {
|
||||
fn resize(&mut self, width: i32, height: i32) {
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
}
|
||||
@@ -155,61 +190,23 @@ impl State {
|
||||
/// Draw the `World` state to the frame buffer.
|
||||
///
|
||||
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
|
||||
fn draw(&self, frame: &mut [u8]) {
|
||||
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
|
||||
let x = (i % self.width as usize) as i16;
|
||||
let y = (i / self.width as usize) as i16;
|
||||
fn draw(&mut self, frame: &mut [u8]) {
|
||||
let ray = &self.rays[self.index];
|
||||
let colour = raytracer::shade_ray(&self.scene, &ray);
|
||||
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
|
||||
let eye = Point3::new(0.0, 0.0, -1.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,
|
||||
90.0,
|
||||
(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];
|
||||
fn draw_all(&mut self, frame: &mut [u8]) {
|
||||
let rays = self.camera.cast_rays(self.width, self.height);
|
||||
let colours = raytracer::shade_rays(&self.scene, &rays, self.width, self.height);
|
||||
for (i, colour) in colours.iter().enumerate() {
|
||||
let colour = colours[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);
|
||||
// pixel[3] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ pub trait Primitive {
|
||||
}
|
||||
|
||||
// SPHERE -----------------------------------------------------------------
|
||||
struct Sphere {
|
||||
pub struct Sphere {
|
||||
position: Point3<f32>,
|
||||
radius: f32,
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -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 normal = Vector3::new(0.0, 1.0, 0.0);
|
||||
let radius = 1.0;
|
||||
@@ -413,7 +413,7 @@ impl Rectangle {
|
||||
bounding_box: BoundingBox { bln, trf },
|
||||
}
|
||||
}
|
||||
fn unit(material: Arc<Material>) -> Self {
|
||||
pub fn unit(material: Arc<Material>) -> Self {
|
||||
Rectangle::new(
|
||||
Point3::new(0.0, 0.0, 0.0),
|
||||
Vector3::new(0.0, 1.0, 0.0),
|
||||
@@ -466,7 +466,7 @@ impl Primitive for Rectangle {
|
||||
}
|
||||
|
||||
// BOX -----------------------------------------------------------------
|
||||
struct Box {
|
||||
pub struct Box {
|
||||
width: f32,
|
||||
height: f32,
|
||||
depth: f32,
|
||||
@@ -486,7 +486,7 @@ impl Box {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -580,7 +580,7 @@ impl Triangle {
|
||||
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 v = Point3::new(0.0, 0.0, 1.0);
|
||||
let w = Point3::new(1.0, 0.0, -1.0);
|
||||
|
||||
@@ -8,57 +8,59 @@ use crate::{
|
||||
use std::sync::Arc;
|
||||
|
||||
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>> {
|
||||
let mut pixel_data = vec![];
|
||||
pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: i32, height: i32) -> Vec<Vector3<u8>> {
|
||||
let mut pixel_data = vec![Vector3::new(0, 0, 0); (width * height) as usize];
|
||||
|
||||
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);
|
||||
}
|
||||
for (pixel_index, ray) in rays.iter().enumerate() {
|
||||
let intersect = get_closest_intersection(scene.primitives.clone(), ray);
|
||||
let colour = match intersect {
|
||||
Some(intersect) => phong_shade_point(scene, &intersect),
|
||||
None => {
|
||||
let colour = Vector3::new(0, 0, 0);
|
||||
pixel_data.push(colour);
|
||||
// Handle rays that miss objects (e.g., use a background color or environment map)
|
||||
Vector3::new(0, 0, 0)
|
||||
}
|
||||
};
|
||||
pixel_data[pixel_index] = colour;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
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_intersect: Option<Intersection> = None;
|
||||
for arc_primitive in &scene.primitives {
|
||||
|
||||
for arc_primitive in primitives {
|
||||
let primitive = arc_primitive.clone();
|
||||
|
||||
if primitive.intersect_ray(ray).is_none() {
|
||||
continue;
|
||||
};
|
||||
|
||||
let intersect = primitive.intersect_ray(ray);
|
||||
if intersect.is_none() {
|
||||
continue;
|
||||
};
|
||||
|
||||
let intersect = intersect.unwrap();
|
||||
if let Some(intersect) = primitive.intersect_ray(ray) {
|
||||
if intersect.distance < closest_distance {
|
||||
closest_distance = intersect.distance;
|
||||
closest_intersect = Some(intersect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closest_intersect
|
||||
}
|
||||
|
||||
// We want to shade a point placed in our scene
|
||||
pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8> {
|
||||
//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
|
||||
let Intersection {
|
||||
point,
|
||||
@@ -102,7 +104,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3<u8>
|
||||
let diffuse = if n_dot_l > 0.0 {
|
||||
kd * n_dot_l
|
||||
} else {
|
||||
zero_vector
|
||||
ZERO_VECTOR
|
||||
};
|
||||
|
||||
// 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 {
|
||||
ks * n_dot_h.powf(shininess)
|
||||
} else {
|
||||
zero_vector
|
||||
ZERO_VECTOR
|
||||
};
|
||||
|
||||
colour += light_colour.component_mul(&((diffuse + specular) * falloff));
|
||||
|
||||
Reference in New Issue
Block a user