summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-01 16:43:50 +0700
committerRosyid Haryadi <rosyid_haryadi@protonmail.com>2025-03-01 16:43:50 +0700
commit084875ac8e9aa12cf6cc1892def9e4bc5fd4cdda (patch)
tree99fbc7b743fdf7a2b26ded0e8073c9a02be5240b
parent2d7457db1c0c719de3e1f76161a35af3fb5ae0c9 (diff)
object list, something is still wrong
-rw-r--r--src/calculus.rs6
-rw-r--r--src/main.rs1
-rw-r--r--src/object.rs109
-rw-r--r--src/renderer.rs54
4 files changed, 142 insertions, 28 deletions
diff --git a/src/calculus.rs b/src/calculus.rs
index ac33514..67138d1 100644
--- a/src/calculus.rs
+++ b/src/calculus.rs
@@ -1,4 +1,5 @@
pub mod calculus {
+ #[derive(Copy, Clone)]
pub struct Vec3 {
pub x: f32,
pub y: f32,
@@ -78,4 +79,9 @@ pub mod calculus {
self.origin.add(&self.direction.scalar_mul(t))
}
}
+
+ pub fn deg2rad(deg: f32) -> f32 {
+ deg * std::f32::consts::PI / 180.0
+ }
+
} \ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 9bdb6ed..db7d2ee 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -2,6 +2,7 @@ mod view;
mod global;
mod calculus;
mod renderer;
+mod object;
use crate::global::*;
use crate::renderer::render;
diff --git a/src/object.rs b/src/object.rs
new file mode 100644
index 0000000..ff965f0
--- /dev/null
+++ b/src/object.rs
@@ -0,0 +1,109 @@
+use crate::calculus::calculus::{Point3, Ray, Vec3};
+
+#[derive(Clone)]
+pub struct HitRecord {
+ pub position: Point3,
+ pub normal: Vec3,
+ pub t: f32,
+ pub front_face: bool,
+}
+
+impl Default for HitRecord {
+ fn default() -> Self {
+ Self {
+ position: Point3 {x:0.0, y:0.0, z:0.0},
+ normal: Vec3 {x:0.0, y:0.0, z:0.0},
+ t: 0.0,
+ front_face: false,
+ }
+ }
+}
+
+impl HitRecord {
+ pub fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) {
+ self.front_face = r.direction.dot_prod(&outward_normal) < 0.0;
+ self.normal = if self.front_face { outward_normal } else { outward_normal.scalar_mul(-1.0) };
+ }
+}
+
+pub trait Hittable {
+ fn hit(&self, r: &Ray, ray_tmin: f32, ray_tmax: f32, rec: &mut HitRecord) -> bool;
+}
+
+pub struct Sphere {
+ center: Point3,
+ radius: f32,
+}
+
+impl Sphere {
+ pub fn new(center: Vec3, radius: f32) -> Self {
+ let r = f32::max(0.0, radius);
+ Self { center, radius }
+ }
+}
+
+impl Hittable for Sphere {
+ fn hit(&self, r: &Ray, ray_tmin: f32, ray_tmax: f32, rec: &mut HitRecord) -> bool {
+ let oc = self.center.sub(&r.origin);
+ let a = r.direction.mag_sqr();
+ let h = r.direction.dot_prod(&oc);
+ let c = oc.mag_sqr() - self.radius * self.radius;
+ let discriminant = h * h - a * c;
+ if discriminant < 0.0 {
+ return false;
+ }
+
+ let sqrtd = discriminant.sqrt();
+
+ let mut root = (h - sqrtd) / a;
+ if root <= ray_tmin || ray_tmax <= root {
+ root = (h + sqrtd) / a;
+ if root <= ray_tmin || ray_tmax <= root {
+ return false;
+ }
+ }
+
+ rec.t = root;
+ rec.position = r.at(rec.t);
+ let outward_normal = rec.normal
+ .sub(&self.center)
+ .scalar_mul(1.0 / self.radius);
+ rec.set_face_normal(r, outward_normal);
+
+ true
+ }
+}
+
+pub struct HittableList {
+ objects: Vec<Box<dyn Hittable>>,
+}
+
+impl HittableList {
+ pub fn new() -> Self {
+ Self { objects: vec![] }
+ }
+
+ pub fn push<T: Hittable + 'static>(&mut self, object: T) {
+ self.objects.push(Box::new(object));
+ }
+}
+
+impl Hittable for HittableList {
+ fn hit(&self, r: &Ray, ray_tmin: f32, ray_tmax: f32, rec: &mut HitRecord) -> bool {
+ let mut temp_rec = HitRecord::default();
+ let mut hit_anything = false;
+ let mut closest_so_far = ray_tmax;
+
+ self.objects.iter().for_each(
+ |object| {
+ if object.hit(r, ray_tmin, closest_so_far, &mut temp_rec) {
+ hit_anything = true;
+ closest_so_far = temp_rec.t;
+ *rec = temp_rec.clone();
+ }
+ }
+ );
+
+ hit_anything
+ }
+} \ No newline at end of file
diff --git a/src/renderer.rs b/src/renderer.rs
index 49d8046..2fb76d2 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -1,18 +1,18 @@
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::object::{HitRecord, Hittable, HittableList, Sphere};
-fn ray_color(ray: &Ray) -> Color {
- let t = hit_sphere(&Point3 {x: 0.0, y: 0.0, z: -1.0}, 0.5, ray);
- if t > 0.0 {
- let normal = ray
- .at(t)
- .sub(&Vec3 {x: 0.0, y: 0.0, z: -1.0})
- .unit();
- return Color::new(
- normal.x + 1.0,
- normal.y + 1.0,
- normal.z + 1.0,
- ).mul_scalar(0.5);
+fn ray_color(ray: &Ray, world: &HittableList) -> Color {
+ let mut rec = HitRecord::default();
+ if world.hit(ray, 0.0, f32::INFINITY, &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();
@@ -22,22 +22,9 @@ fn ray_color(ray: &Ray) -> Color {
color1.add(&color2)
}
-fn hit_sphere(center: &Point3, radius: f32, ray: &Ray) -> f32 {
- let oc = center.sub(&ray.origin);
- let a = ray.direction.mag_sqr();
- let h = ray.direction.dot_prod(&oc);
- let c = oc.mag_sqr() - radius * radius;
- let discriminant = h * h - a * c;
- if discriminant < 0.0 {
- -1.0
- } else {
- (h - discriminant.sqrt()) / a
- }
-}
-
pub fn render(display_buffer: &mut DisplayBuffer) {
- let viewport_hor_vector = Vec3{ x: VIEWPORT_WIDTH as f32, y: 0.0, z: 0.0 };
- let viewport_ver_vector = Vec3 { x: 0.0, y: -1f32 * VIEWPORT_HEIGHT as f32, z: 0.0 };
+ 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);
@@ -50,6 +37,17 @@ pub fn render(display_buffer: &mut DisplayBuffer) {
&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
@@ -60,7 +58,7 @@ pub fn render(display_buffer: &mut DisplayBuffer) {
origin: &CAMERA_CENTER,
direction: &ray_direction,
};
- let color = ray_color(&ray);
+ let color = ray_color(&ray, &world);
display_buffer[j][i] = Pixel::from_color(&color);
})
})