diff --git a/src/camera.rs b/src/camera.rs index 366de59..75d2db1 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -69,10 +69,10 @@ impl Camera { pub fn cast_rays(&self, width: u32, height: u32) -> Vec { //All good let aspect = width as f64 / height as f64; - let fovy_radians = self.fovy as f64; + let fovy_radians = (self.fovy as f64).to_radians(); let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan(); // All good - let view_direction = self.target - self.eye; + let view_direction = (self.target - self.eye).normalize(); //All good let hor = view_direction.cross(&self.up).normalize(); // pointing right let vert = view_direction.cross(&hor).normalize(); // pointing up @@ -123,4 +123,8 @@ impl Camera { Ray::new(self.eye, direction) } + + pub fn set_position(&mut self, eye: Point3) { + self.eye = eye; + } } diff --git a/src/gui.rs b/src/gui.rs index dc8e1fa..cb452cc 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -1,3 +1,4 @@ +use nalgebra::Point3; use pixels::{wgpu, PixelsContext}; use std::time::Instant; @@ -5,10 +6,14 @@ const BUFFER_PROPORTION_INIT: f32 = 0.8; const BUFFER_PROPORTION_MIN: f32 = 0.5; const BUFFER_PROPORTION_MAX: f32 = 0.9; -const RAYS_INIT: i32 = 100; +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_INIT: f32 = 5.0; + /// Manages all state required for rendering Dear ImGui over `Pixels`. pub(crate) struct Gui { imgui: imgui::Context, @@ -19,8 +24,12 @@ pub(crate) struct Gui { about_open: bool, pub ray_num: i32, + pub buffer_proportion: f32, pub buffer_resize: bool, + + pub camera_eye: Point3, + pub camera_reposition: bool, } impl Gui { @@ -73,6 +82,8 @@ impl Gui { ray_num: RAYS_INIT, buffer_proportion: BUFFER_PROPORTION_INIT, buffer_resize: false, + camera_eye: Point3::new(CAMERA_INIT, CAMERA_INIT, CAMERA_INIT), + camera_reposition: false, } } @@ -126,6 +137,20 @@ impl Gui { }; self.buffer_resize = buffer_resize; + let mut camera_reposition = false; + 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") { + println!("Camera changed: {:?}", self.camera_eye); + self.camera_eye = Point3::from(self.camera_eye); + camera_reposition = true; + } + self.camera_reposition = camera_reposition; + // Render Dear ImGui with WGPU let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("imgui"), diff --git a/src/main.rs b/src/main.rs index 13e6cfc..033c3bf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -80,7 +80,7 @@ impl State { /// Update the `World` internal state; bounce the box around the screen. fn update(&mut self) -> bool { - if self.gui.buffer_resize { + if self.gui.buffer_resize || self.gui.camera_reposition { let pixels = &self.pixels; let size = self.window.inner_size(); let width_new = (size.width as f32 * self.gui.buffer_proportion) as u32; @@ -92,6 +92,7 @@ impl State { return false; } self.index = 0; + self.camera.set_position(self.gui.camera_eye); self.rays = Arc::new(self.camera.cast_rays(width_new, height_new)); } true @@ -204,38 +205,33 @@ fn main() -> Result<(), Error> { let event_loop = EventLoop::new(); //SCENE //Camera - let eye = Point3::new(100.0, 100.0, 100.0); + let eye = Point3::new(10.0, 0.0, 10.0); let target = Point3::new(0.0, 0.0, 0.0); let up = Vector3::new(0.0, 1.0, 0.0); let camera = Camera::new( eye, target, up, - 70.0, + 90.0, (START_WIDTH as f32 / START_HEIGHT as f32) as f32, ); - // SETUP PRIMITIVES + // SETUP MATERIALS let magenta = Arc::new(Material::magenta()); let blue = Arc::new(Material::blue()); let turquoise = Arc::new(Material::turquoise()); let red = Arc::new(Material::red()); - // let sphere = Arc::new(Sphere::unit(magenta.clone())); - // primitives.push(sphere.clone()); - // let cone = Arc::new(Cone::new(0.25, 1.0, -0.5, turquoise.clone())); - // primitives.push(cone.clone()); + // SETUP PRIMITIVES let mut primitives: Vec> = Vec::new(); - let cube = Box::new(Cube::unit(turquoise.clone())); - let sphere = Box::new(Sphere::new(Point3::new(0.0, 4.0, 0.0), 1.0, red.clone())); - let cone = Box::new(Circle::new( - Point3::new(0.0, -3.0, 0.0), - 2.0, - Vector3::new(0.0, 1.0, 0.0), - magenta.clone(), - )); - primitives.push(cube); + //let cube = Box::new(Cube::unit(turquoise.clone())); + // primitives.push(cube); + let sphere = Box::new(Sphere::new(Point3::new(0.0, -2.0, 0.0), 1.0, red.clone())); + let sphere2 = Box::new(Sphere::new(Point3::new(0.0, 2.0, 0.0), 1.0, red.clone())); + let cone = Box::new(Cone::new(1.0, 1.0, -1.0, magenta.clone())); primitives.push(sphere); + primitives.push(sphere2); primitives.push(cone); - //Lights + + // SETUP LIGHTS let light_pos = Point3::new(0.0, 12.0, 4.0); let light_colour = Vector3::new(0.4, 0.4, 0.6); let light_falloff = [1.0, 0.00, 0.00]; diff --git a/src/primitive.rs b/src/primitive.rs index d29d5ec..3b5a7ec 100644 --- a/src/primitive.rs +++ b/src/primitive.rs @@ -244,7 +244,7 @@ impl Primitive for Circle { }; let intersect = ray.at_t(t); let distance = distance(&intersect, &self.position); - match distance > self.radius { + match distance >= self.radius { true => return None, false => { return Some(Intersection { @@ -297,14 +297,14 @@ impl Primitive for Cylinder { pub struct Cone { radius: f32, base: f32, - height: f32, + apex: f32, circle: Circle, material: Arc, bounding_box: BoundingBox, } impl Cone { - pub fn new(radius: f32, height: f32, base: f32, material: Arc) -> Self { + pub fn new(radius: f32, apex: f32, base: f32, material: Arc) -> Self { let circle = Circle::new( Point3::new(0.0, base, 0.0), radius, @@ -312,11 +312,11 @@ impl Cone { Arc::clone(&material), ); let bln = Point3::new(-radius, base, -radius); - let trf = Point3::new(radius, base + height, radius); + let trf = Point3::new(radius, base + apex, radius); Cone { - radius, + radius: radius / 2.0, base, - height, + apex, circle, material, bounding_box: BoundingBox { bln, trf }, @@ -328,7 +328,7 @@ impl Cone { pub fn get_normal(&self, intersect: Point3) -> Vector3 { let r = self.radius; - let h = self.height; + let h = self.apex; let (x, y, z) = (intersect.x, intersect.y, intersect.z); let normal = Vector3::new(2.0 * x, 2.0 * r * r * (h - y), 2.0 * z).normalize(); normal @@ -339,7 +339,7 @@ impl Primitive for Cone { fn intersect_ray(&self, ray: &Ray) -> Option { let point = &ray.a; let dir = &ray.b; - let (r, h) = (self.radius, self.height); + let (r, h) = (self.radius, self.apex); let (a1, a2, a3) = (point.x, point.y, point.z); let (b1, b2, b3) = (dir.x, dir.y, dir.z); let r2 = r * r; @@ -368,7 +368,7 @@ impl Primitive for Cone { None => None, Some(t) => { let intersect = ray.at_t(t); - match intersect.y >= self.base && intersect.y <= self.height { + match intersect.y >= self.base && intersect.y <= self.apex { true => Some(Intersection { point: intersect, normal: Unit::new_normalize(self.get_normal(intersect)),