Skip to content

Commit

Permalink
quads!
Browse files Browse the repository at this point in the history
  • Loading branch information
ChristopherBiscardi committed Sep 1, 2023
1 parent c1548fa commit dd72c24
Show file tree
Hide file tree
Showing 3 changed files with 196 additions and 0 deletions.
83 changes: 83 additions & 0 deletions examples/quads.rs
@@ -0,0 +1,83 @@
use glam::DVec3;
use raytracer::{
camera::Camera,
material::Material,
shapes::{quad::Quad, sphere::Sphere},
textures::Texture,
};
use std::{io, path::Path};

fn main() -> io::Result<()> {
let mut world = vec![];

// Materials
let left_red = Material::Lambertian {
albedo: DVec3::new(1.0, 0.2, 0.2).into(),
};
let back_green = Material::Lambertian {
albedo: DVec3::new(0.2, 1.0, 0.2).into(),
};
let right_blue = Material::Lambertian {
albedo: DVec3::new(0.2, 0.2, 1.0).into(),
};
let upper_orange = Material::Lambertian {
albedo: DVec3::new(1.0, 0.5, 0.0).into(),
};
let lower_teal = Material::Lambertian {
albedo: DVec3::new(0.2, 0.8, 0.8).into(),
};

// Quads
world.push(Quad::new(
DVec3::new(-3., -2., 5.),
DVec3::new(0., 0., -4.),
DVec3::new(0., 4., 0.),
left_red,
));
world.push(Quad::new(
DVec3::new(-2., -2., 0.),
DVec3::new(4., 0., 0.),
DVec3::new(0., 4., 0.),
back_green,
));
world.push(Quad::new(
DVec3::new(3., -2., 1.),
DVec3::new(0., 0., 4.),
DVec3::new(0., 4., 0.),
right_blue,
));
world.push(Quad::new(
DVec3::new(-2., 3., 1.),
DVec3::new(4., 0., 0.),
DVec3::new(0., 0., 4.),
upper_orange,
));
world.push(Quad::new(
DVec3::new(-2., -3., 5.),
DVec3::new(4., 0., 0.),
DVec3::new(0., 0., -4.),
lower_teal,
));

let camera = Camera::init()
.image_width(800)
.aspect_ratio(1.)
.look_from(DVec3::new(0., 0., 9.))
.look_at(DVec3::ZERO)
.vup(DVec3::Y)
.focus_dist(10.0)
.defocus_angle(0.0)
.samples_per_pixel(500)
.max_depth(50)
.vfov(80.)
.build();

let filename = Path::new(file!())
.file_name()
.and_then(|s| s.to_str())
.unwrap()
.trim_end_matches(".rs");
camera.render_to_disk(filename, world)?;

Ok(())
}
5 changes: 5 additions & 0 deletions src/shapes.rs
@@ -1,5 +1,6 @@
use crate::hittable::Hittable;

pub mod quad;
pub mod sphere;
// are other shapes useful?
// possible SDF definitions?
Expand All @@ -9,6 +10,7 @@ pub mod sphere;

pub enum Shapes {
Sphere(sphere::Sphere),
Quad(quad::Quad),
// RoundedBox(rounded_box::RoundedBox),
// Box(a_box::Box),
// Cylinder(cylinder::Cylinder),
Expand All @@ -23,6 +25,9 @@ impl Hittable for Shapes {
match self {
Shapes::Sphere(object) => {
object.hit(ray, interval)
}
Shapes::Quad(object) => {
object.hit(ray, interval)
} // Shapes::RoundedBox(object) => {
// object.hit(ray, interval)
// }
Expand Down
108 changes: 108 additions & 0 deletions src/shapes/quad.rs
@@ -0,0 +1,108 @@
use std::{f64::consts::PI, ops::Range};

use glam::DVec3;

use crate::{
hittable::{HitRecord, Hittable},
material::Material,
ray::Ray,
textures::Texture,
};

pub struct Quad {
Q: DVec3,
u: DVec3,
v: DVec3,
material: Material,
normal: DVec3,
D: f64,
w: DVec3,
}

impl Quad {
pub fn new(
Q: DVec3,
u: DVec3,
v: DVec3,
material: Material,
) -> Self {
let n = u.cross(v);
let normal = n.normalize();
let D = normal.dot(Q);
let w = n / n.dot(n);
Self {
Q,
u,
v,
material,
normal,
D,
w,
}
}
fn is_interior(a: f64, b: f64) -> Option<(f64, f64)> {
// Given the hit point in plane coordinates, return false if it is outside the
// primitive, otherwise set the hit record UV coordinates and return true.

if (a < 0.) || (1. < a) || (b < 0.) || (1. < b) {
return None;
}

// a,b == u,v
Some((a, b))
}
}

impl Hittable for Quad {
fn hit(
&self,
ray: &Ray,
interval: Range<f64>,
) -> Option<HitRecord> {
let denom = self.normal.dot(ray.direction);

// No hit if the ray is parallel to the plane.
if denom.abs() < 1e-8 {
return None;
}
// Return false if the hit point parameter t is outside the ray interval.
let t =
(self.D - self.normal.dot(ray.origin)) / denom;
if !interval.contains(&t) {
return None;
}

// Determine the hit point lies within the planar shape using its plane coordinates.
let intersection = ray.at(t);
let planar_hitpt_vector: DVec3 =
intersection - self.Q;
let alpha =
self.w.dot(planar_hitpt_vector.cross(self.v));
let beta =
self.w.dot(self.u.cross(planar_hitpt_vector));

let Some((u, v)) = Quad::is_interior(alpha, beta)
else {
return None;
};
// Ray hits the 2D shape; set the rest of the hit record and return true.
// rec.t = t;
// rec.p = intersection;
// rec.mat = mat;
// rec.set_face_normal(r, normal);

// return true;

let rec = HitRecord::with_face_normal(
self.material.clone(),
intersection,
self.normal,
t,
ray,
u,
v,
);

Some(rec)
}
}

0 comments on commit dd72c24

Please sign in to comment.