From 6d332199e159ccfe3c2f7edd5762eebe74c024fa Mon Sep 17 00:00:00 2001 From: STP Date: Mon, 20 Nov 2023 20:19:38 -0500 Subject: [PATCH] Moved ray intersection code into ray class --- src/ray.rs | 34 +++++++++++++++++++++++++++- src/raytracer.rs | 58 ++++++------------------------------------------ src/state.rs | 10 ++++----- 3 files changed, 44 insertions(+), 58 deletions(-) diff --git a/src/ray.rs b/src/ray.rs index bfa1a8b..f19ada0 100644 --- a/src/ray.rs +++ b/src/ray.rs @@ -1,4 +1,9 @@ -use crate::EPSILON; +use crate::{ + primitive::Intersection, + raytracer::phong_shade_point, + scene::{Node, Scene}, + EPSILON, INFINITY, +}; use nalgebra::{Point3, Unit, Vector3}; pub struct Ray { @@ -13,4 +18,31 @@ impl Ray { pub fn at_t(&self, t: f32) -> Point3 { self.a + self.b.into_inner() * (t + EPSILON) } + //Shade a single ray + pub fn shade_ray(&self, scene: &Scene) -> Option> { + let intersect = self.get_closest_intersection(&scene.nodes); + match intersect { + Some(intersect) => Some(phong_shade_point(&scene, &intersect)), + None => None, + } + } + + // Find the closest intersection, given a ray in world coordinates + pub fn get_closest_intersection(&self, nodes: &Vec) -> Option { + let mut closest_distance = INFINITY; + let mut closest_intersect: Option = None; + + for node in nodes { + let primitive = node.primitive.clone(); + + if let Some(intersect) = primitive.intersect_ray(self) { + if intersect.distance < closest_distance { + closest_distance = intersect.distance; + closest_intersect = Some(intersect); + } + } + } + + closest_intersect + } } diff --git a/src/raytracer.rs b/src/raytracer.rs index a84cd44..0d42f4a 100644 --- a/src/raytracer.rs +++ b/src/raytracer.rs @@ -1,57 +1,11 @@ -use crate::{light::Light, primitive::Intersection, ray::Ray, scene::*, INFINITY}; +use crate::{light::Light, primitive::Intersection, scene::*}; use nalgebra::{Unit, Vector3}; static ZERO_VECTOR: Vector3 = Vector3::new(0.0, 0.0, 0.0); -pub fn shade_rays(scene: &Scene, rays: &Vec, width: i32, height: i32) -> Vec> { - let mut pixel_data = vec![Vector3::new(0, 0, 0); (width * height) as usize]; - - for (pixel_index, ray) in rays.iter().enumerate() { - let intersect = get_closest_intersection(&scene.nodes, ray); - let colour = match intersect { - Some(intersect) => phong_shade_point(scene, &intersect), - None => { - // 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) -> Option> { - let intersect = get_closest_intersection(&scene.nodes, ray); - match intersect { - Some(intersect) => Some(phong_shade_point(&scene, &intersect)), - None => None, - } -} - -// Find the closest intersection, given a ray in world coordinates -pub fn get_closest_intersection(nodes: &Vec, ray: &Ray) -> Option { - let mut closest_distance = INFINITY; - let mut closest_intersect: Option = None; - - for node in nodes { - let primitive = node.primitive.clone(); - - 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 +// Function to shade a point in the scene using Phong shading model pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3 { - //Useful vectors !!!! CHECK IF WE CAN OPTIMISE - //Unpack the intersection data let Intersection { point, normal, @@ -63,9 +17,8 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3 let kd = material.kd; let ks = material.ks; let shininess = material.shininess; - // We should now have all the information for our ray-tracer - // Let us first compute the ambient light component and set it as out base colour + // Compute the ambient light component and set it as base colour let mut colour = kd.component_mul(ambient_light); for light in &scene.lights { @@ -75,7 +28,7 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3 falloff: light_falloff, } = light; - // Get light incidence vector + // Compute light incidence vector and its distance let to_light = light_position - point; let light_distance = to_light.norm(); let light_incidence = Unit::new_normalize(to_light); @@ -103,8 +56,11 @@ pub fn phong_shade_point(scene: &Scene, intersect: &Intersection) -> Vector3 ZERO_VECTOR }; + // Update colour with diffuse and specular components colour += light_colour.component_mul(&((diffuse + specular) * falloff)); } + + // Clamp colour values to [0, 255] and convert to u8 let r = nalgebra::clamp(colour.x * 255.0, 0.0, 255.0) as u8; let g = nalgebra::clamp(colour.y * 255.0, 0.0, 255.0) as u8; let b = nalgebra::clamp(colour.z * 255.0, 0.0, 255.0) as u8; diff --git a/src/state.rs b/src/state.rs index 2e77ef4..ef42315 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,6 +1,6 @@ //Use linear algebra module -use crate::raytracer; +use crate::raytracer::*; use crate::{gui::Gui, ray::Ray, scene::Scene}; use crate::{gui::GuiEvent, log_error}; @@ -8,7 +8,7 @@ use std::error::Error; use std::sync::{Arc, Mutex}; -use pixels::{Pixels, SurfaceTexture}; +use pixels::{Pixels, SurfaceTexture, TextureError}; use winit::dpi::{LogicalSize, PhysicalSize}; use winit::event::{Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent}; use winit::event_loop::{ControlFlow, EventLoop}; @@ -139,11 +139,9 @@ impl State { self.clear(); } - fn resize(&mut self, size: &PhysicalSize) -> Result<(), Box> { + fn resize(&mut self, size: &PhysicalSize) -> Result<(), TextureError> { let mut pixels = self.pixels.lock().unwrap(); - pixels - .resize_surface(size.width, size.height) - .map_err(Box::new) + pixels.resize_surface(size.width, size.height) } fn keyboard_input(&mut self, key: &KeyboardInput) {