Try implementing obj support

This commit is contained in:
Jonathan Flueren 2022-07-15 00:08:51 +02:00
parent c8ce9060b1
commit 1157b0e22b
6 changed files with 155363 additions and 1 deletions

27
Cargo.lock generated
View file

@ -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"

View file

@ -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

File diff suppressed because it is too large Load diff

153877
obj/baum.obj Normal file

File diff suppressed because it is too large Load diff

View file

@ -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
View 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(())
}
}