summaryrefslogtreecommitdiff
path: root/src/camera.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/camera.rs')
-rw-r--r--src/camera.rs91
1 files changed, 91 insertions, 0 deletions
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