Skip to content

Commit

Permalink
fix(world): will take closest object for ray, not first
Browse files Browse the repository at this point in the history
  • Loading branch information
grishy committed Feb 19, 2024
1 parent b1a53bd commit 6ed2e44
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 37 deletions.
6 changes: 3 additions & 3 deletions src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ impl Camera {
pub fn new() -> Camera {
let aspect_ratio = 16.0 / 9.0;
let image_width = 1600;
let samples_per_pixel = 300;
let max_depth = 30;
let vfov: f64 = 50.0;
let samples_per_pixel = 600;
let max_depth = 200;
let vfov: f64 = 30.0;
let look_from = Point3::new(-2.0, 2.0, 1.0);
let look_at = Point3::new(0.0, 0.0, -1.0);
let vup = Vector3::new(0.0, 1.0, 0.0);
Expand Down
3 changes: 0 additions & 3 deletions src/hittable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,3 @@ impl HitRecord {
}
}

pub fn length_squared(v: &Vector3) -> f64 {
v.x * v.x + v.y * v.y + v.z * v.z
}
23 changes: 14 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,15 @@ impl HittableList {

impl hittable::Hittable for HittableList {
fn hit(&self, ray: &ray::Ray, ray_t: Range<f64>) -> Option<hittable::HitRecord> {
self.objects
.iter()
.flat_map(|obj| obj.hit(ray, ray_t.clone()))
.next()
let (_closest, hit_record) = self.objects.iter().fold((ray_t.end, None), |acc, item| {
if let Some(temp_rec) = item.hit(ray, ray_t.start..acc.0) {
(temp_rec.t, Some(temp_rec))
} else {
acc
}
});

hit_record
}
}

Expand All @@ -44,6 +49,11 @@ fn main() {
let material_left = Arc::new(material::Dielectric::new(1.5));
let material_right = Arc::new(material::Metal::new(Color::new(0.8, 0.6, 0.2), 0.0));

world.add(Arc::new(sphere::Sphere::new(
Point3::new(0.0, -100.5, -1.0),
100.0,
material_ground,
)));
world.add(Arc::new(sphere::Sphere::new(
Point3::new(0.0, 0.0, -1.0),
0.5,
Expand All @@ -64,11 +74,6 @@ fn main() {
0.5,
material_right,
)));
world.add(Arc::new(sphere::Sphere::new(
Point3::new(0.0, -100.5, -1.0),
100.0,
material_ground,
)));

// Render
camera.render("target/image.ppm", &world);
Expand Down
41 changes: 22 additions & 19 deletions src/material.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ use rand::Rng;

use crate::types::*;

fn reflect(v: &Vector3, n: &Vector3) -> Vector3 {
*v - 2.0 * v.dot(n) * *n
fn reflect(v: Vector3, n: Vector3) -> Vector3 {
v - 2. * v.dot(&n) * n
}

fn refract(uv: &Vector3, n: &Vector3, etai_over_etat: f64) -> Vector3 {
let cos_theta = (-*uv).dot(n).min(1.0);
fn refract(uv: Vector3, n: Vector3, etai_over_etat: f64) -> Vector3 {
let cos_theta = (uv * -1.0).dot(&n).min(1.0);
let r_out_perp = etai_over_etat * (uv + cos_theta * n);
let r_out_parallel = -((1.0 - r_out_perp.norm_squared()).abs()).sqrt() * n;
let r_out_parallel = ((1.0 - r_out_perp.magnitude_squared()).abs().sqrt() * -1.0) * n;
r_out_perp + r_out_parallel
}

fn reflectance(cosine: f64, ref_idx: f64) -> f64 {
// Use Schlick's approximation for reflectance
let r0 = ((1.0 - ref_idx) / (1.0 + ref_idx)).powi(2);
r0 + (1.0 - r0) * (1.0 - cosine).powi(5)
// Use Schlick's approximation for reflectance.
let mut r0 = (1. - ref_idx) / (1. + ref_idx);
r0 = r0 * r0;
r0 + (1. - r0) * (1. - cosine).powf(5.)
}

pub trait Material {
Expand Down Expand Up @@ -129,27 +130,29 @@ impl Material for Dielectric {
ray_in: &ray::Ray,
hit_record: &hittable::HitRecord,
) -> Option<(Color, ray::Ray)> {
let mut rng = rand::thread_rng();

let attenuation = Color::new(1.0, 1.0, 1.0);
let refraction_ratio = if hit_record.front_face {
1.0 / self.ir
let refraction_ratio: f64 = if hit_record.front_face {
self.ir.recip()
} else {
self.ir
};

let unit_direction = ray_in.dir.normalize();
let cos_theta = (-unit_direction).dot(&hit_record.normal).min(1.0);

let cos_theta = (unit_direction.dot(&hit_record.normal) * -1.0).min(1.0);
let sin_theta = (1.0 - cos_theta * cos_theta).sqrt();

let cannot_refract = refraction_ratio * sin_theta > 1.0;
let is_reflectance = reflectance(cos_theta, refraction_ratio) > rand::thread_rng().gen();
let direction = if cannot_refract || is_reflectance {
reflect(&unit_direction, &hit_record.normal)
} else {
refract(&unit_direction, &hit_record.normal, refraction_ratio)
};

let scattered = ray::Ray::new(hit_record.p, direction);
let direction =
if cannot_refract || reflectance(cos_theta, refraction_ratio) > rng.gen::<f64>() {
reflect(unit_direction, hit_record.normal)
} else {
refract(unit_direction, hit_record.normal, refraction_ratio)
};

Some((attenuation, scattered))
Some((attenuation, ray::Ray::new(hit_record.p, direction)))
}
}
5 changes: 2 additions & 3 deletions src/sphere.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::ops::Range;
use std::sync::Arc;

use crate::hittable;
use crate::hittable::length_squared;
use crate::hittable::HitRecord;
use crate::material;
use crate::ray;
Expand Down Expand Up @@ -31,9 +30,9 @@ impl hittable::Hittable for Sphere {
fn hit(&self, ray: &ray::Ray, ray_t: Range<f64>) -> Option<hittable::HitRecord> {
let oc = ray.orig - self.center;

let a = length_squared(&ray.dir);
let a = ray.dir.magnitude_squared();
let half_b = oc.dot(&ray.dir);
let c = length_squared(&oc) - self.radius * self.radius;
let c = oc.magnitude_squared() - self.radius * self.radius;
let discriminant = half_b * half_b - a * c;

if discriminant < 0.0 {
Expand Down

0 comments on commit 6ed2e44

Please sign in to comment.