Add generalized bvh for pbrt
This commit is contained in:
parent
807168f787
commit
6403aabc11
5 changed files with 360 additions and 43 deletions
|
|
@ -49,6 +49,14 @@ impl AABB {
|
||||||
self.max
|
self.max
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn center(self) -> Pos3 {
|
||||||
|
Pos3::new(
|
||||||
|
(self.min.x + self.max.x) * 0.5,
|
||||||
|
(self.min.y + self.max.y) * 0.5,
|
||||||
|
(self.min.z + self.max.z) * 0.5,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn contains_point(self, pos: Pos3) -> bool {
|
pub fn contains_point(self, pos: Pos3) -> bool {
|
||||||
self.min.x <= pos.x
|
self.min.x <= pos.x
|
||||||
&& pos.x <= self.max.x
|
&& pos.x <= self.max.x
|
||||||
|
|
|
||||||
182
ray-tracing-pbrt-scene/src/bvh.rs
Normal file
182
ray-tracing-pbrt-scene/src/bvh.rs
Normal file
|
|
@ -0,0 +1,182 @@
|
||||||
|
use ray_tracing_core::{aabb::AABB, prelude::*};
|
||||||
|
|
||||||
|
pub type Index = u32;
|
||||||
|
|
||||||
|
pub trait BvhData {
|
||||||
|
type Intersect: AsRef<Float>;
|
||||||
|
|
||||||
|
// fn get_slice(&mut self) -> &mut [Self::Sortable];
|
||||||
|
|
||||||
|
fn len(&self) -> Index;
|
||||||
|
|
||||||
|
fn sort_range_dim(&mut self, id: std::ops::Range<Index>, dim: u8);
|
||||||
|
|
||||||
|
fn get_aabb(&self, id: Index) -> AABB;
|
||||||
|
|
||||||
|
fn get_aabb_range(&self, id: std::ops::Range<Index>) -> AABB {
|
||||||
|
id.map(|i| self.get_aabb(i))
|
||||||
|
.reduce(|a, b| a.extend(b.min()).extend(b.max()))
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect(&self, id: Index, ray: Ray, min: Float, max: Float) -> Option<Self::Intersect>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Node {
|
||||||
|
Inner {
|
||||||
|
left: Index,
|
||||||
|
left_aabb: AABB,
|
||||||
|
right: Index,
|
||||||
|
right_aabb: AABB,
|
||||||
|
},
|
||||||
|
Leaf {
|
||||||
|
start: Index,
|
||||||
|
count: Index,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Bvh<T> {
|
||||||
|
data: T,
|
||||||
|
bvh: Vec<Node>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: BvhData> Bvh<T> {
|
||||||
|
pub fn new(mut data: T, min: Index) -> Self {
|
||||||
|
let len = data.len();
|
||||||
|
let mut bvh = vec![Node::Leaf {
|
||||||
|
start: 0,
|
||||||
|
count: len,
|
||||||
|
}];
|
||||||
|
|
||||||
|
let aabb = data.get_aabb_range(0..len);
|
||||||
|
|
||||||
|
Self::build_bvh(&mut data, &mut bvh, 0, aabb, min);
|
||||||
|
|
||||||
|
Self { data, bvh }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_bvh(data: &mut T, bvh: &mut Vec<Node>, node: usize, aabb: AABB, min: Index) {
|
||||||
|
let (start, count) = if let Node::Leaf { start, count } = bvh[node] {
|
||||||
|
(start, count)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if count <= min {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = aabb.size();
|
||||||
|
|
||||||
|
let dim = if size.x() > Float::max(size.y(), size.z()) {
|
||||||
|
0
|
||||||
|
} else if size.y() > Float::max(size.x(), size.z()) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
};
|
||||||
|
|
||||||
|
// sort
|
||||||
|
data.sort_range_dim(start..start + count, dim);
|
||||||
|
|
||||||
|
let mid = count / 2;
|
||||||
|
|
||||||
|
let left_aabb = data.get_aabb_range(start..(start + mid));
|
||||||
|
let right_aabb = data.get_aabb_range((start + mid)..(start + count));
|
||||||
|
|
||||||
|
let i = bvh.len() as Index;
|
||||||
|
bvh[node] = Node::Inner {
|
||||||
|
left: i,
|
||||||
|
left_aabb,
|
||||||
|
right: i + 1,
|
||||||
|
right_aabb,
|
||||||
|
};
|
||||||
|
bvh.push(Node::Leaf { start, count: mid });
|
||||||
|
bvh.push(Node::Leaf {
|
||||||
|
start: start + mid,
|
||||||
|
count: count - mid,
|
||||||
|
});
|
||||||
|
|
||||||
|
Self::build_bvh(data, bvh, i as usize, left_aabb, min);
|
||||||
|
Self::build_bvh(data, bvh, i as usize + 1, right_aabb, min);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect_inner(
|
||||||
|
&self,
|
||||||
|
node: Index,
|
||||||
|
ray: Ray,
|
||||||
|
min: Float,
|
||||||
|
max: Float,
|
||||||
|
) -> Option<T::Intersect> {
|
||||||
|
match self.bvh[node as usize] {
|
||||||
|
Node::Inner {
|
||||||
|
left,
|
||||||
|
left_aabb,
|
||||||
|
right,
|
||||||
|
right_aabb,
|
||||||
|
} => {
|
||||||
|
let left_intersect = left_aabb.intersect_ray(ray, min, max);
|
||||||
|
let right_intersect = right_aabb.intersect_ray(ray, min, max);
|
||||||
|
|
||||||
|
match (left_intersect, right_intersect) {
|
||||||
|
(None, None) => None,
|
||||||
|
(None, Some(_)) => self.intersect_inner(right, ray, min, max),
|
||||||
|
(Some(_), None) => self.intersect_inner(left, ray, min, max),
|
||||||
|
(Some(l), Some(r)) => {
|
||||||
|
let close;
|
||||||
|
let far;
|
||||||
|
if l < r {
|
||||||
|
close = left;
|
||||||
|
far = right;
|
||||||
|
} else {
|
||||||
|
close = right;
|
||||||
|
far = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(close_intersect) = self.intersect_inner(close, ray, min, max) {
|
||||||
|
if let Some(far_intersect) = self
|
||||||
|
.intersect_inner(
|
||||||
|
far,
|
||||||
|
ray,
|
||||||
|
min,
|
||||||
|
Float::min(max, *close_intersect.as_ref()),
|
||||||
|
)
|
||||||
|
.filter(|far_intersect| {
|
||||||
|
*far_intersect.as_ref() < *close_intersect.as_ref()
|
||||||
|
})
|
||||||
|
{
|
||||||
|
Some(far_intersect)
|
||||||
|
} else {
|
||||||
|
Some(close_intersect)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.intersect_inner(far, ray, min, max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Node::Leaf { start, count } => {
|
||||||
|
let mut intersection = None;
|
||||||
|
for i in start..(start + count) {
|
||||||
|
if let Some(t) = self.data.intersect(i, ray, min, max)
|
||||||
|
&& min <= *t.as_ref()
|
||||||
|
&& *t.as_ref() <= max
|
||||||
|
&& !intersection.as_ref().is_some_and(
|
||||||
|
|old_t: &<T as BvhData>::Intersect| *t.as_ref() > *old_t.as_ref(),
|
||||||
|
)
|
||||||
|
{
|
||||||
|
intersection.replace(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intersection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn intersect(&self, ray: Ray, min: Float, max: Float) -> Option<T::Intersect> {
|
||||||
|
self.intersect_inner(0, ray, min, max)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
|
bvh::Bvh,
|
||||||
either::Either,
|
either::Either,
|
||||||
scene::PbrtScene,
|
scene::PbrtScene,
|
||||||
shape::{Shape, ShapeAlpha, ShapeType},
|
shape::{Shape, ShapeAlpha, ShapeType, TriangleMesh},
|
||||||
tokenizer::{Token, Tokenizer},
|
tokenizer::{Token, Tokenizer},
|
||||||
};
|
};
|
||||||
use material::PbrtMaterial;
|
use material::PbrtMaterial;
|
||||||
|
|
@ -23,6 +24,7 @@ use texture::PbrtTexture;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
||||||
|
mod bvh;
|
||||||
mod either;
|
mod either;
|
||||||
mod error;
|
mod error;
|
||||||
mod material;
|
mod material;
|
||||||
|
|
@ -151,14 +153,14 @@ fn parse_shape<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
|
||||||
n, Vec<Dir3>, Vec::new();
|
n, Vec<Dir3>, Vec::new();
|
||||||
s, Vec<Dir3>, Vec::new();
|
s, Vec<Dir3>, Vec::new();
|
||||||
uv, Vec<[Float; 2]>, Vec::new();
|
uv, Vec<[Float; 2]>, Vec::new();
|
||||||
indices, Vec<usize>, Vec::new();
|
indices, Vec<[usize;3]>, Vec::new();
|
||||||
alpha, ShapeAlpha, ShapeAlpha::None
|
alpha, ShapeAlpha, ShapeAlpha::None
|
||||||
=>
|
=>
|
||||||
p, "point3 P", iter.parse_list_3(Pos3::new)?;
|
p, "point3 P", iter.parse_list_3(Pos3::new)?;
|
||||||
n, "normal N", iter.parse_list_3(Dir3::new)?;
|
n, "normal N", iter.parse_list_3(Dir3::new)?;
|
||||||
s, "normal S", iter.parse_list_3(Dir3::new)?;
|
s, "normal S", iter.parse_list_3(Dir3::new)?;
|
||||||
uv, "point2 uv", iter.parse_list_2(|u, v| [u, v])?;
|
uv, "point2 uv", iter.parse_list_2(|u, v| [u, v])?;
|
||||||
indices, "integer indices", iter.parse_list()?;
|
indices, "integer indices", iter.parse_list_3(|a, b, c|[a, b, c])?;
|
||||||
alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?);
|
alpha, "float alpha", ShapeAlpha::Value(iter.parse_parameter()?);
|
||||||
alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?)
|
alpha, "texture alpha", ShapeAlpha::Texture(iter.parse_parameter()?)
|
||||||
);
|
);
|
||||||
|
|
@ -170,13 +172,6 @@ fn parse_shape<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
|
||||||
bail!("Indices required for trianglemesh with more than 3 points.")
|
bail!("Indices required for trianglemesh with more than 3 points.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.indices.len() % 3 != 0 {
|
|
||||||
bail!(
|
|
||||||
"number of indices must be divisible by 3. num indices: {}",
|
|
||||||
t.indices.len()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !t.n.is_empty() && t.n.len() != t.p.len() {
|
if !t.n.is_empty() && t.n.len() != t.p.len() {
|
||||||
bail!("Number of normals not equal to number of positions.")
|
bail!("Number of normals not equal to number of positions.")
|
||||||
}
|
}
|
||||||
|
|
@ -189,13 +184,16 @@ fn parse_shape<R>(iter: &mut Tokenizer) -> Result<Statement<R>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Statement::Shape(
|
Ok(Statement::Shape(
|
||||||
ShapeType::TriangleMesh {
|
ShapeType::TriangleMesh(Bvh::new(
|
||||||
indices: t.indices,
|
TriangleMesh {
|
||||||
p: t.p,
|
indices: t.indices,
|
||||||
n: t.n,
|
p: t.p,
|
||||||
s: t.s,
|
n: t.n,
|
||||||
uv: t.uv,
|
s: t.s,
|
||||||
},
|
uv: t.uv,
|
||||||
|
},
|
||||||
|
8,
|
||||||
|
)),
|
||||||
t.alpha,
|
t.alpha,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
@ -863,7 +861,7 @@ fn inner_parse_pbrt<R: Rng + std::fmt::Debug>(
|
||||||
|
|
||||||
// dbg!(context);
|
// dbg!(context);
|
||||||
|
|
||||||
Ok(dbg!(pbrt))
|
Ok(pbrt)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_pbrt_v4<R: Rng + std::fmt::Debug>(
|
pub fn parse_pbrt_v4<R: Rng + std::fmt::Debug>(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,13 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
|
use ray_tracing_core::{affine_transform::AffineTransform, prelude::*, scene::Intersection};
|
||||||
|
|
||||||
use crate::{AreaLight, either::Either, material::PbrtMaterial, scene::UVMaterial};
|
use crate::{
|
||||||
|
AreaLight,
|
||||||
|
bvh::{Bvh, BvhData},
|
||||||
|
either::Either,
|
||||||
|
material::PbrtMaterial,
|
||||||
|
scene::UVMaterial,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -21,6 +27,122 @@ pub(crate) enum ShapeAlpha {
|
||||||
Texture(String),
|
Texture(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) struct InnerIntersect {
|
||||||
|
t: Float,
|
||||||
|
n: Dir3,
|
||||||
|
u: Float,
|
||||||
|
v: Float,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Float> for InnerIntersect {
|
||||||
|
fn as_ref(&self) -> &Float {
|
||||||
|
&self.t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct TriangleMesh {
|
||||||
|
pub(crate) indices: Vec<[usize; 3]>,
|
||||||
|
pub(crate) p: Vec<Pos3>,
|
||||||
|
pub(crate) n: Vec<Dir3>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) s: Vec<Dir3>,
|
||||||
|
pub(crate) uv: Vec<[Float; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BvhData for TriangleMesh {
|
||||||
|
type Intersect = InnerIntersect;
|
||||||
|
|
||||||
|
fn len(&self) -> crate::bvh::Index {
|
||||||
|
self.indices.len() as crate::bvh::Index
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sort_range_dim(&mut self, id: std::ops::Range<crate::bvh::Index>, dim: u8) {
|
||||||
|
let get_key =
|
||||||
|
|t: &[usize; 3]| t.iter().map(|&v| self.p[v][dim as usize]).sum::<Float>() / 3.0;
|
||||||
|
self.indices[id.start as usize..id.end as usize]
|
||||||
|
.sort_by(|a, b| get_key(a).partial_cmp(&get_key(b)).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_aabb(&self, id: crate::bvh::Index) -> AABB {
|
||||||
|
let v = self.indices[id as usize];
|
||||||
|
|
||||||
|
AABB::new(self.p[v[0]], self.p[v[1]]).extend(self.p[v[2]])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intersect(
|
||||||
|
&self,
|
||||||
|
id: crate::bvh::Index,
|
||||||
|
ray: Ray,
|
||||||
|
min: Float,
|
||||||
|
max: Float,
|
||||||
|
) -> Option<Self::Intersect> {
|
||||||
|
let _ = max;
|
||||||
|
let _ = min;
|
||||||
|
let v = [
|
||||||
|
self.p[self.indices[id as usize][0]],
|
||||||
|
self.p[self.indices[id as usize][1]],
|
||||||
|
self.p[self.indices[id as usize][2]],
|
||||||
|
];
|
||||||
|
|
||||||
|
let e1 = v[1] - v[0];
|
||||||
|
let e2 = v[2] - v[0];
|
||||||
|
|
||||||
|
let ray_cross_e2 = Dir3::cross(ray.dir(), e2);
|
||||||
|
let det = e1.dot(ray_cross_e2);
|
||||||
|
|
||||||
|
if det > -f32::EPSILON && det < f32::EPSILON {
|
||||||
|
return None; // This ray is parallel to this triangle.
|
||||||
|
}
|
||||||
|
|
||||||
|
let inv_det = 1.0 / det;
|
||||||
|
let s = ray.start() - v[0];
|
||||||
|
let u = inv_det * s.dot(ray_cross_e2);
|
||||||
|
if !(0.0..=1.0).contains(&u) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let s_cross_e1 = s.cross(e1);
|
||||||
|
let v = inv_det * Dir3::dot(ray.dir(), s_cross_e1);
|
||||||
|
if v < 0.0 || u + v > 1.0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
// At this stage we can compute t to find out where the intersection point is on the line.
|
||||||
|
let t = inv_det * e2.dot(s_cross_e1);
|
||||||
|
|
||||||
|
if t > Float::EPSILON {
|
||||||
|
// ray intersection
|
||||||
|
let w = 1.0 - u - v;
|
||||||
|
Some(InnerIntersect {
|
||||||
|
t,
|
||||||
|
n: if self.n.is_empty() {
|
||||||
|
Dir3::cross(e1, e2)
|
||||||
|
} else {
|
||||||
|
w * self.n[self.indices[id as usize][0]]
|
||||||
|
+ u * self.n[self.indices[id as usize][1]]
|
||||||
|
+ v * self.n[self.indices[id as usize][2]]
|
||||||
|
},
|
||||||
|
u: if self.uv.is_empty() {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
w * self.uv[self.indices[id as usize][0]][0]
|
||||||
|
+ u * self.uv[self.indices[id as usize][1]][0]
|
||||||
|
+ v * self.uv[self.indices[id as usize][2]][0]
|
||||||
|
},
|
||||||
|
v: if self.uv.is_empty() {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
w * self.uv[self.indices[id as usize][0]][1]
|
||||||
|
+ u * self.uv[self.indices[id as usize][1]][1]
|
||||||
|
+ v * self.uv[self.indices[id as usize][2]][1]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// This means that there is a line intersection but not a ray intersection.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub(crate) enum ShapeType {
|
pub(crate) enum ShapeType {
|
||||||
|
|
@ -30,13 +152,7 @@ pub(crate) enum ShapeType {
|
||||||
zmax: Float,
|
zmax: Float,
|
||||||
phimax: Float,
|
phimax: Float,
|
||||||
},
|
},
|
||||||
TriangleMesh {
|
TriangleMesh(Bvh<TriangleMesh>),
|
||||||
indices: Vec<usize>,
|
|
||||||
p: Vec<Pos3>,
|
|
||||||
n: Vec<Dir3>,
|
|
||||||
s: Vec<Dir3>,
|
|
||||||
uv: Vec<[Float; 2]>,
|
|
||||||
},
|
|
||||||
BilinearMesh {
|
BilinearMesh {
|
||||||
indices: Vec<usize>,
|
indices: Vec<usize>,
|
||||||
p: Vec<Pos3>,
|
p: Vec<Pos3>,
|
||||||
|
|
@ -156,12 +272,7 @@ fn bilinear_intersection(
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Rng + std::fmt::Debug> Shape<R> {
|
impl<R: Rng + std::fmt::Debug> Shape<R> {
|
||||||
fn inner_intersect(
|
fn inner_intersect(&self, ray: Ray, min: Float, max: Float) -> Option<InnerIntersect> {
|
||||||
&self,
|
|
||||||
ray: Ray,
|
|
||||||
min: Float,
|
|
||||||
max: Float,
|
|
||||||
) -> Option<(Float, Dir3, Float, Float)> {
|
|
||||||
match &self.obj {
|
match &self.obj {
|
||||||
&ShapeType::Sphere {
|
&ShapeType::Sphere {
|
||||||
radius,
|
radius,
|
||||||
|
|
@ -213,11 +324,20 @@ impl<R: Rng + std::fmt::Debug> Shape<R> {
|
||||||
if phi < 0.0 {
|
if phi < 0.0 {
|
||||||
phi += 2.0 * FloatConsts::PI;
|
phi += 2.0 * FloatConsts::PI;
|
||||||
}
|
}
|
||||||
return Some((t, p.as_dir(), phi, Float::acos(p.z() / radius)));
|
Some(InnerIntersect {
|
||||||
|
t,
|
||||||
|
n: p.as_dir(),
|
||||||
|
u: phi,
|
||||||
|
v: Float::acos(p.z() / radius),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ShapeType::TriangleMesh { .. } => (),
|
ShapeType::TriangleMesh(bvh) => bvh.intersect(ray, min, max),
|
||||||
ShapeType::BilinearMesh {
|
ShapeType::BilinearMesh {
|
||||||
indices,
|
indices,
|
||||||
p,
|
p,
|
||||||
|
|
@ -228,15 +348,18 @@ impl<R: Rng + std::fmt::Debug> Shape<R> {
|
||||||
&& let Some((t, u, v)) =
|
&& let Some((t, u, v)) =
|
||||||
bilinear_intersection(ray, min, max, [p[0], p[1], p[2], p[3]])
|
bilinear_intersection(ray, min, max, [p[0], p[1], p[2], p[3]])
|
||||||
{
|
{
|
||||||
return Some((t, Dir3::new(0.0, 0.0, 1.0), u, v));
|
Some(InnerIntersect {
|
||||||
|
t,
|
||||||
|
n: Dir3::new(0.0, 0.0, 1.0),
|
||||||
|
u,
|
||||||
|
v,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ShapeType::LoopSubDiv { .. } => todo!(),
|
_ => None,
|
||||||
ShapeType::Disk { .. } => (),
|
|
||||||
ShapeType::PlyMesh { .. } => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
pub(crate) fn intersect(
|
pub(crate) fn intersect(
|
||||||
&'_ self,
|
&'_ self,
|
||||||
|
|
@ -247,10 +370,10 @@ impl<R: Rng + std::fmt::Debug> Shape<R> {
|
||||||
let ray = self.ctm.transform_ray(ray);
|
let ray = self.ctm.transform_ray(ray);
|
||||||
|
|
||||||
self.inner_intersect(ray, min, max)
|
self.inner_intersect(ray, min, max)
|
||||||
.map(|(t, normal, u, v)| {
|
.map(|InnerIntersect { t, n, u, v }| {
|
||||||
Intersection::new(
|
Intersection::new(
|
||||||
t,
|
t,
|
||||||
self.ctm.inverse_transform_normal(normal).normalize(),
|
self.ctm.inverse_transform_normal(n).normalize(),
|
||||||
self.material.get_a().map(|m| UVMaterial {
|
self.material.get_a().map(|m| UVMaterial {
|
||||||
u,
|
u,
|
||||||
v,
|
v,
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,13 @@ fn main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pbrt_filename) = &args.pbrt_filename {
|
if let Some(pbrt_filename) = &args.pbrt_filename {
|
||||||
let pbrt = parse_pbrt_v4(pbrt_filename).unwrap();
|
let pbrt = match parse_pbrt_v4(pbrt_filename) {
|
||||||
|
Ok(pbrt) => pbrt,
|
||||||
|
Err(e) => {
|
||||||
|
println!("{e:?}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let c = BasicCamera::from_look_at(
|
let c = BasicCamera::from_look_at(
|
||||||
args.width,
|
args.width,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue