Working realtime tracing
This commit is contained in:
99
Cargo.lock
generated
99
Cargo.lock
generated
@@ -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"
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
src/gui.rs
13
src/gui.rs
@@ -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 {
|
||||||
|
|||||||
155
src/main.rs
155
src/main.rs
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
Reference in New Issue
Block a user