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