From 5fb34460b02b2b151dd775e43675bd4f09d2633a Mon Sep 17 00:00:00 2001 From: Rosyid Haryadi Date: Sat, 1 Mar 2025 23:07:43 +0700 Subject: refactor camera --- src/camera.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 src/camera.rs (limited to 'src/camera.rs') diff --git a/src/camera.rs b/src/camera.rs new file mode 100644 index 0000000..587a312 --- /dev/null +++ b/src/camera.rs @@ -0,0 +1,91 @@ +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); + }) + }) + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2