Try implementing obj support
This commit is contained in:
		
							parent
							
								
									c8ce9060b1
								
							
						
					
					
						commit
						1157b0e22b
					
				
					 6 changed files with 155363 additions and 1 deletions
				
			
		
							
								
								
									
										27
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										27
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| 
						 | 
					@ -14,6 +14,17 @@ version = "1.2.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
 | 
					checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "ahash"
 | 
				
			||||||
 | 
					version = "0.7.6"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "getrandom",
 | 
				
			||||||
 | 
					 "once_cell",
 | 
				
			||||||
 | 
					 "version_check",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "autocfg"
 | 
					name = "autocfg"
 | 
				
			||||||
version = "1.1.0"
 | 
					version = "1.1.0"
 | 
				
			||||||
| 
						 | 
					@ -321,6 +332,7 @@ dependencies = [
 | 
				
			||||||
 "image",
 | 
					 "image",
 | 
				
			||||||
 "rand",
 | 
					 "rand",
 | 
				
			||||||
 "rayon",
 | 
					 "rayon",
 | 
				
			||||||
 | 
					 "tobj",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					@ -329,6 +341,21 @@ version = "1.1.0"
 | 
				
			||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 | 
					checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "tobj"
 | 
				
			||||||
 | 
					version = "3.2.3"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "deacee3abcc4fd8ff3f0f7c08d4583ab51753ed1d5a3acacd6d5773f640c27d6"
 | 
				
			||||||
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "ahash",
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[[package]]
 | 
				
			||||||
 | 
					name = "version_check"
 | 
				
			||||||
 | 
					version = "0.9.4"
 | 
				
			||||||
 | 
					source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
				
			||||||
 | 
					checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
name = "wasi"
 | 
					name = "wasi"
 | 
				
			||||||
version = "0.11.0+wasi-snapshot-preview1"
 | 
					version = "0.11.0+wasi-snapshot-preview1"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,3 +9,4 @@ edition = "2021"
 | 
				
			||||||
image = { version = "0.24.2", default-features = false, features = ["jpeg", "png", "pnm"] }
 | 
					image = { version = "0.24.2", default-features = false, features = ["jpeg", "png", "pnm"] }
 | 
				
			||||||
rand = { version = "0.8.5", features = ["small_rng"] }
 | 
					rand = { version = "0.8.5", features = ["small_rng"] }
 | 
				
			||||||
rayon = "1.5.3"
 | 
					rayon = "1.5.3"
 | 
				
			||||||
 | 
					tobj = "3.2.3"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1309
									
								
								obj/Lowpoly_tree_sample.obj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1309
									
								
								obj/Lowpoly_tree_sample.obj
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										153877
									
								
								obj/baum.obj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153877
									
								
								obj/baum.obj
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										55
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								src/main.rs
									
									
									
									
									
								
							| 
						 | 
					@ -19,6 +19,7 @@ use rayon::prelude::*;
 | 
				
			||||||
use std::env;
 | 
					use std::env;
 | 
				
			||||||
use std::sync::atomic::{AtomicU32, Ordering};
 | 
					use std::sync::atomic::{AtomicU32, Ordering};
 | 
				
			||||||
use std::sync::Arc;
 | 
					use std::sync::Arc;
 | 
				
			||||||
 | 
					use tobj;
 | 
				
			||||||
use vec3::{Color, Point3, Vec3};
 | 
					use vec3::{Color, Point3, Vec3};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
 | 
					fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
 | 
				
			||||||
| 
						 | 
					@ -166,6 +167,56 @@ fn random_world() -> HittableList {
 | 
				
			||||||
    return world;
 | 
					    return world;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn from_obj(path: &str) -> HittableList {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let mut world = HittableList::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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(),
 | 
				
			||||||
 | 
					    )));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dbg!(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let cornell_box = tobj::load_obj(path, &tobj::GPU_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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        todo!("find out how to get triangular faces and build world") // https://docs.rs/tobj/3.2.3/tobj/struct.Mesh.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in mesh.indices.iter() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for v in 0..mesh.positions.len() / 3 {
 | 
				
			||||||
 | 
					            println!(
 | 
				
			||||||
 | 
					                "    v[{}] = ({}, {}, {})",
 | 
				
			||||||
 | 
					                v,
 | 
				
			||||||
 | 
					                mesh.positions[3 * v],
 | 
				
			||||||
 | 
					                mesh.positions[3 * v + 1],
 | 
				
			||||||
 | 
					                mesh.positions[3 * v + 2]
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let material = Arc::new(Lambertian::new(&Color::new(0.4, 0.2, 0.1)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return world;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
Current world view:
 | 
					Current world view:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,7 +237,7 @@ fn main() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Image
 | 
					    // Image
 | 
				
			||||||
    let aspect_ratio = 16.0 / 9.0;
 | 
					    let aspect_ratio = 16.0 / 9.0;
 | 
				
			||||||
    let image_width = 1200;
 | 
					    let image_width = 200;
 | 
				
			||||||
    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 = 100_u32;
 | 
					    let samples_per_pixel = 100_u32;
 | 
				
			||||||
    let max_depth = 50;
 | 
					    let max_depth = 50;
 | 
				
			||||||
| 
						 | 
					@ -198,6 +249,8 @@ fn main() {
 | 
				
			||||||
    let dist_to_focus = 17.0;
 | 
					    let dist_to_focus = 17.0;
 | 
				
			||||||
    let aperture = 0.1;
 | 
					    let aperture = 0.1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let world = from_obj("obj/Lowpoly_tree_sample.obj");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // World
 | 
					    // World
 | 
				
			||||||
    let world = random_world();
 | 
					    let world = random_world();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										95
									
								
								src/obj.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/obj.rs
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,95 @@
 | 
				
			||||||
 | 
					use super::{Point3, Vec3};
 | 
				
			||||||
 | 
					use std::fs::File;
 | 
				
			||||||
 | 
					use std::io::{self, prelude::*, BufReader};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Face {
 | 
				
			||||||
 | 
					    aNormal: Vec3,
 | 
				
			||||||
 | 
					    bNormal: Vec3,
 | 
				
			||||||
 | 
					    cNormal: Vec3,
 | 
				
			||||||
 | 
					    aTexture: Point3,
 | 
				
			||||||
 | 
					    bTexture: Point3,
 | 
				
			||||||
 | 
					    cTexture: Point3,
 | 
				
			||||||
 | 
					    a: Point3,
 | 
				
			||||||
 | 
					    b: Point3,
 | 
				
			||||||
 | 
					    c: Point3,
 | 
				
			||||||
 | 
					    onlyPoints: boolean,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct Obj  {
 | 
				
			||||||
 | 
					    vertexes: Vec<Point3>,
 | 
				
			||||||
 | 
					    textures: Vec<Point3>,
 | 
				
			||||||
 | 
					    normals: Vec<Vec3>,
 | 
				
			||||||
 | 
					    faces: Vec<Face>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Obj {
 | 
				
			||||||
 | 
					    pub fn fromFile(&self, path: String) -> Self {
 | 
				
			||||||
 | 
					        let file = File::open(path)?;
 | 
				
			||||||
 | 
					        let reader = BufReader::new(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for line in reader.lines() {
 | 
				
			||||||
 | 
					            let split = line.split_whitespace();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            match split[0] {
 | 
				
			||||||
 | 
					                // vertexes
 | 
				
			||||||
 | 
					                "v" => {
 | 
				
			||||||
 | 
					                    if split.len() != 4 { continue };
 | 
				
			||||||
 | 
					                    self.vertexes.push(Point3::new(
 | 
				
			||||||
 | 
					                        split[1].parse::<f64>(),
 | 
				
			||||||
 | 
					                        split[2].parse::<f64>(),
 | 
				
			||||||
 | 
					                        split[3].parse::<f64>()
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					                    // can throw ParseFloatError
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // textures
 | 
				
			||||||
 | 
					                "vt" => {
 | 
				
			||||||
 | 
					                    if split.len() < 2 { continue };
 | 
				
			||||||
 | 
					                    normals.push(Point3::new(
 | 
				
			||||||
 | 
					                        split[1].parse::<f64>(),
 | 
				
			||||||
 | 
					                        if split.len() >= 3 { split[2].parse::<f64>() } else { 0.0 },
 | 
				
			||||||
 | 
					                        if split.len() >= 4 { split[3].parse::<f64>() } else { 0.0 },
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					                    // can throw ParseFloatError
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // normals
 | 
				
			||||||
 | 
					                "vn" => {
 | 
				
			||||||
 | 
					                    if split.len() != 4 { continue };
 | 
				
			||||||
 | 
					                    normals.push(Vec3::new(
 | 
				
			||||||
 | 
					                        split[1].parse::<f64>(),
 | 
				
			||||||
 | 
					                        split[2].parse::<f64>(),
 | 
				
			||||||
 | 
					                        split[3].parse::<f64>()
 | 
				
			||||||
 | 
					                    ));
 | 
				
			||||||
 | 
					                    // can throw ParseFloatError
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					                // faces
 | 
				
			||||||
 | 
					                "f" => {
 | 
				
			||||||
 | 
					                    if split.len() != 4 { continue };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if split[1].contains("/") { // format 'f 1/4/6 2/7/8 3/7/8'
 | 
				
			||||||
 | 
					                        let a = split[1].split("/");
 | 
				
			||||||
 | 
					                        let b = split[2].split("/");
 | 
				
			||||||
 | 
					                        let c = split[3].split("/");
 | 
				
			||||||
 | 
					                        faces.push(
 | 
				
			||||||
 | 
					                            Face {
 | 
				
			||||||
 | 
					                                aNormal: if a[1] != "" { normals[a[1].parse::<u64>()] } else { Vec3::empty() },
 | 
				
			||||||
 | 
					                                bNormal: if b[1] != "" { normals[b[1].parse::<u64>()] } else { Vec3::empty() },
 | 
				
			||||||
 | 
					                                cNormal: if c[1] != "" { normals[c[1].parse::<u64>()] } else { Vec3::empty() },
 | 
				
			||||||
 | 
					                                aTexture: if a[2] != "" { textures[a[1].parse::<u64>()] } else { Point3::empty() }
 | 
				
			||||||
 | 
					                            }
 | 
				
			||||||
 | 
					                        )
 | 
				
			||||||
 | 
					                    } else { // format 'f 1 2 3'
 | 
				
			||||||
 | 
					                        faces.push(Point3::new(
 | 
				
			||||||
 | 
					                            split[1].parse::<f64>(),
 | 
				
			||||||
 | 
					                            split[2].parse::<f64>(),
 | 
				
			||||||
 | 
					                            split[3].parse::<f64>()
 | 
				
			||||||
 | 
					                        ));
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    
 | 
				
			||||||
 | 
					                    // can throw ParseFloatError
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue