Add OBJ loading
This commit is contained in:
parent
526e92f582
commit
cee009f5a8
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"
|
||||||
@ -324,6 +335,7 @@ dependencies = [
|
|||||||
"image",
|
"image",
|
||||||
"rand",
|
"rand",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
"tobj",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -332,6 +344,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"
|
||||||
|
@ -10,6 +10,7 @@ include = ["/src"]
|
|||||||
image = { version = "0.24.2", default-features = false, features=["png", "jpeg", "jpeg_rayon"] }
|
image = { version = "0.24.2", default-features = false, features=["png", "jpeg", "jpeg_rayon"] }
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
rayon = "1.5.3"
|
rayon = "1.5.3"
|
||||||
|
tobj = "3.2.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = 1
|
debug = 1
|
||||||
|
62
src/main.rs
62
src/main.rs
@ -16,11 +16,13 @@ use crate::constant_medium::ConstantMedium;
|
|||||||
use crate::cuboid::Cuboid;
|
use crate::cuboid::Cuboid;
|
||||||
use crate::image_texture::ImageTexture;
|
use crate::image_texture::ImageTexture;
|
||||||
use crate::noise::NoiseTexture;
|
use crate::noise::NoiseTexture;
|
||||||
|
use crate::obj::obj_to_hitable;
|
||||||
use crate::perlin::Perlin;
|
use crate::perlin::Perlin;
|
||||||
use crate::texture::CheckerTexture;
|
use crate::texture::CheckerTexture;
|
||||||
use crate::rect::{Plane, Rect2D};
|
use crate::rect::{Plane, Rect2D};
|
||||||
use crate::rotate_y::RotateY;
|
use crate::rotate_y::RotateY;
|
||||||
use crate::translate::Translate;
|
use crate::translate::Translate;
|
||||||
|
use crate::triangle::Triangle;
|
||||||
|
|
||||||
mod vec3;
|
mod vec3;
|
||||||
mod ray;
|
mod ray;
|
||||||
@ -40,11 +42,13 @@ mod translate;
|
|||||||
mod rotate_y;
|
mod rotate_y;
|
||||||
mod constant_medium;
|
mod constant_medium;
|
||||||
mod isotropic;
|
mod isotropic;
|
||||||
|
mod obj;
|
||||||
|
mod triangle;
|
||||||
|
|
||||||
// Image
|
// Image
|
||||||
const DEFAULT_ASPECT_RATIO: f64 = 3.0 / 2.0;
|
const DEFAULT_ASPECT_RATIO: f64 = 3.0 / 2.0;
|
||||||
const IMAGE_WIDTH: usize = 1600;
|
const IMAGE_WIDTH: usize = 600;
|
||||||
const SAMPLES_PER_PIXEL: i32 = 1_000;
|
const SAMPLES_PER_PIXEL: i32 = 100;
|
||||||
const MAX_DEPTH: i32 = 50;
|
const MAX_DEPTH: i32 = 50;
|
||||||
|
|
||||||
struct Scene {
|
struct Scene {
|
||||||
@ -53,6 +57,55 @@ struct Scene {
|
|||||||
pub background: Color
|
pub background: Color
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn obj(path: &str) -> Scene {
|
||||||
|
let object = obj_to_hitable(&std::path::Path::new(path));
|
||||||
|
print!("Object hitbox: {:#?}", object.bounding_box(0.0, 1.0));
|
||||||
|
|
||||||
|
let difflight = Arc::new(Material::white_light(2.0));
|
||||||
|
|
||||||
|
let world: HittableList = vec![
|
||||||
|
object,
|
||||||
|
Arc::new(Rect2D::new(
|
||||||
|
Plane::XZ,
|
||||||
|
-2.0,
|
||||||
|
2.0,
|
||||||
|
-2.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
difflight.clone()
|
||||||
|
)),
|
||||||
|
Arc::new(Rect2D::new(
|
||||||
|
Plane::XY,
|
||||||
|
-2.0,
|
||||||
|
2.0,
|
||||||
|
-2.0,
|
||||||
|
2.0,
|
||||||
|
5.0,
|
||||||
|
difflight
|
||||||
|
))];
|
||||||
|
|
||||||
|
let look_from = Point3::new(10.0, 10.0, 10.0);
|
||||||
|
let look_at = Point3::new(0.0, 1.0, 0.0);
|
||||||
|
let focus_dist = 2.0;
|
||||||
|
|
||||||
|
let cam = Camera::new(
|
||||||
|
look_from,
|
||||||
|
look_at,
|
||||||
|
Vec3::new(0.0, 1.0, 0.0),
|
||||||
|
1.0,
|
||||||
|
40.0,
|
||||||
|
0.0,
|
||||||
|
focus_dist,
|
||||||
|
0.0,
|
||||||
|
1.0);
|
||||||
|
|
||||||
|
Scene {
|
||||||
|
world,
|
||||||
|
cam,
|
||||||
|
background: Color::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn cornell_box() -> Scene {
|
fn cornell_box() -> Scene {
|
||||||
let mut world:HittableList = Vec::new();
|
let mut world:HittableList = Vec::new();
|
||||||
let red = Material::Lambertian(
|
let red = Material::Lambertian(
|
||||||
@ -771,9 +824,9 @@ fn next_week_final() -> Scene {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
//rayon::ThreadPoolBuilder::new().num_threads(3).build_global().unwrap(); // Enable, to reduce load
|
//rayon::ThreadPoolBuilder::new().num_threads(1).build_global().unwrap(); // Enable, to reduce load
|
||||||
// World
|
// World
|
||||||
let scene: u8 = 7;
|
let scene: u8 = 8;
|
||||||
let scene_setup = match scene {
|
let scene_setup = match scene {
|
||||||
0 => two_spheres(),
|
0 => two_spheres(),
|
||||||
1 => two_perlin_spheres(),
|
1 => two_perlin_spheres(),
|
||||||
@ -783,6 +836,7 @@ fn main() {
|
|||||||
5 => cornell_box(),
|
5 => cornell_box(),
|
||||||
6 => cornell_box_smoke(),
|
6 => cornell_box_smoke(),
|
||||||
7 => next_week_final(),
|
7 => next_week_final(),
|
||||||
|
8 => obj("teapot.obj"),
|
||||||
_ => random_scene(),
|
_ => random_scene(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,7 +20,19 @@ pub enum Material {
|
|||||||
|
|
||||||
impl Default for Material {
|
impl Default for Material {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Material::Lambertian(Lambertian::from(Color::default()))
|
Material::solid(0.8, 0.8, 0.8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Material {
|
||||||
|
pub fn solid(r: f64, g: f64, b: f64) -> Self {
|
||||||
|
Material::Lambertian(Lambertian::from(Color::new(r, g, b)))
|
||||||
|
}
|
||||||
|
pub fn light(r: f64, g: f64, b: f64) -> Self {
|
||||||
|
Material::DiffuseLight(DiffuseLight::from(Color::new(r, g, b)))
|
||||||
|
}
|
||||||
|
pub fn white_light(brightness: f64) -> Self {
|
||||||
|
Material::DiffuseLight(DiffuseLight::from(Color::new(brightness, brightness, brightness)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
src/obj.rs
Normal file
53
src/obj.rs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use tobj::LoadOptions;
|
||||||
|
use crate::{BVH, Color, HittableList, HittableObject, Lambertian, Material, Point3, Vec3};
|
||||||
|
use crate::hittable::Hittable;
|
||||||
|
use crate::triangle::Triangle;
|
||||||
|
|
||||||
|
pub fn obj_to_hitable(path: &Path) -> HittableObject {
|
||||||
|
let mut lo = LoadOptions::default();
|
||||||
|
lo.triangulate = true;
|
||||||
|
let (models, materials) = tobj::load_obj(path, &lo)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let default_mat: Arc<Material> = Arc::new(
|
||||||
|
Material::Lambertian(
|
||||||
|
Lambertian::from(
|
||||||
|
Color::new(0.6, 0.6, 0.6)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
let mut triangles: HittableList = Vec::with_capacity(models.len());
|
||||||
|
for model in models {
|
||||||
|
let mesh = model.mesh;
|
||||||
|
for f in 0..mesh.indices.len() / 3 {
|
||||||
|
let i0 = mesh.indices[3 * f] as usize;
|
||||||
|
let i1 = mesh.indices[3 * f + 1] as usize;
|
||||||
|
let i2 = mesh.indices[3 * f + 2] as usize;
|
||||||
|
let v0 = Point3::new(
|
||||||
|
mesh.positions[i0 * 3] as f64,
|
||||||
|
mesh.positions[i0 * 3 + 1] as f64,
|
||||||
|
mesh.positions[i0 * 3 + 2] as f64);
|
||||||
|
let v1 = Point3::new(
|
||||||
|
mesh.positions[i1 * 3] as f64,
|
||||||
|
mesh.positions[i1 * 3 + 1] as f64,
|
||||||
|
mesh.positions[i1 * 3 + 2] as f64);
|
||||||
|
let v2 = Point3::new(
|
||||||
|
mesh.positions[i2 * 3] as f64,
|
||||||
|
mesh.positions[i2 * 3 + 1] as f64,
|
||||||
|
mesh.positions[i2 * 3 + 2] as f64);
|
||||||
|
let triangle = if mesh.normals.len() <= i0 * 3 + 2 {
|
||||||
|
Triangle::without_normal(v0, v1, v2, default_mat.clone())
|
||||||
|
} else {
|
||||||
|
let normal = Vec3::new(
|
||||||
|
mesh.normals[i0 * 3] as f64,
|
||||||
|
mesh.normals[i0 * 3 + 1] as f64,
|
||||||
|
mesh.normals[i0 * 3 + 2] as f64);
|
||||||
|
Triangle::new(v0, v1, v2, normal, default_mat.clone())
|
||||||
|
};
|
||||||
|
triangles.push(Arc::new(triangle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Arc::new(BVH::new(triangles, 0.0, 1.0))
|
||||||
|
}
|
78
src/triangle.rs
Normal file
78
src/triangle.rs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
use crate::hittable::{HitRecord, Hittable};
|
||||||
|
use crate::{Aabb, Material, Point3, Ray, Vec3};
|
||||||
|
//https://github.com/perliedman/raytracing-in-one-weekend/blob/master/src/geometry/triangle.rs
|
||||||
|
|
||||||
|
pub struct Triangle {
|
||||||
|
a: Point3,
|
||||||
|
b: Point3,
|
||||||
|
c: Point3,
|
||||||
|
normal: Vec3,
|
||||||
|
material: Arc<Material>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Triangle {
|
||||||
|
pub fn new(a: Point3, b: Point3, c: Point3, normal: Vec3, material: Arc<Material>, ) -> Self {
|
||||||
|
Self { a, b, c, normal, material }
|
||||||
|
}
|
||||||
|
pub fn without_normal(a: Point3, b: Point3, c: Point3, material: Arc<Material>, ) -> Self {
|
||||||
|
let normal = (b - a).cross(&(c - a));
|
||||||
|
Self { a, b, c, normal, material }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hittable for Triangle {
|
||||||
|
fn hit(&self, ray: &Ray, t_min: f64, t_max: f64) -> Option<HitRecord> {
|
||||||
|
let ab = self.b - self.a;
|
||||||
|
let ac = self.c - self.a;
|
||||||
|
let pvec = ray.direction().cross(&ac);
|
||||||
|
let det = ab.dot(&pvec);
|
||||||
|
if det.abs() < 1e-4 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let inv_det = 1.0 / det;
|
||||||
|
let tvec = ray.origin() - self.a;
|
||||||
|
let u = tvec.dot(&pvec) * inv_det;
|
||||||
|
if u < 0.0 || u > 1.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let qvec = tvec.cross(&ab);
|
||||||
|
let v = ray.direction().dot(&qvec) * inv_det;
|
||||||
|
if v < 0.0 || u + v > 1.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
match ac.dot(&qvec) * inv_det {
|
||||||
|
t if t < t_min || t > t_max => None,
|
||||||
|
_ => {
|
||||||
|
let mut rec = HitRecord {
|
||||||
|
point: ray.at(t),
|
||||||
|
normal: self.normal,
|
||||||
|
t,
|
||||||
|
u,
|
||||||
|
v,
|
||||||
|
front_face: true,
|
||||||
|
material: &self.material
|
||||||
|
};
|
||||||
|
rec.normalized(ray);
|
||||||
|
Some(rec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounding_box(&self, _time0: f64, _time1: f64) -> Option<Aabb> {
|
||||||
|
Some(Aabb {
|
||||||
|
minimum: Point3::new(
|
||||||
|
self.a.x().min(self.b.x()).min(self.c.x()),
|
||||||
|
self.a.y().min(self.b.y()).min(self.c.y()),
|
||||||
|
self.a.z().min(self.b.z()).min(self.c.z()),
|
||||||
|
),
|
||||||
|
maximum: Point3::new(
|
||||||
|
self.a.x().max(self.b.x()).max(self.c.x()),
|
||||||
|
self.a.y().max(self.b.y()).max(self.c.y()),
|
||||||
|
self.a.z().max(self.b.z()).max(self.c.z()),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
19814
teapot.obj
Normal file
19814
teapot.obj
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user