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