diff --git a/src/main.rs b/src/main.rs index 6c5f499..9985e70 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,6 +22,7 @@ use std::sync::Arc; use tobj; use vec3::{Color, Point3, Vec3}; +/* Gets the pixel color for the passed ray */ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color { let mut rec = HitRecord::empty(); @@ -46,251 +47,19 @@ fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color { return (1.0 - t) * Color::new(1.0, 1.0, 1.0) + t * Color::new(0.5, 0.7, 1.0); } -fn random_world() -> HittableList { - let mut world = HittableList::new(); - - let material_ground = Arc::new(Lambertian::new(&Color::new(0.05, 0.05, 0.05))); - world.add(Box::::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(); - let rad = utility::random_rng(0.1, 0.5); - let center = Point3::new( - 1.5 * a as f64 + 1.3 * utility::random_f64(), - rad, - 1.5 * b as f64 + 1.3 * utility::random_f64(), - ); - if (center - Point3::new(4.0, rad, 0.0)).length() > 0.9 { - if choose_mat < 0.8 { - // diffuse - let sphere_material = Arc::new(Lambertian::new( - &(Color::random_f64() * Color::random_f64()), - )); - world.add(Box::::new(Sphere::new( - center, - rad, - sphere_material.clone(), - ))); - } else if choose_mat < 0.95 { - // metal - let sphere_material = Arc::new(Metal::new( - &Color::random_rng(0.5, 1.0), - utility::random_rng(0.0, 0.5), - )); - world.add(Box::::new(Sphere::new( - center, - 0.2, - sphere_material.clone(), - ))); - } else { - // glass - let sphere_material = Arc::new(Dielectric::new(1.5)); - world.add(Box::::new(Sphere::new( - center, - 0.2, - sphere_material.clone(), - ))); - } - } - }); - }); - - let material1 = Arc::new(Dielectric::new(1.5)); - let material2 = Arc::new(Lambertian::new(&Color::new(0.4, 0.2, 0.1))); - let material3 = Arc::new(Metal::new(&Color::new(0.7, 0.6, 0.5), 0.0)); - let material4 = Arc::new(Dielectric::new(2.0)); - let material5 = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 0.0)); - - world.add(Box::::new(Sphere::new( - Point3::new(0.0, 1.0, 0.0), - 1.0, - material2.clone(), - ))); - - world.add(Box::::new(Sphere::new( - Point3::new(-4.0, 1.0, 0.0), - 1.0, - material1.clone(), - ))); - - world.add(Box::::new(Sphere::new( - Point3::new(4.0, 1.0, 0.0), - 1.0, - material3.clone(), - ))); - - world.add(Box::::new(Sphere::new( - Point3::new(-2.0, 2.0, -5.0), - 2.0, - material4.clone(), - ))); - - world.add(Box::::new(Sphere::new( - Point3::new(-3.6, 2.0, -2.0), - 0.6, - material5.clone(), - ))); - - /* - world.add(Box::::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::::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::::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::::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; -} - -fn from_obj(path: &str) -> HittableList { - let mut world = HittableList::new(); - - /* - 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( - // 77.0 / 255.0, - // 77.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), 1.0)); - let material = Arc::new(Rainbow::new()); - - let cornell_box = tobj::load_obj(path, &tobj::OFFLINE_RENDERING_LOAD_OPTIONS); - let (models, materials) = cornell_box.expect("Failed to load OBJ file"); - let materials = materials.expect("Failed to load MTL file"); - - 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()); - println!("texcoords: {}", mesh.texcoords.len()); - println!("indices: {}", mesh.indices.len()); - println!("face_arities: {}", mesh.face_arities.len()); - println!("texcoord_indices: {}", mesh.texcoord_indices.len()); - println!("normal_indices: {}", mesh.normal_indices.len()); - */ - - let mut next_face = 0; - for f in 0..mesh.face_arities.len() { - let end = next_face + mesh.face_arities[f] as usize; - let face_indices: Vec<_> = mesh.indices[next_face..end].iter().collect(); - println!(" face[{}] = {:?}", f, face_indices); - next_face = end; - } - - for v in 0..mesh.indices.len() / 3 { - 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_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( - mesh.positions[3 * index_a] as f64, - mesh.positions[3 * index_a + 1] as f64, - mesh.positions[3 * index_a + 2] as f64, - ), - Point3::new( - mesh.positions[3 * index_b] as f64, - mesh.positions[3 * index_b + 1] as f64, - mesh.positions[3 * index_b + 2] as f64, - ), - Point3::new( - mesh.positions[3 * index_c] as f64, - mesh.positions[3 * index_c + 1] as f64, - mesh.positions[3 * index_c + 2] as f64, - ), - normal_avg, - material.clone(), - ))); - } - } - return world; -} - -/* -Current world view: - - I y - I - I - I - / \ - / \ - / \ - / z \ x +// Current world view: +// +// I y +// I +// I +// I +// / \ +// / \ +// / \ +// / z \ x +/* +* Main function that builds everything and runs the raytracing */ fn main() { // File @@ -467,3 +236,249 @@ fn main() { image.save(default_file).unwrap(); } + + +/******************** +* WORLD GENERATION * +********************* +*/ + + +/* +* Generates world based on .obj mesh file passed by path +*/ +fn from_obj(path: &str) -> HittableList { + let mut world = HittableList::new(); + + /* + 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( + // 77.0 / 255.0, + // 77.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), 1.0)); + let material = Arc::new(Rainbow::new()); + + let cornell_box = tobj::load_obj(path, &tobj::OFFLINE_RENDERING_LOAD_OPTIONS); + let (models, materials) = cornell_box.expect("Failed to load OBJ file"); + let materials = materials.expect("Failed to load MTL file"); + + 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()); + println!("texcoords: {}", mesh.texcoords.len()); + println!("indices: {}", mesh.indices.len()); + println!("face_arities: {}", mesh.face_arities.len()); + println!("texcoord_indices: {}", mesh.texcoord_indices.len()); + println!("normal_indices: {}", mesh.normal_indices.len()); + */ + + let mut next_face = 0; + for f in 0..mesh.face_arities.len() { + let end = next_face + mesh.face_arities[f] as usize; + let face_indices: Vec<_> = mesh.indices[next_face..end].iter().collect(); + println!(" face[{}] = {:?}", f, face_indices); + next_face = end; + } + + for v in 0..mesh.indices.len() / 3 { + 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_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( + mesh.positions[3 * index_a] as f64, + mesh.positions[3 * index_a + 1] as f64, + mesh.positions[3 * index_a + 2] as f64, + ), + Point3::new( + mesh.positions[3 * index_b] as f64, + mesh.positions[3 * index_b + 1] as f64, + mesh.positions[3 * index_b + 2] as f64, + ), + Point3::new( + mesh.positions[3 * index_c] as f64, + mesh.positions[3 * index_c + 1] as f64, + mesh.positions[3 * index_c + 2] as f64, + ), + normal_avg, + material.clone(), + ))); + } + } + return world; +} + +/* +* Generates a world with a bunch of spheres +*/ +fn random_world() -> HittableList { + let mut world = HittableList::new(); + + let material_ground = Arc::new(Lambertian::new(&Color::new(0.05, 0.05, 0.05))); + world.add(Box::::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(); + let rad = utility::random_rng(0.1, 0.5); + let center = Point3::new( + 1.5 * a as f64 + 1.3 * utility::random_f64(), + rad, + 1.5 * b as f64 + 1.3 * utility::random_f64(), + ); + if (center - Point3::new(4.0, rad, 0.0)).length() > 0.9 { + if choose_mat < 0.8 { + // diffuse + let sphere_material = Arc::new(Lambertian::new( + &(Color::random_f64() * Color::random_f64()), + )); + world.add(Box::::new(Sphere::new( + center, + rad, + sphere_material.clone(), + ))); + } else if choose_mat < 0.95 { + // metal + let sphere_material = Arc::new(Metal::new( + &Color::random_rng(0.5, 1.0), + utility::random_rng(0.0, 0.5), + )); + world.add(Box::::new(Sphere::new( + center, + 0.2, + sphere_material.clone(), + ))); + } else { + // glass + let sphere_material = Arc::new(Dielectric::new(1.5)); + world.add(Box::::new(Sphere::new( + center, + 0.2, + sphere_material.clone(), + ))); + } + } + }); + }); + + let material1 = Arc::new(Dielectric::new(1.5)); + let material2 = Arc::new(Lambertian::new(&Color::new(0.4, 0.2, 0.1))); + let material3 = Arc::new(Metal::new(&Color::new(0.7, 0.6, 0.5), 0.0)); + let material4 = Arc::new(Dielectric::new(2.0)); + let material5 = Arc::new(Metal::new(&Color::new(0.9, 0.9, 0.7), 0.0)); + + world.add(Box::::new(Sphere::new( + Point3::new(0.0, 1.0, 0.0), + 1.0, + material2.clone(), + ))); + + world.add(Box::::new(Sphere::new( + Point3::new(-4.0, 1.0, 0.0), + 1.0, + material1.clone(), + ))); + + world.add(Box::::new(Sphere::new( + Point3::new(4.0, 1.0, 0.0), + 1.0, + material3.clone(), + ))); + + world.add(Box::::new(Sphere::new( + Point3::new(-2.0, 2.0, -5.0), + 2.0, + material4.clone(), + ))); + + world.add(Box::::new(Sphere::new( + Point3::new(-3.6, 2.0, -2.0), + 0.6, + material5.clone(), + ))); + + /* + world.add(Box::::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::::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::::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::::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; +} \ No newline at end of file