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};
 | 
			
		||||
 | 
			
		||||
pub struct HitRecord {
 | 
			
		||||
    pub p: Point3,
 | 
			
		||||
    pub normal: Vec3,
 | 
			
		||||
    pub p: Point3,    // hit location
 | 
			
		||||
    pub normal: Vec3, // normal of hit location
 | 
			
		||||
    pub mat_ptr: Arc<dyn Material>,
 | 
			
		||||
    pub t: f64,
 | 
			
		||||
    pub front_face: bool,
 | 
			
		||||
    pub t: f64,           // ray steps (distance) from camera to hit
 | 
			
		||||
    pub front_face: bool, // whether object was hitted from front or back
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Sphere {
 | 
			
		||||
| 
						 | 
				
			
			@ -113,41 +113,67 @@ impl Triangle {
 | 
			
		|||
 | 
			
		||||
impl Hittable for Triangle {
 | 
			
		||||
    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_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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let inv_det = 1.0 / det;
 | 
			
		||||
        let f = 1.0 / 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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										51
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										51
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -10,7 +10,7 @@ mod utility;
 | 
			
		|||
mod vec3;
 | 
			
		||||
 | 
			
		||||
use camera::Camera;
 | 
			
		||||
use hittable::{HitRecord, Hittable, Sphere};
 | 
			
		||||
use hittable::{HitRecord, Hittable, Sphere, Triangle};
 | 
			
		||||
use hittable_list::HittableList;
 | 
			
		||||
use image::{Rgb, RgbImage};
 | 
			
		||||
use material::{Dielectric, Lambertian, Material, Metal};
 | 
			
		||||
| 
						 | 
				
			
			@ -50,14 +50,13 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
 | 
			
		|||
fn random_world() -> HittableList {
 | 
			
		||||
    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(
 | 
			
		||||
        Point3::new(0.0, -50000.0, 0.0),
 | 
			
		||||
        50000.0,
 | 
			
		||||
        material_ground.clone(),
 | 
			
		||||
    )));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    (-6..5).into_iter().for_each(|a| {
 | 
			
		||||
        (-6..5).into_iter().for_each(|b| {
 | 
			
		||||
            let choose_mat = utility::random_f64();
 | 
			
		||||
| 
						 | 
				
			
			@ -138,18 +137,58 @@ fn random_world() -> HittableList {
 | 
			
		|||
        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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Current world view:
 | 
			
		||||
 | 
			
		||||
            I y
 | 
			
		||||
            I
 | 
			
		||||
            I
 | 
			
		||||
            I
 | 
			
		||||
          /   \
 | 
			
		||||
        /       \
 | 
			
		||||
      /           \
 | 
			
		||||
    / z             \ x
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    // File
 | 
			
		||||
    let mut default_file = "image.ppm";
 | 
			
		||||
 | 
			
		||||
    // Image
 | 
			
		||||
    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 samples_per_pixel = 50_u32;
 | 
			
		||||
    let samples_per_pixel = 100_u32;
 | 
			
		||||
    let max_depth = 50;
 | 
			
		||||
 | 
			
		||||
    let vfov = 40.0;
 | 
			
		||||
| 
						 | 
				
			
			@ -183,7 +222,7 @@ fn main() {
 | 
			
		|||
 | 
			
		||||
    let atomic_counter = Arc::new(AtomicU32::new(0));
 | 
			
		||||
    let color_lines: Vec<_> = (0..image_height)
 | 
			
		||||
        .into_par_iter()  // threadded/parallel variant
 | 
			
		||||
        .into_par_iter() // threadded/parallel variant
 | 
			
		||||
        //.into_iter()  // iterative variant
 | 
			
		||||
        .rev()
 | 
			
		||||
        .map(|j| {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue