Get normals for faces directly from .obj
This commit is contained in:
		
							parent
							
								
									b37f8e3144
								
							
						
					
					
						commit
						acbb572dcd
					
				
					 3 changed files with 80 additions and 45 deletions
				
			
		
							
								
								
									
										20
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -39,9 +39,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bytemuck"
 | 
			
		||||
version = "1.10.0"
 | 
			
		||||
version = "1.11.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c53dfa917ec274df8ed3c572698f381a24eef2efba9492d797301b72b6db408a"
 | 
			
		||||
checksum = "a5377c8865e74a160d21f29c2d40669f53286db6eab59b88540cbb12ffc8b835"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "byteorder"
 | 
			
		||||
| 
						 | 
				
			
			@ -72,9 +72,9 @@ dependencies = [
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crossbeam-channel"
 | 
			
		||||
version = "0.5.5"
 | 
			
		||||
version = "0.5.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4c02a4d71819009c192cf4872265391563fd6a84c81ff2c0f2a7026ca4c1d85c"
 | 
			
		||||
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "crossbeam-utils",
 | 
			
		||||
| 
						 | 
				
			
			@ -82,9 +82,9 @@ dependencies = [
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crossbeam-deque"
 | 
			
		||||
version = "0.8.1"
 | 
			
		||||
version = "0.8.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
 | 
			
		||||
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "crossbeam-epoch",
 | 
			
		||||
| 
						 | 
				
			
			@ -93,9 +93,9 @@ dependencies = [
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crossbeam-epoch"
 | 
			
		||||
version = "0.9.9"
 | 
			
		||||
version = "0.9.10"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "07db9d94cbd326813772c968ccd25999e5f8ae22f4f8d1b11effa37ef6ce281d"
 | 
			
		||||
checksum = "045ebe27666471bb549370b4b0b3e51b07f56325befa4284db65fc89c02511b1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "autocfg",
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
| 
						 | 
				
			
			@ -107,9 +107,9 @@ dependencies = [
 | 
			
		|||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crossbeam-utils"
 | 
			
		||||
version = "0.8.10"
 | 
			
		||||
version = "0.8.11"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7d82ee10ce34d7bc12c2122495e7593a9c41347ecdd64185af4ecf72cb1a7f83"
 | 
			
		||||
checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ pub trait Hittable: Sync + Send {
 | 
			
		|||
 | 
			
		||||
impl HitRecord {
 | 
			
		||||
    fn set_face_normal(&mut self, r: &Ray, outward_normal: Vec3) {
 | 
			
		||||
        self.front_face = true;//Vec3::dot(r.direction(), outward_normal) < 0.0;
 | 
			
		||||
        self.front_face = true; //Vec3::dot(r.direction(), outward_normal) < 0.0;
 | 
			
		||||
        if self.front_face {
 | 
			
		||||
            self.normal = outward_normal;
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -161,16 +161,22 @@ impl Hittable for Triangle {
 | 
			
		|||
        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
 | 
			
		||||
        rec.normal = self.normal;
 | 
			
		||||
        return true;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        /* old normal calculation code if normal is not known
 | 
			
		||||
 | 
			
		||||
        // 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();
 | 
			
		||||
 | 
			
		||||
        println!("From obj: {},{},{} - calculated: {},{},{}", self.normal.x(),self.normal.y(),self.normal.z(),unit_normal.x(),unit_normal.y(),unit_normal.z());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if Vec3::dot(unit_normal, r.direction()) >= 0.0 {
 | 
			
		||||
            // normal towards camera
 | 
			
		||||
            rec.set_face_normal(r, unit_normal);
 | 
			
		||||
| 
						 | 
				
			
			@ -180,5 +186,6 @@ impl Hittable for Triangle {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
        */
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										92
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										92
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -17,9 +17,6 @@ use material::{Dielectric, Lambertian, Material, Metal};
 | 
			
		|||
use ray::Ray;
 | 
			
		||||
use rayon::prelude::*;
 | 
			
		||||
use std::env;
 | 
			
		||||
use std::fs::File;
 | 
			
		||||
use std::io::{self, BufRead};
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use std::sync::atomic::{AtomicU32, Ordering};
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use tobj;
 | 
			
		||||
| 
						 | 
				
			
			@ -42,13 +39,8 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
 | 
			
		|||
            return attenuation * ray_color(&scattered, world, depth - 1);
 | 
			
		||||
        }
 | 
			
		||||
        return Color::null();
 | 
			
		||||
 | 
			
		||||
        //let target = rec.p + rec.normal + Vec3::random_unit_vector(); // rec.p + rec.normal.random_in_hemisphere();
 | 
			
		||||
        //return 0.5 * ray_color(&Ray::new(rec.p, target - rec.p), world, depth - 1);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // return Color::new(1.0, 1.0, 1.0);
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    let unit_direction = r.direction();
 | 
			
		||||
    let t = 0.5 * (unit_direction.y() + 1.0);
 | 
			
		||||
    return (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0);
 | 
			
		||||
| 
						 | 
				
			
			@ -144,6 +136,7 @@ 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),
 | 
			
		||||
| 
						 | 
				
			
			@ -169,6 +162,7 @@ fn random_world() -> HittableList {
 | 
			
		|||
        Point3::new(6.0, 4.0, -6.0),
 | 
			
		||||
        material5.clone(),
 | 
			
		||||
    )));
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    return world;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -176,9 +170,24 @@ fn random_world() -> HittableList {
 | 
			
		|||
fn from_obj(path: &str) -> HittableList {
 | 
			
		||||
    let mut world = HittableList::new();
 | 
			
		||||
 | 
			
		||||
    let material = Arc::new(Lambertian::new(&Color::new(0.6, 0.2, 0.3)));
 | 
			
		||||
    let material_ground = Arc::new(Lambertian::new(&Color::new(
 | 
			
		||||
        29.0 / 255.0,
 | 
			
		||||
        71.0 / 255.0,
 | 
			
		||||
        14.0 / 255.0,
 | 
			
		||||
    )));
 | 
			
		||||
    world.add(Box::<Sphere>::new(Sphere::new(
 | 
			
		||||
        Point3::new(0.0, -5005.0, 0.0),
 | 
			
		||||
        5000.0,
 | 
			
		||||
        material_ground.clone(),
 | 
			
		||||
    )));
 | 
			
		||||
 | 
			
		||||
    let material = Arc::new(Lambertian::new(&Color::new(
 | 
			
		||||
        26.0 / 255.0,
 | 
			
		||||
        82.0 / 255.0,
 | 
			
		||||
        118.0 / 255.0,
 | 
			
		||||
    )));
 | 
			
		||||
    //let material = Arc::new(Dielectric::new(2.0));
 | 
			
		||||
    //let material = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 0.5));
 | 
			
		||||
    //let material = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 1.0));
 | 
			
		||||
 | 
			
		||||
    let cornell_box = tobj::load_obj(path, &tobj::OFFLINE_RENDERING_LOAD_OPTIONS);
 | 
			
		||||
    let (models, materials) = cornell_box.expect("Failed to load OBJ file");
 | 
			
		||||
| 
						 | 
				
			
			@ -187,6 +196,7 @@ fn from_obj(path: &str) -> HittableList {
 | 
			
		|||
    for (i, m) in models.iter().enumerate() {
 | 
			
		||||
        let mesh = &m.mesh;
 | 
			
		||||
 | 
			
		||||
        /* Mesh vector lengths
 | 
			
		||||
        println!("positions: {}", mesh.positions.len());
 | 
			
		||||
        println!("vertex_color: {}", mesh.vertex_color.len());
 | 
			
		||||
        println!("normals: {}", mesh.normals.len());
 | 
			
		||||
| 
						 | 
				
			
			@ -195,9 +205,7 @@ fn from_obj(path: &str) -> HittableList {
 | 
			
		|||
        println!("face_arities: {}", mesh.face_arities.len());
 | 
			
		||||
        println!("texcoord_indices: {}", mesh.texcoord_indices.len());
 | 
			
		||||
        println!("normal_indices: {}", mesh.normal_indices.len());
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        return world;
 | 
			
		||||
        */
 | 
			
		||||
 | 
			
		||||
        let mut next_face = 0;
 | 
			
		||||
        for f in 0..mesh.face_arities.len() {
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +219,38 @@ fn from_obj(path: &str) -> HittableList {
 | 
			
		|||
            let index_a = mesh.indices[3 * v] as usize;
 | 
			
		||||
            let index_b = mesh.indices[3 * v + 1] as usize;
 | 
			
		||||
            let index_c = mesh.indices[3 * v + 2] as usize;
 | 
			
		||||
            let index_normal = mesh.normal_indices[]
 | 
			
		||||
            let index_normal_a = mesh.normal_indices[3 * v] as usize;
 | 
			
		||||
            let index_normal_b = mesh.normal_indices[3 * v + 1] as usize;
 | 
			
		||||
            let index_normal_c = mesh.normal_indices[3 * v + 2] as usize;
 | 
			
		||||
 | 
			
		||||
            let normal_avg = Vec3::unit_vector(
 | 
			
		||||
                Vec3::new(
 | 
			
		||||
                    mesh.positions[3 * index_normal_a] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_normal_a + 1] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_normal_a + 2] as f64,
 | 
			
		||||
                ) + Vec3::new(
 | 
			
		||||
                    mesh.positions[3 * index_normal_b] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_normal_b + 1] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_normal_b + 2] as f64,
 | 
			
		||||
                ) + Vec3::new(
 | 
			
		||||
                    mesh.positions[3 * index_normal_c] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_normal_c + 1] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_normal_c + 2] as f64,
 | 
			
		||||
                ),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
            println!("a:{},{},{}; b:{},{},{}; c:{},{},{}",
 | 
			
		||||
            mesh.normals[3*index_normal_a],
 | 
			
		||||
            mesh.normals[3*index_normal_a+1],
 | 
			
		||||
            mesh.normals[3*index_normal_a+2],
 | 
			
		||||
            mesh.normals[3*index_normal_b],
 | 
			
		||||
            mesh.normals[3*index_normal_b+1],
 | 
			
		||||
            mesh.normals[3*index_normal_b+2],
 | 
			
		||||
            mesh.normals[3*index_normal_c],
 | 
			
		||||
            mesh.normals[3*index_normal_c+1],
 | 
			
		||||
            mesh.normals[3*index_normal_c+2]);
 | 
			
		||||
            */
 | 
			
		||||
 | 
			
		||||
            world.add(Box::<Triangle>::new(Triangle::new(
 | 
			
		||||
                Point3::new(
 | 
			
		||||
| 
						 | 
				
			
			@ -229,7 +268,7 @@ fn from_obj(path: &str) -> HittableList {
 | 
			
		|||
                    mesh.positions[3 * index_c + 1] as f64,
 | 
			
		||||
                    mesh.positions[3 * index_c + 2] as f64,
 | 
			
		||||
                ),
 | 
			
		||||
                mesh.
 | 
			
		||||
                normal_avg,
 | 
			
		||||
                material.clone(),
 | 
			
		||||
            )));
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -237,16 +276,6 @@ fn from_obj(path: &str) -> HittableList {
 | 
			
		|||
    return world;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The output is wrapped in a Result to allow matching on errors
 | 
			
		||||
// Returns an Iterator to the Reader of the lines of the file.
 | 
			
		||||
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
 | 
			
		||||
where
 | 
			
		||||
    P: AsRef<Path>,
 | 
			
		||||
{
 | 
			
		||||
    let file = File::open(filename)?;
 | 
			
		||||
    Ok(io::BufReader::new(file).lines())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
Current world view:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -267,27 +296,26 @@ fn main() {
 | 
			
		|||
 | 
			
		||||
    // 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 = 1_u32;
 | 
			
		||||
    let samples_per_pixel = 50_u32;
 | 
			
		||||
    let max_depth = 50;
 | 
			
		||||
 | 
			
		||||
    let vfov = 40.0;
 | 
			
		||||
    let lookfrom = Point3::new(2.0, 0.5, 3.0);
 | 
			
		||||
    let lookfrom = Point3::new(2.0, 0.8, 3.0);
 | 
			
		||||
    let lookat = Point3::new(0.0, 0.0, 0.0);
 | 
			
		||||
    let vup = Vec3::new(0.0, 1.0, 0.0);
 | 
			
		||||
    let dist_to_focus = 3.0;
 | 
			
		||||
    let aperture = 0.1;
 | 
			
		||||
 | 
			
		||||
    // limit rayon multithreading thread count
 | 
			
		||||
    let thread_count = 0; // if 0, for each logical cpu core a thread wil be created
 | 
			
		||||
    let thread_count = 6; // if 0, for each logical cpu core a thread wil be created
 | 
			
		||||
    if thread_count > 0 {
 | 
			
		||||
        env::set_var("RAYON_NUM_THREADS", thread_count.to_string());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let world = from_obj("obj/suzanne.obj");
 | 
			
		||||
 | 
			
		||||
    // World
 | 
			
		||||
    let world = from_obj("obj/suzanne.obj");
 | 
			
		||||
    // let world = random_world();
 | 
			
		||||
 | 
			
		||||
    // Camera
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue