use cgmath::{ vec2, vec3, vec4, EuclideanSpace, InnerSpace, Matrix4, Point3, SquareMatrix, Vector2, Vector3, }; use super::view::View; use std::f32::consts::PI as M_PI; pub struct Ray { pub origin: Vector3, pub direction: Vector3, pub inv_direction: Vector3, pub signs: Vector3, } impl Ray { pub fn new(origin: Vector3, direction: Vector3) -> Ray { let inv_direction = 1.0 / direction; let x = (inv_direction.x < 0.0) as usize; let y = (inv_direction.y < 0.0) as usize; let z = (inv_direction.z < 0.0) as usize; Ray { origin, direction, inv_direction, signs: Vector3::new(x, y, z), } } pub fn primary_ray(x: f32, y: f32, dim_x: f32, dim_y: f32, view: &View) -> Ray { /* let aspect_ratio = dim_x / dim_y; let uv = vec2((x + 0.5) / dim_x, (y + 0.5) / dim_y); let (up, right) = view.axises(); let trans = 2.0 * uv - vec2(1.0, 1.0); let raw_dir = view.look_at + right * trans.x + up * trans.y; let dir = vec3( raw_dir.x * aspect_ratio, raw_dir.y, raw_dir.z * aspect_ratio, ) .normalize(); */ let aspect_ratio = dim_x / dim_y; let fov = view.fov / M_PI * 2.0 / 180.0; let p_x = (1.0 - 2.0 * ((x as f32 + 0.5) / dim_x as f32)) * fov * aspect_ratio; let p_y = (2.0 * (((y) as f32 + 0.5) / dim_y as f32) - 1.0) * fov; return Self::cast_ray(vec2(p_x, p_y), view); } pub fn cast_ray(uv: Vector2, view: &View) -> Ray { let look_at = Matrix4::look_at( Point3::from_vec(view.position), Point3::from_vec(view.look_at), vec3(0.0, 0.0, 1.0), ); let camera_to_world = look_at.invert().unwrap(); let origin = camera_to_world * vec4(0.0, 0.0, 0.0, 1.0); let direction = camera_to_world * vec4(uv.x, uv.y, -1.0, 1.0); Ray::new(origin.truncate(), -direction.truncate().normalize()) } #[inline] fn perspective(fov_y: f32, aspect: f32, z_near: f32, z_far: f32) -> cgmath::Matrix4 { let zero = 0.0; let one = 1.0; let two = 2.0; let q = one / (fov_y / two).tan(); let a = q / aspect; let b = (z_near + z_far) / (z_near - z_far); let c = (two * z_near * z_far) / (z_near - z_far); cgmath::Matrix4::new( a, zero, zero, zero, zero, -q, zero, zero, zero, zero, b, zero - one, zero, zero, c, zero, ) } } #[test] fn text_ray_casting() { let center = vec3(0.0, 0.0, 0.0); let view = View { position: vec3(0.0, -4.0, 4.0), look_at: center, up: vec3(0.0, 0.0, 1.0), fov: 45.0, }; }