use crate::calculus::calculus::{Point3, Ray, Vec3}; use crate::global::{get_image_height, Color, DisplayBuffer, Pixel, ASPECT_RATIO, CAMERA_CENTER, FOCAL_LENGTH, IMG_WIDTH, VIEWPORT_HEIGHT}; use crate::interval::Interval; use crate::object::{HitRecord, Hittable, HittableList, Sphere}; pub struct Camera { pub aspect_ratio: f32, pub image_width: usize, image_height: usize, center: Point3, pixel_upper_left: Point3, delta_pixel_u: Vec3, delta_pixel_v: Vec3, } impl Camera { pub fn new() -> Self { let aspect_ratio = ASPECT_RATIO; let image_width = IMG_WIDTH; let image_height = get_image_height(image_width, aspect_ratio); let center = CAMERA_CENTER; let focal_length = FOCAL_LENGTH; let viewport_height = VIEWPORT_HEIGHT; let viewport_width = viewport_height * (image_width as f32 / image_height as f32); let viewport_hor_vector = Vec3{ x: viewport_width, y: 0.0, z: 0.0 }; let viewport_ver_vector = Vec3 { x: 0.0, y: -1f32 * viewport_height, z: 0.0 }; let delta_pixel_u = viewport_hor_vector.scalar_mul(1.0 / image_width as f32); let delta_pixel_v = viewport_ver_vector.scalar_mul(1.0 / image_height as f32); let viewport_upper_left = center .sub(&Vec3 { x: 0f32, y: 0f32, z: focal_length}) .sub(&viewport_hor_vector.scalar_mul(0.5)) .sub(&viewport_ver_vector.scalar_mul(0.5)); let pixel_upper_left = viewport_upper_left.add( &delta_pixel_u.add(&delta_pixel_u).scalar_mul(0.5) ); Self { aspect_ratio, image_width, image_height, center, pixel_upper_left, delta_pixel_u, delta_pixel_v, } } fn ray_color(&self, ray: &Ray, world: &HittableList) -> Color { let mut rec = HitRecord::default(); let ray_t = Interval::new(0.0, f32::INFINITY); if world.hit(ray, ray_t, &mut rec) { let color = Color::new(1.0, 1.0, 1.0) .add(&Color::new( rec.normal.x, rec.normal.y, rec.normal.z) ) .mul_scalar(0.5); return color; } let unit_direction = ray.direction.unit(); let a = 0.5 * (unit_direction.y + 1.0); let color1 = Color::new(1.0, 1.0, 1.0).mul_scalar(1.0 - a); let color2 = Color::new(0.5, 0.7, 1.0).mul_scalar(a); color1.add(&color2) } pub fn render(&self, display_buffer: &mut DisplayBuffer, world: &HittableList) { (0..self.image_height).for_each(|j| { (0..self.image_width).for_each(|i| { let pixel_center = self.pixel_upper_left .add(&self.delta_pixel_u.scalar_mul(i as f32)) .add(&self.delta_pixel_v.scalar_mul(j as f32)); let ray_direction = pixel_center.sub(&self.center); let ray = Ray { origin: &self.center, direction: &ray_direction, }; let color = self.ray_color(&ray, &world); display_buffer[j][i] = Pixel::from_color(&color); }) }) } }