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"
 | 
			
		||||
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]]
 | 
			
		||||
name = "autocfg"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
| 
						 | 
				
			
			@ -321,6 +332,7 @@ dependencies = [
 | 
			
		|||
 "image",
 | 
			
		||||
 "rand",
 | 
			
		||||
 "rayon",
 | 
			
		||||
 "tobj",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
| 
						 | 
				
			
			@ -329,6 +341,21 @@ version = "1.1.0"
 | 
			
		|||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
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]]
 | 
			
		||||
name = "wasi"
 | 
			
		||||
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"] }
 | 
			
		||||
rand = { version = "0.8.5", features = ["small_rng"] }
 | 
			
		||||
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::sync::atomic::{AtomicU32, Ordering};
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use tobj;
 | 
			
		||||
use vec3::{Color, Point3, Vec3};
 | 
			
		||||
 | 
			
		||||
fn ray_color(r: &Ray, world: &HittableList, depth: u32) -> Color {
 | 
			
		||||
| 
						 | 
				
			
			@ -166,6 +167,56 @@ fn random_world() -> HittableList {
 | 
			
		|||
    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:
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -186,7 +237,7 @@ fn main() {
 | 
			
		|||
 | 
			
		||||
    // Image
 | 
			
		||||
    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 samples_per_pixel = 100_u32;
 | 
			
		||||
    let max_depth = 50;
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +249,8 @@ fn main() {
 | 
			
		|||
    let dist_to_focus = 17.0;
 | 
			
		||||
    let aperture = 0.1;
 | 
			
		||||
 | 
			
		||||
    let world = from_obj("obj/Lowpoly_tree_sample.obj");
 | 
			
		||||
 | 
			
		||||
    // 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