From 137fb9f6d7f3c5ddd99ef7f0c369e108796d1ceb Mon Sep 17 00:00:00 2001 From: STP Date: Sat, 25 Nov 2023 03:15:59 -0500 Subject: [PATCH] Changed UI and integrated rays into camera --- scene.rhai | 64 ++++++++++++++++++- src/camera.rs | 160 +++++++++++++++++++++++++++++++---------------- src/gui.rs | 110 ++++++++++++++++++++------------ src/light.rs | 3 +- src/main.rs | 2 + src/primitive.rs | 55 ++++++++-------- src/ray.rs | 6 ++ src/raytracer.rs | 4 +- src/scene.rs | 19 +----- src/state.rs | 73 ++++++++++----------- 10 files changed, 313 insertions(+), 183 deletions(-) diff --git a/scene.rhai b/scene.rhai index 9376344..6d014dd 100644 --- a/scene.rhai +++ b/scene.rhai @@ -1,3 +1,65 @@ +// engine +// .register_type::>() +// .register_fn("V", Vector3::::new); +// engine +// .register_type::>() +// .register_fn("P", Point3::::new); +// engine +// .register_type::() +// .register_fn("Scene", Scene::empty) +// .register_fn("addNode", Scene::add_node) +// .register_fn("addLight", Scene::add_light); + +// engine +// .register_type::() +// .register_fn("Node", Node::new) +// .register_fn("translate", Node::translate) +// .register_fn("rotate", Node::rotate) +// .register_fn("scale", Node::scale); +// engine +// .register_type::() +// .register_fn("Camera", Camera::new); +// engine +// .register_type::() +// .register_fn("Light", Light::new); +// engine +// .register_type::() +// .register_fn("Material", Material::new) +// .register_fn("MaterialRed", Material::red) +// .register_fn("MaterialBlue", Material::blue) +// .register_fn("MaterialGreen", Material::green) +// .register_fn("MaterialMagenta", Material::magenta) +// .register_fn("MaterialTurquoise", Material::turquoise); +// engine +// .register_type::() +// .register_fn("Sphere", Sphere::new) +// .register_fn("SphereUnit", Sphere::unit); +// engine +// .register_type::() +// .register_fn("Cube", Cube::new) +// .register_fn("CubeUnit", Cube::unit); +// engine +// .register_type::() +// .register_fn("Cone", Cone::new) +// .register_fn("ConeUnit", Cone::unit); +// engine +// .register_type::() +// .register_fn("Cylinder", Cylinder::new); +// engine +// .register_type::() +// .register_fn("Circle", Circle::new) +// .register_fn("CircleUnit", Circle::unit); +// engine +// .register_type::() +// .register_fn("Rectangle", Rectangle::new) +// .register_fn("RectangleUnit", Rectangle::unit); +// engine +// .register_type::() +// .register_fn("Steiner", SteinerSurface::new); +// engine +// .register_type::() +// .register_fn("Torus", Torus::new); + let scene = Scene(); let eye = P(0.0, 0.0, 3.0); @@ -19,7 +81,7 @@ scene.addLight(light2); // let node = Node(sphere); // scene.addNode(node); -let stein = Stein(5.0,10.0, material); +let stein = Steiner(material); let node = Node(stein); scene.addNode(node); diff --git a/src/camera.rs b/src/camera.rs index a908fe6..531ca73 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -5,53 +5,76 @@ use nalgebra::{Matrix4, Perspective3, Point3, Unit, Vector3}; const ZNEAR: f32 = EPSILON; const ZFAR: f32 = INFINITY; +#[allow(dead_code)] #[derive(Clone)] pub struct Camera { eye: Point3, target: Point3, up: Vector3, fovy: f32, - aspect: f32, + width: u32, + height: u32, matrix: Matrix4, inverse: Matrix4, + pub rays: Vec, } +#[allow(dead_code)] impl Camera { pub fn new( eye: Point3, target: Point3, up: Vector3, + width: u32, + height: u32, fovy: f32, - aspect: f32, ) -> Self { - let (matrix, inverse) = Camera::build_matrix_and_inverse(&eye, &target, &up, fovy, aspect); + let (matrix, inverse) = build_matrix_and_inverse(&eye, &target, &up, width, height, fovy); + let rays = cast_rays(&eye, &target, &up, width, height, fovy); Camera { eye, target, up, + width, + height, fovy, matrix, inverse, - aspect, + rays, } } - pub fn build_matrix_and_inverse( - eye: &Point3, - target: &Point3, - up: &Vector3, - fovy: f32, - aspect: f32, - ) -> (Matrix4, Matrix4) { - let view = Matrix4::look_at_lh(eye, target, up); - 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 unit() -> Self { + 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); + Camera::new(eye, target, up, 1, 1, 90.0) } - pub fn cast_rays(&self, width: u32, height: u32) -> Vec { - let aspect = width as f64 / height as f64; + pub fn cast_rays(&self) -> Vec { + cast_rays( + &self.eye, + &self.target, + &self.up, + self.width, + self.height, + self.fovy, + ) + } + + pub fn build_matrix_and_inverse(&self) -> (Matrix4, Matrix4) { + build_matrix_and_inverse( + &self.eye, + &self.target, + &self.up, + self.width, + self.height, + self.fovy, + ) + } + + pub fn cast_ray(&self, x: u32, y: u32) -> Ray { + let aspect = self.width as f64 / self.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(); @@ -60,48 +83,16 @@ impl Camera { let h_width = 2.0 * (fovh_radians / 2.0).tan(); let v_height = 2.0 * (fovy_radians / 2.0).tan(); //All good - 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 d_hor_vec = hor * (h_width / self.width as f64) as f32; + let d_vert_vec = vert * (v_height / self.height as f64) as f32; - let mut rays = Vec::with_capacity(width as usize * height as usize); - - let half_w = width as i32 / 2; - let half_h = height as i32 / 2; - - for j in 0..height as i32 { - for i in 0..width as i32 { - let horizontal = (i - half_w) as f32 * (d_hor_vec); - let vertical = (-j + half_h) as f32 * (d_vert_vec); - - let direction = view_direction + horizontal + vertical; - let ray = Ray::new(self.eye, Unit::new_normalize(direction)); - rays.push(ray); - } - } - rays - } - - pub fn cast_ray(&self, width: u32, height: u32, x: u32, y: u32) -> 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(); - let hor = (view_direction.cross(&self.up)).normalize(); - let vert = (view_direction.cross(&hor)).normalize(); - let h_width = 2.0 * (fovh_radians / 2.0).tan(); - let v_height = 2.0 * (fovy_radians / 2.0).tan(); - //All good - 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 half_w = width as i32 / 2; - let half_h = height as i32 / 2; + let half_w = self.width as i32 / 2; + let half_h = self.height as i32 / 2; let horizontal = (x as i32 - half_w) as f32 * (d_hor_vec); let vertical = (-(y as i32) + half_h) as f32 * (d_vert_vec); let direction = view_direction + horizontal + vertical; - let ray = Ray::new(self.eye, Unit::new_normalize(direction)); Ray::new(self.eye, Unit::new_normalize(direction)) } @@ -109,4 +100,65 @@ impl Camera { pub fn set_position(&mut self, eye: Point3) { self.eye = eye; } + + pub fn set_size(&mut self, width: u32, height: u32) { + self.width = width; + self.height = height; + self.rays = self.cast_rays(); + (self.matrix, self.inverse) = self.build_matrix_and_inverse(); + } +} + +fn build_matrix_and_inverse( + eye: &Point3, + target: &Point3, + up: &Vector3, + width: u32, + height: u32, + fovy: f32, +) -> (Matrix4, Matrix4) { + let view = Matrix4::look_at_lh(eye, target, up); + let aspect = width as f32 / height as f32; + 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) +} + +fn cast_rays( + eye: &Point3, + target: &Point3, + up: &Vector3, + width: u32, + height: u32, + fovy: f32, +) -> Vec { + let aspect = width as f64 / height as f64; + let fovy_radians = (fovy as f64).to_radians(); + let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan(); + let view_direction = (target - eye).normalize(); + let hor = (view_direction.cross(&up)).normalize(); + let vert = (view_direction.cross(&hor)).normalize(); + let h_width = 2.0 * (fovh_radians / 2.0).tan() as f32; + let v_height = 2.0 * (fovy_radians / 2.0).tan() as f32; + //All good + let d_hor_vec = hor * (h_width / width as f32); + let d_vert_vec = vert * (v_height / height as f32); + + let mut rays = Vec::with_capacity(width as usize * height as usize); + + let half_w = width as i32 / 2; + let half_h = height as i32 / 2; + + for j in 0..height as i32 { + for i in 0..width as i32 { + let horizontal = (i - half_w) as f32 * (d_hor_vec); + let vertical = (-j + half_h) as f32 * (d_vert_vec); + + let direction = view_direction + horizontal + vertical; + let ray = Ray::new(eye.clone(), Unit::new_normalize(direction)); + rays.push(ray); + } + } + rays } diff --git a/src/gui.rs b/src/gui.rs index a79ae3b..4979225 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,9 +1,9 @@ -use nalgebra::Point3; +use crate::{camera::Camera, state::INIT_FILE, UP_VECTOR, ZERO_VECTOR}; +use imgui::*; +use nalgebra::{Point3, Vector3}; use pixels::{wgpu, PixelsContext}; use std::time::Instant; -const INIT_FILE: &str = "scene.rhai"; - const BUFFER_PROPORTION_INIT: f32 = 1.0; const BUFFER_PROPORTION_MIN: f32 = 0.5; const BUFFER_PROPORTION_MAX: f32 = 1.0; @@ -12,14 +12,14 @@ const RAYS_INIT: i32 = 9000; const RAYS_MIN: i32 = 100; const RAYS_MAX: i32 = 10000; -const CAMERA_MIN: f32 = -10.0; -const CAMERA_MAX: f32 = 10.0; +const CAMERA_MIN_FOV: f32 = 10.0; +const CAMERA_MAX_FOV: f32 = 160.0; const CAMERA_INIT: f32 = 5.0; /// Manages all state required for rendering Dear ImGui over `Pixels`test. pub enum GuiEvent { - BufferResize, - CameraRelocate, + BufferResize(f32), + CameraUpdate(Camera), SceneLoad(String), } @@ -32,10 +32,16 @@ pub struct Gui { pub event: Option, - pub filename: String, + script_filename: String, + script: String, pub ray_num: i32, - pub buffer_proportion: f32, - pub camera_eye: Point3, + + buffer_proportion: f32, + + camera_eye: [f32; 3], + camera_target: [f32; 3], + camera_up: [f32; 3], + camera_fov: f32, } impl Gui { @@ -85,10 +91,15 @@ impl Gui { last_frame: Instant::now(), last_cursor: None, event: None, - filename: String::from(INIT_FILE), + script_filename: String::from(INIT_FILE), + script: String::new(), ray_num: RAYS_INIT, buffer_proportion: BUFFER_PROPORTION_INIT, - camera_eye: Point3::new(CAMERA_INIT, CAMERA_INIT, CAMERA_INIT), + + camera_eye: [CAMERA_INIT, CAMERA_INIT, CAMERA_INIT], + camera_target: ZERO_VECTOR.into(), + camera_up: UP_VECTOR.into(), + camera_fov: 110.0, } } @@ -121,41 +132,62 @@ impl Gui { self.platform.prepare_render(ui, window); } - // Draw windows and GUI elements here + //Top Menu Bar let mut about_open = false; ui.main_menu_bar(|| { ui.menu("Help", || { about_open = ui.menu_item("About..."); }); }); - ui.slider("# Rays: ", RAYS_MIN, RAYS_MAX, &mut self.ray_num); - ui.slider( - "% Buffer: ", - BUFFER_PROPORTION_MIN, - BUFFER_PROPORTION_MAX, - &mut self.buffer_proportion, - ); - if ui.button("Change Buffer") { - self.event = Some(GuiEvent::BufferResize); - }; - - ui.text("Vector3 Input:"); - // Create three input fields for x, y, and z components - ui.slider("X", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[0]); - ui.slider("Y", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[1]); - ui.slider("Z", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[2]); - // Check if any component of the Vector3 has changed - if ui.button("Apply Camera") { - println!("Camera changed: {:?}", self.camera_eye); - self.camera_eye = Point3::from(self.camera_eye); - self.event = Some(GuiEvent::CameraRelocate); + //Raytracing options + if CollapsingHeader::new("Raytracer").build(ui) { + //Ray Renderer + ui.slider("# Rays: ", RAYS_MIN, RAYS_MAX, &mut self.ray_num); + //Buffer Options + ui.slider( + "% Buffer: ", + BUFFER_PROPORTION_MIN, + BUFFER_PROPORTION_MAX, + &mut self.buffer_proportion, + ); + //Apply changes + if ui.button("Apply") { + self.event = Some(GuiEvent::BufferResize(self.buffer_proportion)); + }; } - - //Load file from - ui.input_text("Scene file", &mut self.filename).build(); - if ui.button("Apply File") { - self.event = Some(GuiEvent::SceneLoad(self.filename.clone())); + //Camera options + if CollapsingHeader::new("Camera").build(ui) { + ui.text("Camera options:"); + ui.input_float3("Eye", &mut self.camera_eye).build(); + ui.input_float3("Target", &mut self.camera_target).build(); + ui.input_float3("Up", &mut self.camera_up).build(); + ui.slider("fov", CAMERA_MIN_FOV, CAMERA_MAX_FOV, &mut self.camera_fov); + // Create three input fields for x, y, and z components + if ui.button("Apply Camera") { + println!("Camera changed: {:?}", self.camera_eye); + let camera = Camera::new( + Point3::from_slice(&self.camera_eye), + Point3::from_slice(&self.camera_target), + Vector3::from_row_slice(&self.camera_up), + 1, + 1, + self.camera_fov, + ); + self.event = Some(GuiEvent::CameraUpdate(camera)); + } + } + //Scripting + if CollapsingHeader::new("Scripting").build(ui) { + //Import from file (We just want to replace the contents of self.script) + ui.input_text("Scene file", &mut self.script_filename) + .build(); + if ui.button("Import from File") { + self.event = Some(GuiEvent::SceneLoad(self.script_filename.clone())); + } + //Script block + ui.input_text_multiline("script", &mut self.script, [300., 100.]) + .build(); } // Render Dear ImGui with WGPU diff --git a/src/light.rs b/src/light.rs index 0d3894d..d0aaa1e 100644 --- a/src/light.rs +++ b/src/light.rs @@ -15,9 +15,8 @@ impl Light { falloff, } } - pub fn white() -> Self { + pub fn white(position: Point3) -> Self { let colour = Vector3::new(1.0, 1.0, 1.0); - let position = Point3::new(0.0, 0.0, 0.0); let falloff = Vector3::new(1.0, 0.0, 0.0); Light::new(position, colour, falloff) } diff --git a/src/main.rs b/src/main.rs index fc51192..458cd96 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ use error_iter::ErrorIter; const EPSILON: f32 = 1e-6; const INFINITY: f32 = f32::MAX; const EPSILON_VECTOR: Vector3 = Vector3::new(EPSILON, EPSILON, EPSILON); +static ZERO_VECTOR: Vector3 = Vector3::new(0.0, 0.0, 0.0); +static UP_VECTOR: Vector3 = Vector3::new(0.0, 1.0, 0.0); use log::error; use std::env; diff --git a/src/primitive.rs b/src/primitive.rs index e164e6e..3dc8325 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -1013,52 +1013,52 @@ impl Primitive for Torus { let d = ray.b.y; let e = ray.a.z; let f = ray.b.z; - let r = self.inner_rad; - let R = self.outer_rad; - let t0 = R.powf(2.0).powf(2.0) - 2.0 * R.powf(2.0) * a.powf(2.0) + a.powf(2.0).powf(2.0) - - 2.0 * R.powf(2.0) * c.powf(2.0) + let r1 = self.inner_rad; + let r2 = self.outer_rad; + let t0 = r2.powf(2.0).powf(2.0) - 2.0 * r2.powf(2.0) * a.powf(2.0) + a.powf(2.0).powf(2.0) + - 2.0 * r2.powf(2.0) * c.powf(2.0) + 2.0 * a.powf(2.0) * c.powf(2.0) + c.powf(2.0).powf(2.0) - + 2.0 * R.powf(2.0) * e.powf(2.0) + + 2.0 * r2.powf(2.0) * e.powf(2.0) + 2.0 * a.powf(2.0) * e.powf(2.0) + 2.0 * c.powf(2.0) * e.powf(2.0) + e.powf(2.0).powf(2.0) - - 2.0 * R.powf(2.0) * r.powf(2.0) - - 2.0 * a.powf(2.0) * r.powf(2.0) - - 2.0 * c.powf(2.0) * r.powf(2.0) - - 2.0 * e.powf(2.0) * r.powf(2.0) - + r.powf(2.0).powf(2.0); - let t1 = -4.0 * R.powf(2.0) * a * b + 4.0 * a.powf(3.0) * b + 4.0 * a * b * c.powf(2.0) - - 4.0 * R.powf(2.0) * c * d + - 2.0 * r2.powf(2.0) * r1.powf(2.0) + - 2.0 * a.powf(2.0) * r1.powf(2.0) + - 2.0 * c.powf(2.0) * r1.powf(2.0) + - 2.0 * e.powf(2.0) * r1.powf(2.0) + + r1.powf(2.0).powf(2.0); + let t1 = -4.0 * r2.powf(2.0) * a * b + 4.0 * a.powf(3.0) * b + 4.0 * a * b * c.powf(2.0) + - 4.0 * r2.powf(2.0) * c * d + 4.0 * a.powf(2.0) * c * d + 4.0 * c.powf(3.0) * d + 4.0 * a * b * e.powf(2.0) + 4.0 * c * d * e.powf(2.0) - + 4.0 * R.powf(2.0) * e * f + + 4.0 * r2.powf(2.0) * e * f + 4.0 * a.powf(2.0) * e * f + 4.0 * c.powf(2.0) * e * f + 4.0 * e.powf(3.0) * f - - 4.0 * a * b * r.powf(2.0) - - 4.0 * c * d * r.powf(2.0) - - 4.0 * e * f * r.powf(2.0); - let t2 = -2.0 * R.powf(2.0) * b.powf(2.0) + - 4.0 * a * b * r1.powf(2.0) + - 4.0 * c * d * r1.powf(2.0) + - 4.0 * e * f * r1.powf(2.0); + let t2 = -2.0 * r2.powf(2.0) * b.powf(2.0) + 6.0 * a.powf(2.0) * b.powf(2.0) + 2.0 * b.powf(2.0) * c.powf(2.0) + 8.0 * a * b * c * d - - 2.0 * R.powf(2.0) * d.powf(2.0) + - 2.0 * r2.powf(2.0) * d.powf(2.0) + 2.0 * a.powf(2.0) * d.powf(2.0) + 6.0 * c.powf(2.0) * d.powf(2.0) + 2.0 * b.powf(2.0) * e.powf(2.0) + 2.0 * d.powf(2.0) * e.powf(2.0) + 8.0 * a * b * e * f + 8.0 * c * d * e * f - + 2.0 * R.powf(2.0) * f.powf(2.0) + + 2.0 * r2.powf(2.0) * f.powf(2.0) + 2.0 * a.powf(2.0) * f.powf(2.0) + 2.0 * c.powf(2.0) * f.powf(2.0) + 6.0 * e.powf(2.0) * f.powf(2.0) - - 2.0 * b.powf(2.0) * r.powf(2.0) - - 2.0 * d.powf(2.0) * r.powf(2.0) - - 2.0 * f.powf(2.0) * r.powf(2.0); + - 2.0 * b.powf(2.0) * r1.powf(2.0) + - 2.0 * d.powf(2.0) * r1.powf(2.0) + - 2.0 * f.powf(2.0) * r1.powf(2.0); let t3 = 4.0 * a * b.powf(3.0) + 4.0 * b.powf(2.0) * c * d + 4.0 * a * b * d.powf(2.0) @@ -1091,11 +1091,12 @@ impl Primitive for Torus { //Now we have the smallest non-zero t let point = ray.at_t(t); let (x, y, z) = (point.x, point.y, point.z); - let dx = 4.0 * (R.powf(2.0) - r.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * R - - 8.0 * (x.powf(2.0) + y.powf(2.0)) * R; - let dy = -4.0 * (R.powf(2.0) - r.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r; - let dz = -8.0 * R.powf(2.0) * x - + 4.0 * (R.powf(2.0) - r.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * x; + let dx = 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r2 + - 8.0 * (x.powf(2.0) + y.powf(2.0)) * r2; + let dy = + -4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * r1; + let dz = -8.0 * r2.powf(2.0) * x + + 4.0 * (r2.powf(2.0) - r1.powf(2.0) + x.powf(2.0) + y.powf(2.0) + z.powf(2.0)) * x; let normal = Unit::new_normalize(Vector3::new(dx, dy, dz)); Some(Intersection { diff --git a/src/ray.rs b/src/ray.rs index f19ada0..84a1bc0 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -6,6 +6,7 @@ use crate::{ }; use nalgebra::{Point3, Unit, Vector3}; +#[derive(Clone)] pub struct Ray { pub a: Point3, pub b: Unit>, @@ -15,6 +16,11 @@ impl Ray { pub fn new(a: Point3, b: Unit>) -> Ray { Ray { a, b } } + pub fn unit() -> Ray { + let a = Point3::new(0.0, 0.0, 0.0); + let b = Unit::new_normalize(Vector3::new(0.0, 1.0, 0.0)); + Ray { a, b } + } pub fn at_t(&self, t: f32) -> Point3 { self.a + self.b.into_inner() * (t + EPSILON) } diff --git a/src/raytracer.rs b/src/raytracer.rs index 6db5a94..b88004f 100644 --- a/src/raytracer.rs +++ b/src/raytracer.rs @@ -1,9 +1,7 @@ -use crate::{light::Light, primitive::Intersection, scene::*}; +use crate::{light::Light, primitive::Intersection, scene::*, ZERO_VECTOR}; use nalgebra::{Unit, Vector3}; -static ZERO_VECTOR: Vector3 = Vector3::new(0.0, 0.0, 0.0); - // Function to shade a point in the scene using Phong shading model pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3 { let Intersection { diff --git a/src/scene.rs b/src/scene.rs index dce3c5a..258ce99 100644 --- a/src/scene.rs +++ b/src/scene.rs @@ -39,7 +39,6 @@ pub struct Scene { pub materials: Vec, pub lights: Vec, pub cameras: Vec, - pub camera: Camera, } impl Scene { @@ -50,13 +49,6 @@ impl Scene { materials: Vec::new(), lights: Vec::new(), cameras: Vec::new(), - camera: Camera::new( - Point3::new(0.0, 0.0, -10.0), - Point3::new(0.0, 0.0, 0.0), - Vector3::new(0.0, 0.0, -1.0), - 120.0, - 1.0, - ), } } fn add_node(&mut self, node: Node) { @@ -71,15 +63,8 @@ impl Scene { fn add_camera(&mut self, camera: Camera) { self.cameras.push(camera); } - fn set_camera(&mut self, camera: Camera) { - self.camera = camera; - } - fn get_camera(&self) -> &Camera { - &self.camera - } - - pub fn from_script(filename: &str) -> Result> { + pub fn from_rhai(script: &str) -> Result> { let mut engine = Engine::new(); engine @@ -144,7 +129,7 @@ impl Scene { .register_type::() .register_fn("Torus", Torus::new); - let scene: Scene = engine.eval_file(filename.into())?; + let scene: Scene = engine.eval(script.into())?; Ok(scene) } } diff --git a/src/state.rs b/src/state.rs index f05d472..7b66cec 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,7 @@ //Use linear algebra module -use crate::{gui::Gui, ray::Ray, scene::Scene}; +use crate::camera::Camera; +use crate::{gui::Gui, scene::Scene}; use crate::{gui::GuiEvent, log_error}; use std::error::Error; @@ -18,7 +19,7 @@ const START_WIDTH: i32 = 800; const START_HEIGHT: i32 = 800; const COLOUR_CLEAR: [u8; 4] = [0x22, 0x00, 0x11, 0xff]; -const INIT_FILE: &str = "test.rhai"; +pub const INIT_FILE: &str = "scene.rhai"; pub fn run() -> Result<(), Box> { let event_loop = EventLoop::new(); @@ -27,8 +28,7 @@ pub fn run() -> Result<(), Box> { let gui = Gui::new(&window, &pixels); let mut state = State::new(window, pixels, gui); - state.load_scene(&String::from(INIT_FILE)); - state.resize_buffer()?; + state.resize_buffer(1.0)?; event_loop.run(move |event, _, control_flow| { state.gui.handle_event(&state.window, &event); @@ -86,7 +86,7 @@ fn handle_window_event( pub struct State { scene: Scene, - rays: Vec, + camera: Camera, window: Window, buffer_width: u32, buffer_height: u32, @@ -96,29 +96,28 @@ pub struct State { } impl State { - pub fn update_scene_from_file(&mut self, filename: &String) -> Result<(), Box> { - self.scene = Scene::from_script(filename)?.into(); - let window_size = self.window.inner_size(); - self.rays = self - .scene - .camera - .cast_rays(window_size.width, window_size.height); + pub fn import_rhai_from_file(&mut self, filename: &str) -> Result<(), Box> { + let script = std::fs::read_to_string(filename)?; + self.scene = Scene::from_rhai(&script)?.into(); + Ok(()) + } + + pub fn import_rhai(&mut self, script: &str) -> Result<(), Box> { + self.scene = Scene::from_rhai(&script)?.into(); Ok(()) } pub fn new(window: Window, pixels: Pixels, gui: Gui) -> Self { let scene = Scene::empty(); let window_size = window.inner_size(); - let rays = scene - .camera - .cast_rays(window_size.width, window_size.height); + let camera = Camera::unit(); Self { scene, - rays, + camera, window, - buffer_width: (window_size.width as f32 * gui.buffer_proportion) as u32, - buffer_height: (window_size.height as f32 * gui.buffer_proportion) as u32, + buffer_width: window_size.width as u32, + buffer_height: window_size.height as u32, pixels: Arc::new(Mutex::new(pixels)), gui, index: 0, @@ -128,34 +127,27 @@ impl State { fn update(&mut self) -> Result<(), Box> { if let Some(event) = self.gui.event.take() { match event { - GuiEvent::BufferResize | GuiEvent::CameraRelocate => self.resize_buffer()?, - GuiEvent::SceneLoad(filename) => self.load_scene(&filename), + GuiEvent::BufferResize(proportion) => self.resize_buffer(proportion)?, + GuiEvent::CameraUpdate(camera) => self.set_camera(camera), + GuiEvent::SceneLoad(script) => self.import_rhai(&script)?, } }; Ok(()) } - fn resize_buffer(&mut self) -> Result<(), Box> { + fn resize_buffer(&mut self, proportion: f32) -> Result<(), Box> { let size = self.window.inner_size(); - self.buffer_width = (size.width as f32 * self.gui.buffer_proportion) as u32; - self.buffer_height = (size.height as f32 * self.gui.buffer_proportion) as u32; + + self.buffer_width = (size.width as f32 * proportion) as u32; + self.buffer_height = (size.height as f32 * proportion) as u32; + self.camera.set_size(self.buffer_width, self.buffer_height); + self.clear()?; let mut pixels = self.pixels.lock().unwrap(); pixels.resize_buffer(self.buffer_width, self.buffer_height)?; Ok(()) } - fn load_scene(&mut self, filename: &String) { - println!("Reading {}", filename); - match self.update_scene_from_file(filename) { - Err(e) => println!("{}", e), - Ok(()) => { - println!("Loaded file: {filename}"); - self.render().expect("Could not draw new file"); - } - } - } - fn resize(&mut self, size: &PhysicalSize) -> Result<(), Box> { let mut pixels = self.pixels.lock().unwrap(); pixels.resize_surface(size.width, size.height)?; @@ -175,7 +167,8 @@ impl State { fn draw(&mut self) -> Result<(), Box> { for _ in 0..self.gui.ray_num { let i = self.index as usize; - let colour = self.rays[i].shade_ray(&self.scene); + let camera = &self.camera; + let colour = camera.rays[i].shade_ray(&self.scene); let rgba = colour.map_or(COLOUR_CLEAR, |colour| [colour.x, colour.y, colour.z, 255]); let mut pixels = self.pixels.lock().unwrap(); let frame = pixels.frame_mut(); @@ -192,14 +185,14 @@ impl State { for pixel in frame.chunks_exact_mut(4) { pixel.copy_from_slice(&[0x00, 0x00, 0x00, 0xff]); } - self.scene.camera.set_position(self.gui.camera_eye); - self.rays = self - .scene - .camera - .cast_rays(self.buffer_width, self.buffer_height); Ok(()) } + fn set_camera(&mut self, camera: Camera) { + self.camera = camera; + self.camera.set_size(self.buffer_width, self.buffer_height); + } + fn render(&mut self) -> Result<(), Box> { self.update()?; //Update state self.draw()?; //Draw to pixels