From 67c1eb861dc45a05a3259457177522d64297798d Mon Sep 17 00:00:00 2001 From: djairoh Date: Wed, 15 Apr 2026 12:11:04 +0200 Subject: [PATCH] ft: 4: ray class + simpl gradient --- src/main.rs | 51 +++++++++++++++++++++------ src/ray.rs | 27 +++++++++++++++ src/vec3.rs | 99 ++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 src/ray.rs diff --git a/src/main.rs b/src/main.rs index 4718de6..a28a657 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,31 +1,62 @@ #![feature(core_float_math)] +mod ray; mod vec3; -use crate::vec3::Vec3; +use std::cmp::max; + +use crate::ray::Ray; +use crate::vec3::{Colour, Vec3}; use log::info; use pretty_env_logger; +fn ray_colour(r: &Ray) -> Colour { + let unit_dir = r.dir().get_unit(); + let a = 0.5 * (unit_dir.y() + 1.); + + (1.0 - a) * Colour::new(1., 1., 1.) + a * Colour::new(0.5, 0.7, 1.0) +} + fn main() { - let v = Vec3::rgb(255., 0., 255.); + // use structs so rust-analyzer can provide lsp + let v = Vec3::new(255., 0., 255.); + let _ = Ray::new(v.clone(), v.clone()); + pretty_env_logger::init(); - let image_width = 256; - let image_height = 256; + let aspect_ratio = 16. / 9.; + let image_width = 400; + let image_height = max(1, (image_width as f32 / aspect_ratio) as u32); + + //camera + let focal_length = 1.; + let viewport_height = 2.; + let viewport_width = viewport_height * (image_width as f32 / image_height as f32); + let camera_center = Vec3::nil(); + + //viewport + let viewport_u = Vec3::new(viewport_width as f32, 0., 0.); + let viewport_v = Vec3::new(0., -viewport_height as f32, 0.); + + let pixel_delta_u = viewport_u / image_width as f32; + let pixel_delta_v = viewport_v / image_height as f32; + + let viewport_upper_left = + camera_center - Vec3::new(0., 0., focal_length) - viewport_u / 2 - viewport_v / 2; + let pixel00_loc = viewport_upper_left + 0.5 * (pixel_delta_u + pixel_delta_v); let mut imgbuf = image::ImageBuffer::new(image_width, image_height); + // render for j in 0..image_height { info!("{}\tScanlines remaining.", (image_height - j)); for i in 0..image_width { - let rgb = Vec3::rgb( - i as f32 / (image_width - 1) as f32, - j as f32 / (image_height - 1) as f32, - 0.0, - ); + let pixel_center = pixel00_loc + (i * pixel_delta_u) + (j * pixel_delta_v); + let ray_dir = pixel_center - camera_center; + let r = Ray::new(camera_center, ray_dir); let pixel = imgbuf.get_pixel_mut(i, j); - *pixel = rgb.output(); + *pixel = ray_colour(&r).output(); } } diff --git a/src/ray.rs b/src/ray.rs new file mode 100644 index 0000000..db8475a --- /dev/null +++ b/src/ray.rs @@ -0,0 +1,27 @@ +use crate::vec3::Vec3; + +pub struct Ray { + origin: Vec3, + dir: Vec3, +} + +impl Ray { + pub fn at(self, t: f32) -> Vec3 { + self.origin + t * self.dir + } + + pub fn new(origin: Vec3, dir: Vec3) -> Ray { + Ray { + origin: origin, + dir: dir, + } + } + + pub fn origin(&self) -> &Vec3 { + &self.origin + } + + pub fn dir(&self) -> &Vec3 { + &self.dir + } +} diff --git a/src/vec3.rs b/src/vec3.rs index 0579aff..3ba2014 100644 --- a/src/vec3.rs +++ b/src/vec3.rs @@ -4,22 +4,46 @@ use std::{ ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; +#[derive(Copy, Clone)] pub struct Vec3 { r: f32, g: f32, b: f32, } +pub type Colour = Vec3; + impl Vec3 { - pub fn rgb(r: f32, g: f32, b: f32) -> Vec3 { - return Self { r: r, g: g, b: b }; + pub fn new(r: f32, g: f32, b: f32) -> Vec3 { + Self { r: r, g: g, b: b } } + + pub fn nil() -> Vec3 { + Self { + r: 0., + g: 0., + b: 0., + } + } + + pub fn x(&self) -> &f32 { + &self.r + } + + pub fn y(&self) -> &f32 { + &self.g + } + + pub fn z(&self) -> &f32 { + &self.b + } + pub fn length(&self) -> f32 { - return sqrt(self.length_squared()); + sqrt(self.length_squared()) } pub fn length_squared(&self) -> f32 { - return (self.r * self.r + self.g * self.g + self.b * self.b) as f32; + (self.r * self.r + self.g * self.g + self.b * self.b) as f32 } pub fn dot(self, other: Vec3) -> Vec3 { @@ -38,10 +62,14 @@ impl Vec3 { } } - pub fn unit(mut self) { + pub fn make_unit(mut self) { self /= self.length(); } + pub fn get_unit(self) -> Vec3 { + self / self.length() + } + pub fn output(self) -> image::Rgb { let ir = (255.599 * self.r) as u8; let ig = (255.599 * self.g) as u8; @@ -49,6 +77,14 @@ impl Vec3 { image::Rgb([ir, ig, ib]) } + + pub fn clone(&self) -> Vec3 { + Vec3 { + r: self.r, + g: self.g, + b: self.b, + } + } } impl Neg for Vec3 { @@ -67,11 +103,11 @@ impl Add for Vec3 { type Output = Self; fn add(self, _rhs: Self) -> Self { - return Self { + Self { r: self.r + _rhs.r, g: self.g + _rhs.g, b: self.b + _rhs.b, - }; + } } } @@ -79,11 +115,11 @@ impl Add for Vec3 { type Output = Self; fn add(self, f: f32) -> Self { - return Self { + Self { r: self.r + f, g: self.g + f, b: self.b + f, - }; + } } } @@ -111,11 +147,11 @@ impl Sub for Vec3 { type Output = Self; fn sub(self, rhs: Self) -> Self { - return Self { + Self { r: self.r - rhs.r, g: self.g - rhs.g, b: self.b - rhs.b, - }; + } } } @@ -123,11 +159,11 @@ impl Sub for Vec3 { type Output = Self; fn sub(self, f: f32) -> Self { - return Self { + Self { r: self.r - f, g: self.g - f, b: self.b - f, - }; + } } } @@ -163,6 +199,19 @@ impl Mul for Vec3 { } } +impl Mul for u32 { + type Output = Vec3; + + fn mul(self, rhs: Vec3) -> Self::Output { + let f = self as f32; + Vec3 { + r: rhs.r * f, + g: rhs.g * f, + b: rhs.b * f, + } + } +} + impl Mul for Vec3 { type Output = Self; @@ -175,6 +224,18 @@ impl Mul for Vec3 { } } +impl Mul for f32 { + type Output = Vec3; + + fn mul(self, rhs: Vec3) -> Self::Output { + Vec3 { + r: rhs.r * self, + g: rhs.g * self, + b: rhs.b * self, + } + } +} + impl MulAssign for Vec3 { fn mul_assign(&mut self, rhs: Self) { *self = Self { @@ -206,6 +267,18 @@ impl Div for Vec3 { } } } +impl Div for Vec3 { + type Output = Self; + + fn div(self, i: i32) -> Self::Output { + let f: f32 = i as f32; + Self { + r: self.r / f, + g: self.g / f, + b: self.b / f, + } + } +} impl Div for Vec3 { type Output = Self;