summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-01 23:07:43 +0700
committerRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-01 23:07:43 +0700
commit5fb34460b02b2b151dd775e43675bd4f09d2633a (patch)
treea596b722257e7c376255ba4a3372f4cabe7a370c
parentfb30b41fb1f4ebbe5274d2cb93e98a1f2bec445f (diff)
refactor camera
-rw-r--r--src/camera.rs91
-rw-r--r--src/global.rs69
-rw-r--r--src/main.rs19
-rw-r--r--src/renderer.rs67
4 files changed, 143 insertions, 103 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
diff --git a/src/global.rs b/src/global.rs
index 9357920..fc9e0c9 100644
--- a/src/global.rs
+++ b/src/global.rs
@@ -1,18 +1,48 @@
use crate::calculus::calculus::Point3;
-
-
// "Ideal" aspect ratio, allowing fraction
pub const ASPECT_RATIO: f32 = 16.0f32 / 9.0f32;
-pub const IMG_WIDTH: usize = 400;
-const IMG_HEIGHT_TMP: usize = (IMG_WIDTH as f32 / ASPECT_RATIO) as usize;
-pub const IMG_HEIGHT: usize = if (IMG_HEIGHT_TMP < 1) { 1 } else { IMG_HEIGHT_TMP };
+pub const IMG_WIDTH: usize = 1000;
+pub const IMG_HEIGHT: usize = get_image_height(IMG_WIDTH, ASPECT_RATIO);
pub const VIEWPORT_HEIGHT: f32 = 2.0;
-pub const VIEWPORT_WIDTH: f32 = VIEWPORT_HEIGHT * (IMG_WIDTH as f32 / IMG_HEIGHT as f32);
pub const FOCAL_LENGTH: f32 = 1.0;
pub const CAMERA_CENTER: Point3 = Point3 { x: 0f32, y: 0f32, z: 0f32 };
+pub const fn get_image_height(image_width: usize, aspect_ratio: f32) -> usize {
+ let image_height = (image_width as f32 / aspect_ratio) as usize;
+ if image_width < 1 { 1 } else { image_height }
+}
+
+pub struct Color {
+ pub r: f32,
+ pub g: f32,
+ pub b: f32,
+}
+
+impl Color {
+ pub fn new(r: f32, g: f32, b: f32) -> Self {
+ Self { r, g, b }
+ }
+
+ pub fn mul_scalar(&self, scalar: f32) -> Color {
+ Self {
+ r: self.r * scalar,
+ g: self.g * scalar,
+ b: self.b * scalar,
+ }
+ }
+
+ pub fn add(&self, other: &Self) -> Color {
+ Self {
+ r: self.r + other.r,
+ g: self.g + other.g,
+ b: self.b + other.b
+ }
+ }
+}
+
+
#[derive(Debug, Copy, Clone)]
pub struct Pixel {
pub r: u8,
@@ -43,30 +73,3 @@ impl Default for Pixel {
pub type DisplayBuffer = [[Pixel; IMG_WIDTH]; IMG_HEIGHT];
-pub struct Color {
- pub r: f32,
- pub g: f32,
- pub b: f32,
-}
-
-impl Color {
- pub fn new(r: f32, g: f32, b: f32) -> Self {
- Self { r, g, b }
- }
-
- pub fn mul_scalar(&self, scalar: f32) -> Color {
- Self {
- r: self.r * scalar,
- g: self.g * scalar,
- b: self.b * scalar,
- }
- }
-
- pub fn add(&self, other: &Self) -> Color {
- Self {
- r: self.r + other.r,
- g: self.g + other.g,
- b: self.b + other.b
- }
- }
-}
diff --git a/src/main.rs b/src/main.rs
index 3c67e9e..02efc49 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,19 +1,32 @@
mod view;
mod global;
mod calculus;
-mod renderer;
+mod camera;
mod object;
mod interval;
+use crate::calculus::calculus::Point3;
use crate::global::*;
-use crate::renderer::render;
+use crate::camera::Camera;
+use crate::object::{HittableList, Sphere};
use crate::view::{render_viewer, View};
fn main() {
let mut display_buffer: DisplayBuffer = [[Pixel::default(); IMG_WIDTH]; IMG_HEIGHT];
+ let mut world = HittableList::new();
+
+ world.push(
+ Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)
+ );
+
+ world.push(
+ Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)
+ );
+
+ let camera = Camera::new();
// test_render(&mut display_buffer);
- render(&mut display_buffer);
+ camera.render(&mut display_buffer, &world);
let view = View {
diff --git a/src/renderer.rs b/src/renderer.rs
deleted file mode 100644
index 72ecf4e..0000000
--- a/src/renderer.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use crate::calculus::calculus::{Point3, Ray, Vec3};
-use crate::global::{Color, DisplayBuffer, Pixel, CAMERA_CENTER, FOCAL_LENGTH, IMG_HEIGHT, IMG_WIDTH, VIEWPORT_HEIGHT, VIEWPORT_WIDTH};
-use crate::interval::Interval;
-use crate::object::{HitRecord, Hittable, HittableList, Sphere};
-
-fn ray_color(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(display_buffer: &mut DisplayBuffer) {
- 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 / IMG_WIDTH as f32);
- let delta_pixel_v = viewport_ver_vector.scalar_mul(1.0 / IMG_HEIGHT as f32);
-
- let viewport_upper_left = CAMERA_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)
- );
-
- let mut world = HittableList::new();
-
- world.push(
- Sphere::new(Point3::new(0.0, 0.0, -1.0), 0.5)
- );
-
- world.push(
- Sphere::new(Point3::new(0.0, -100.5, -1.0), 100.0)
- );
-
-
- (0..IMG_HEIGHT).for_each(|j| {
- (0..IMG_WIDTH).for_each(|i| {
- let pixel_center = pixel_upper_left
- .add(&delta_pixel_u.scalar_mul(i as f32))
- .add(&delta_pixel_v.scalar_mul(j as f32));
- let ray_direction = pixel_center.sub(&CAMERA_CENTER);
- let ray = Ray {
- origin: &CAMERA_CENTER,
- direction: &ray_direction,
- };
- let color = ray_color(&ray, &world);
- display_buffer[j][i] = Pixel::from_color(&color);
- })
- })
-} \ No newline at end of file