use std::fmt::Debug; use anyhow::Result; use nalgebra::Vector3; use crate::image::Color; use crate::ray::Ray; use super::Scene; use super::illumination::IntersectionContext; pub trait ObjectKind: Debug + Send + Sync { /// Determine where the ray intersects this object, returning the earliest /// time this happens. Returns None if no intersection occurs. /// /// Also known as Trace_Ray in the slides, except not the part where it calls /// Shade_Ray. fn intersects_ray_at(&self, ray: &Ray) -> Result>; } /// An object in the scene #[derive(Debug)] pub struct Object { pub kind: Box, /// Index into the scene's material color list pub material: usize, } #[derive(Debug)] pub struct Rect { pub upper_left: Vector3, pub upper_right: Vector3, pub lower_left: Vector3, pub lower_right: Vector3, } #[derive(Debug)] pub struct Material { pub diffuse_color: Vector3, pub specular_color: Vector3, pub k_a: f64, pub k_d: f64, pub k_s: f64, pub exponent: f64, } #[derive(Debug)] pub enum LightKind { /// A point light source exists at a point and emits light in all directions Point { location: Vector3, }, Directional { direction: Vector3, }, } #[derive(Debug)] pub struct Light { pub kind: LightKind, pub color: Vector3, } #[derive(Debug, Default)] pub struct DepthCueing { color: Color, a_max: f64, a_min: f64, dist_max: f64, dist_min: f64, } impl Scene { /// Determine the boundaries of the viewing window in world coordinates pub fn compute_viewing_window(&self, distance: f64) -> Rect { // Compute viewing directions let u = self.view_dir.cross(&self.up_dir).normalize(); let v = u.cross(&self.view_dir).normalize(); // Compute dimensions of viewing window based on field of view let viewing_width = { // Divide the angle in 2 since we are trying to use trig rules so we must // get it from a right triangle let half_hfov = self.hfov.to_radians() / 2.0; // tan(hfov / 2) = w / 2d let w_over_2d = half_hfov.tan(); // To find the viewing width we must multiply by 2d now w_over_2d * 2.0 * distance }; let aspect_ratio = self.image_width as f64 / self.image_height as f64; let viewing_height = viewing_width / aspect_ratio; // Compute viewing window corners let n = self.view_dir.normalize(); #[rustfmt::skip] // Otherwise this line wraps over let view_window = Rect { upper_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) + v * (viewing_height / 2.0), upper_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) + v * (viewing_height / 2.0), lower_left: self.eye_pos + n * distance - u * (viewing_width / 2.0) - v * (viewing_height / 2.0), lower_right: self.eye_pos + n * distance + u * (viewing_width / 2.0) - v * (viewing_height / 2.0), }; view_window } }