ft: 9: diffuse materials

This commit is contained in:
2026-04-15 15:18:33 +02:00
parent 5d18a57799
commit e8f84b590b
6 changed files with 332 additions and 15 deletions

View File

@@ -12,6 +12,7 @@ pub struct Camera {
image_width: u32,
image_height: u32,
anti_alias_rate: u32,
max_depth: u32,
center: Vec3,
pixel00_loc: Vec3,
pixel_delta_u: Vec3,
@@ -45,6 +46,7 @@ impl Camera {
image_width: image_width,
image_height: image_height,
anti_alias_rate: anti_alias_rate,
max_depth: 50,
center: camera_center,
pixel00_loc: pixel00_loc,
pixel_delta_u: pixel_delta_u,
@@ -70,7 +72,7 @@ impl Camera {
+ (y * self.pixel_delta_v / (self.anti_alias_rate + 1) as f32);
let ray_dir = pixel_loc - self.center;
let r = Ray::new(self.center, ray_dir);
pixel_colour += self.ray_colour(&hittables, &r);
pixel_colour += self.ray_colour(&hittables, &r, self.max_depth);
}
}
@@ -84,11 +86,15 @@ impl Camera {
imgbuf.save("output.png").unwrap();
}
fn ray_colour<T: Hittable>(&self, hittables: &Vec<T>, r: &Ray) -> Colour {
fn ray_colour<T: Hittable>(&self, hittables: &Vec<T>, r: &Ray, depth: u32) -> Colour {
if depth <= 0 {
return Colour::nil();
}
let closest = Hit::hit_list(hittables, r);
if let Some(hit) = closest {
let n = hit.n();
return 0.5 * Colour::new(n.x() + 1., n.y() + 1., n.z() + 1.);
let dir = *hit.n() + Vec3::random_unit_hemisphere(hit.n());
return 0.5 * self.ray_colour(hittables, &Ray::new(*hit.p(), dir), depth - 1);
}
// background

View File

@@ -19,6 +19,6 @@ fn main() {
world.push(Sphere::new(Vec3::new(0., 0., -0.1), 0.01));
world.push(Sphere::new(Vec3::new(0., -100.5, -1.), 100.));
let c = Camera::new_aa(16. / 9., 400, 2);
let c = Camera::new_aa(16. / 9., 400, 3);
c.render(&world);
}

View File

@@ -28,7 +28,9 @@ impl Hit {
for hittable in hittables {
if let Some(hit) = hittable.hit(r) {
// hit happens in front of camera and is closer than closest
if *hit.t() > 0. && (closest.is_none() || closest.as_ref().unwrap().t() > hit.t()) {
if *hit.t() > 0.001
&& (closest.is_none() || closest.as_ref().unwrap().t() > hit.t())
{
closest = Some(hit);
}
}

View File

@@ -4,6 +4,8 @@ use std::{
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use rand::RngExt;
#[derive(Copy, Clone)]
pub struct Vec3 {
r: f32,
@@ -26,6 +28,33 @@ impl Vec3 {
}
}
pub fn random() -> Vec3 {
let mut rng = rand::rng();
Vec3 {
r: rng.random_range(-1.0..1.),
g: rng.random_range(-1.0..1.),
b: rng.random_range(-1.0..1.),
}
}
pub fn random_unit() -> Vec3 {
loop {
let v = Vec3::random();
if v.length_squared() <= 1. {
return v / v.length();
}
}
}
pub fn random_unit_hemisphere(n: &Vec3) -> Vec3 {
let v = Vec3::random_unit();
if n.dot(&v) > 0.0 {
v
} else {
-v
}
}
pub fn x(&self) -> &f32 {
&self.r
}
@@ -67,9 +96,26 @@ impl Vec3 {
}
pub fn output(self) -> image::Rgb<u8> {
let ir = (255.599 * self.r.clamp(0., 1.)) as u8;
let ig = (255.599 * self.g.clamp(0., 1.)) as u8;
let ib = (255.599 * self.b.clamp(0., 1.)) as u8;
// gamma correction
let r = if self.r > 0. {
sqrt(self.r).clamp(0., 1.)
} else {
0.
};
let g = if self.g > 0. {
sqrt(self.g).clamp(0., 1.)
} else {
0.
};
let b = if self.b > 0. {
sqrt(self.b).clamp(0.1, 1.)
} else {
0.
};
let ir = (255.599 * r) as u8;
let ig = (255.599 * g) as u8;
let ib = (255.599 * b) as u8;
image::Rgb([ir, ig, ib])
}