parent
526e92f582
commit
cee009f5a8
@ -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))
|
||||
}
|
@ -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()),
|
||||
),
|
||||
})
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue