Add Hittable Triangle
This commit is contained in:
parent
a5eed43b0f
commit
c8ce9060b1
2 changed files with 88 additions and 23 deletions
|
@ -1,11 +1,11 @@
|
||||||
use super::{Arc, Color, Material, Metal, Point3, Ray, Vec3};
|
use super::{Arc, Color, Material, Metal, Point3, Ray, Vec3};
|
||||||
|
|
||||||
pub struct HitRecord {
|
pub struct HitRecord {
|
||||||
pub p: Point3,
|
pub p: Point3, // hit location
|
||||||
pub normal: Vec3,
|
pub normal: Vec3, // normal of hit location
|
||||||
pub mat_ptr: Arc<dyn Material>,
|
pub mat_ptr: Arc<dyn Material>,
|
||||||
pub t: f64,
|
pub t: f64, // ray steps (distance) from camera to hit
|
||||||
pub front_face: bool,
|
pub front_face: bool, // whether object was hitted from front or back
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Sphere {
|
pub struct Sphere {
|
||||||
|
@ -113,41 +113,67 @@ impl Triangle {
|
||||||
|
|
||||||
impl Hittable for Triangle {
|
impl Hittable for Triangle {
|
||||||
fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
|
fn hit(&self, r: &Ray, t_min: f64, t_max: f64, rec: &mut HitRecord) -> bool {
|
||||||
|
let epsilon = 0.0000001;
|
||||||
|
|
||||||
let a_to_b = self.b - self.a;
|
let a_to_b = self.b - self.a;
|
||||||
let a_to_c = self.c - self.a;
|
let a_to_c = self.c - self.a;
|
||||||
|
|
||||||
let u_vec = Vec3::cross(r.direction(), a_to_c);
|
let h = Vec3::cross(r.direction(), a_to_c);
|
||||||
|
|
||||||
let det = Vec3::dot(a_to_b, u_vec);
|
let a = Vec3::dot(a_to_b, h);
|
||||||
|
|
||||||
if det < 0.0 { // only positive bound
|
if a > -epsilon && a < epsilon {
|
||||||
|
// ray is parallel to triangle
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let inv_det = 1.0 / det;
|
let f = 1.0 / a;
|
||||||
|
|
||||||
let a_to_origin = r.origin() - self.a;
|
let a_to_origin = r.origin() - self.a;
|
||||||
|
|
||||||
let u = Vec3::dot(a_to_origin, u_vec) * inv_det;
|
let u = Vec3::dot(a_to_origin, h) * f;
|
||||||
|
|
||||||
if u < 0.0 || u > 1.0 { //check if outside of triangle
|
if u < 0.0 || u > 1.0 {
|
||||||
|
//check if outside of triangle
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let v_vec = Vec3::cross(a_to_origin, a_to_b);
|
let q = Vec3::cross(a_to_origin, a_to_b);
|
||||||
|
|
||||||
let v = Vec3::dot(r.direction(), v_vec) * inv_det;
|
let v = Vec3::dot(r.direction(), q) * f;
|
||||||
|
|
||||||
if v < 0.0 || u+v > 1.0 { // intersection outside of triangle
|
if v < 0.0 || u + v > 1.0 {
|
||||||
|
// intersection outside of triangle
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let dist = Vec3::dot(a_to_c, v_vec) * inv_det;
|
let t = Vec3::dot(a_to_c, q) * f; // where is intersection on ray?
|
||||||
|
|
||||||
if dist > 0.0 {
|
if t <= epsilon {
|
||||||
|
// line intersection but no ray intersection
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ray intersection
|
||||||
|
rec.t = t;
|
||||||
|
rec.p = r.at(t);
|
||||||
|
rec.mat_ptr = self.mat_ptr.clone();
|
||||||
|
|
||||||
|
// triangle normal alg from https://stackoverflow.com/questions/19350792/calculate-normal-of-a-single-triangle-in-3d-space
|
||||||
|
let normal_to_camera = Vec3::new(
|
||||||
|
a_to_b.y() * a_to_c.z() - a_to_b.z() * a_to_c.y(),
|
||||||
|
a_to_b.z() * a_to_c.x() - a_to_b.x() * a_to_c.z(),
|
||||||
|
a_to_b.x() * a_to_c.y() - a_to_b.y() * a_to_c.x(),
|
||||||
|
);
|
||||||
|
let unit_normal = normal_to_camera / normal_to_camera.length();
|
||||||
|
if Vec3::dot(unit_normal, r.direction()) >= 0.0 {
|
||||||
|
// normal towards camera
|
||||||
|
rec.set_face_normal(r, unit_normal);
|
||||||
|
} else {
|
||||||
|
// normal not towards camera, has to be flipped
|
||||||
|
rec.set_face_normal(r, -1.0 * unit_normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
51
src/main.rs
51
src/main.rs
|
@ -10,7 +10,7 @@ mod utility;
|
||||||
mod vec3;
|
mod vec3;
|
||||||
|
|
||||||
use camera::Camera;
|
use camera::Camera;
|
||||||
use hittable::{HitRecord, Hittable, Sphere};
|
use hittable::{HitRecord, Hittable, Sphere, Triangle};
|
||||||
use hittable_list::HittableList;
|
use hittable_list::HittableList;
|
||||||
use image::{Rgb, RgbImage};
|
use image::{Rgb, RgbImage};
|
||||||
use material::{Dielectric, Lambertian, Material, Metal};
|
use material::{Dielectric, Lambertian, Material, Metal};
|
||||||
|
@ -50,14 +50,13 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
|
||||||
fn random_world() -> HittableList {
|
fn random_world() -> HittableList {
|
||||||
let mut world = HittableList::new();
|
let mut world = HittableList::new();
|
||||||
|
|
||||||
let material_ground = Arc::new(Lambertian::new(&Color::new(0.05, 0.05,0.05)));
|
let material_ground = Arc::new(Lambertian::new(&Color::new(0.05, 0.05, 0.05)));
|
||||||
world.add(Box::<Sphere>::new(Sphere::new(
|
world.add(Box::<Sphere>::new(Sphere::new(
|
||||||
Point3::new(0.0, -50000.0, 0.0),
|
Point3::new(0.0, -50000.0, 0.0),
|
||||||
50000.0,
|
50000.0,
|
||||||
material_ground.clone(),
|
material_ground.clone(),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
|
||||||
(-6..5).into_iter().for_each(|a| {
|
(-6..5).into_iter().for_each(|a| {
|
||||||
(-6..5).into_iter().for_each(|b| {
|
(-6..5).into_iter().for_each(|b| {
|
||||||
let choose_mat = utility::random_f64();
|
let choose_mat = utility::random_f64();
|
||||||
|
@ -138,18 +137,58 @@ fn random_world() -> HittableList {
|
||||||
material5.clone(),
|
material5.clone(),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
|
world.add(Box::<Triangle>::new(Triangle::new(
|
||||||
|
Point3::new(0.0, 1.0, 5.0),
|
||||||
|
Point3::new(3.0, 2.0, 0.0),
|
||||||
|
Point3::new(0.0, 4.0, 0.0),
|
||||||
|
material2.clone(),
|
||||||
|
)));
|
||||||
|
|
||||||
|
world.add(Box::<Triangle>::new(Triangle::new(
|
||||||
|
Point3::new(5.0, 1.0, -6.0),
|
||||||
|
Point3::new(1.0, 3.0, -5.0),
|
||||||
|
Point3::new(6.0, 4.0, -6.0),
|
||||||
|
material5.clone(),
|
||||||
|
)));
|
||||||
|
world.add(Box::<Triangle>::new(Triangle::new(
|
||||||
|
Point3::new(5.0, 1.0, -6.0),
|
||||||
|
Point3::new(8.0, 1.0, -7.0),
|
||||||
|
Point3::new(6.0, 4.0, -6.0),
|
||||||
|
material5.clone(),
|
||||||
|
)));
|
||||||
|
world.add(Box::<Triangle>::new(Triangle::new(
|
||||||
|
Point3::new(8.0, 4.0, -5.0),
|
||||||
|
Point3::new(8.0, 1.0, -7.0),
|
||||||
|
Point3::new(6.0, 4.0, -6.0),
|
||||||
|
material5.clone(),
|
||||||
|
)));
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Current world view:
|
||||||
|
|
||||||
|
I y
|
||||||
|
I
|
||||||
|
I
|
||||||
|
I
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ \
|
||||||
|
/ z \ x
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// File
|
// File
|
||||||
let mut default_file = "image.ppm";
|
let mut default_file = "image.ppm";
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
let aspect_ratio = 16.0 / 9.0;
|
let aspect_ratio = 16.0 / 9.0;
|
||||||
let image_width = 600;
|
let image_width = 1200;
|
||||||
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
let image_height = (image_width as f64 / aspect_ratio) as u32;
|
||||||
let samples_per_pixel = 50_u32;
|
let samples_per_pixel = 100_u32;
|
||||||
let max_depth = 50;
|
let max_depth = 50;
|
||||||
|
|
||||||
let vfov = 40.0;
|
let vfov = 40.0;
|
||||||
|
@ -183,7 +222,7 @@ fn main() {
|
||||||
|
|
||||||
let atomic_counter = Arc::new(AtomicU32::new(0));
|
let atomic_counter = Arc::new(AtomicU32::new(0));
|
||||||
let color_lines: Vec<_> = (0..image_height)
|
let color_lines: Vec<_> = (0..image_height)
|
||||||
.into_par_iter() // threadded/parallel variant
|
.into_par_iter() // threadded/parallel variant
|
||||||
//.into_iter() // iterative variant
|
//.into_iter() // iterative variant
|
||||||
.rev()
|
.rev()
|
||||||
.map(|j| {
|
.map(|j| {
|
||||||
|
|
Loading…
Reference in a new issue