From acbb572dcdb8af4ee891974c747651a8e749e2a5 Mon Sep 17 00:00:00 2001 From: Jonathan Flueren Date: Tue, 26 Jul 2022 19:50:09 +0200 Subject: [PATCH] Get normals for faces directly from .obj --- Cargo.lock | 20 +++++------ src/hittable.rs | 13 +++++-- src/main.rs | 92 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 80 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7866e91..e5d0a88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/src/hittable.rs b/src/hittable.rs index 0954d57..c456233 100644 --- a/src/hittable.rs +++ b/src/hittable.rs @@ -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; + */ } } diff --git a/src/main.rs b/src/main.rs index bbb6bb4..13c4d3a 100644 --- a/src/main.rs +++ b/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::::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::::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::::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

(filename: P) -> io::Result>> -where - P: AsRef, -{ - 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