Compare commits
No commits in common. "a0b79ee2fa0db63d6694818ff78833d6ae5a951f" and "5ba5aa5f5d0d9c3bd083067dbd45d6115c453067" have entirely different histories.
a0b79ee2fa
...
5ba5aa5f5d
44
rtiow/Cargo.lock
generated
44
rtiow/Cargo.lock
generated
@ -812,16 +812,6 @@ dependencies = [
|
|||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ctor"
|
|
||||||
version = "0.1.26"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
|
|
||||||
dependencies = [
|
|
||||||
"quote 1.0.23",
|
|
||||||
"syn 1.0.107",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ctr"
|
name = "ctr"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -895,12 +885,6 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "diff"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.8.1"
|
version = "0.8.1"
|
||||||
@ -1926,15 +1910,6 @@ version = "6.4.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "output_vt100"
|
|
||||||
version = "0.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
|
|
||||||
dependencies = [
|
|
||||||
"winapi 0.3.9",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owning_ref"
|
name = "owning_ref"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@ -2101,18 +2076,6 @@ version = "0.2.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pretty_assertions"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
|
|
||||||
dependencies = [
|
|
||||||
"ctor",
|
|
||||||
"diff",
|
|
||||||
"output_vt100",
|
|
||||||
"yansi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -2471,7 +2434,6 @@ dependencies = [
|
|||||||
"lazy_static 1.4.0",
|
"lazy_static 1.4.0",
|
||||||
"log 0.4.17",
|
"log 0.4.17",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"pretty_assertions",
|
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
@ -3733,9 +3695,3 @@ dependencies = [
|
|||||||
"winapi 0.2.8",
|
"winapi 0.2.8",
|
||||||
"winapi-build",
|
"winapi-build",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yansi"
|
|
||||||
version = "0.5.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
|
||||||
|
|||||||
@ -33,7 +33,6 @@ strum_macros = "0.24.3"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.4"
|
criterion = "0.4"
|
||||||
pretty_assertions = "1.3.0"
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
profile = ["cpuprofiler"]
|
profile = ["cpuprofiler"]
|
||||||
|
|||||||
@ -2,7 +2,7 @@ use std::fmt;
|
|||||||
|
|
||||||
use crate::{ray::Ray, vec3::Vec3};
|
use crate::{ray::Ray, vec3::Vec3};
|
||||||
|
|
||||||
#[derive(Default, Copy, Clone, PartialEq)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq)]
|
||||||
pub struct AABB {
|
pub struct AABB {
|
||||||
bounds: [Vec3; 2],
|
bounds: [Vec3; 2],
|
||||||
}
|
}
|
||||||
@ -29,25 +29,13 @@ fn max(x: f32, y: f32) -> f32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for AABB {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"AABB: <{} - {}> Vol: {}",
|
|
||||||
self.bounds[0],
|
|
||||||
self.bounds[1],
|
|
||||||
self.volume()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AABB {
|
impl AABB {
|
||||||
pub fn new<V: Into<Vec3>>(min: V, max: V) -> AABB {
|
pub fn new<V: Into<Vec3>>(min: V, max: V) -> AABB {
|
||||||
let min: Vec3 = min.into();
|
let min: Vec3 = min.into();
|
||||||
let max: Vec3 = max.into();
|
let max: Vec3 = max.into();
|
||||||
assert!(min.x <= max.x);
|
assert!(min.x < max.x);
|
||||||
assert!(min.y <= max.y);
|
assert!(min.y < max.y);
|
||||||
assert!(min.z <= max.z);
|
assert!(min.z < max.z);
|
||||||
AABB { bounds: [min, max] }
|
AABB { bounds: [min, max] }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,9 +167,6 @@ impl AABB {
|
|||||||
let tmin = max(max(vmin4.0, max(vmin4.1, vmin4.2)), t_min);
|
let tmin = max(max(vmin4.0, max(vmin4.1, vmin4.2)), t_min);
|
||||||
tmin <= tmax
|
tmin <= tmax
|
||||||
}
|
}
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
// TODO(wathiede): add NEON implementation.
|
|
||||||
self.hit2(r, t_min, t_max)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hit_fast(&self, r: Ray, _t_min: f32, _t_max: f32) -> bool {
|
pub fn hit_fast(&self, r: Ray, _t_min: f32, _t_max: f32) -> bool {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
/// Implementation based on blog post @
|
/// Implementation based on blog post @
|
||||||
/// https://jacco.ompf2.com/2022/04/13/how-to-build-a-bvh-part-1-basics/
|
/// https://jacco.ompf2.com/2022/04/13/how-to-build-a-bvh-part-1-basics/
|
||||||
use std::f32::EPSILON;
|
use std::f32::EPSILON;
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
use stl::STL;
|
use stl::STL;
|
||||||
|
|
||||||
@ -13,7 +12,7 @@ use crate::{
|
|||||||
vec3::{cross, dot, Vec3},
|
vec3::{cross, dot, Vec3},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
struct BVHNode {
|
struct BVHNode {
|
||||||
aabb: AABB,
|
aabb: AABB,
|
||||||
left_child: usize,
|
left_child: usize,
|
||||||
@ -27,21 +26,13 @@ impl BVHNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(Debug)]
|
||||||
pub struct Triangle {
|
pub struct Triangle {
|
||||||
centroid: Vec3,
|
centroid: Vec3,
|
||||||
verts: [Vec3; 3],
|
verts: [Vec3; 3],
|
||||||
}
|
}
|
||||||
impl fmt::Debug for Triangle {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
"Tri: <{}, {}, {}> @ {}",
|
|
||||||
self.verts[0], self.verts[1], self.verts[2], self.centroid
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct BVHTriangles<M>
|
pub struct BVHTriangles<M>
|
||||||
where
|
where
|
||||||
M: Material,
|
M: Material,
|
||||||
@ -51,56 +42,12 @@ where
|
|||||||
bvh_nodes: Vec<BVHNode>,
|
bvh_nodes: Vec<BVHNode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> fmt::Debug for BVHTriangles<M>
|
|
||||||
where
|
|
||||||
M: Material,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{} triangles", self.triangles.len())?;
|
|
||||||
if f.alternate() {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
for (i, t) in self.triangles.iter().enumerate() {
|
|
||||||
if f.alternate() {
|
|
||||||
write!(f, "\t")?;
|
|
||||||
}
|
|
||||||
write!(f, "{i:>3} {:?} ", t)?;
|
|
||||||
if f.alternate() {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if f.alternate() {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
for (i, n) in self.bvh_nodes.iter().enumerate() {
|
|
||||||
write!(f, "N[{i}] {n:?}")?;
|
|
||||||
if f.alternate() {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
let n = &self.bvh_nodes[i];
|
|
||||||
if n.is_leaf() {
|
|
||||||
for t_idx in n.first_prim..(n.first_prim + n.prim_count) {
|
|
||||||
if f.alternate() {
|
|
||||||
write!(f, "\t")?;
|
|
||||||
}
|
|
||||||
write!(f, "{:?} ", self.triangles[t_idx])?;
|
|
||||||
if f.alternate() {
|
|
||||||
writeln!(f)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const ROOT_NODE_IDX: usize = 0;
|
const ROOT_NODE_IDX: usize = 0;
|
||||||
impl<M> BVHTriangles<M>
|
impl<M> BVHTriangles<M>
|
||||||
where
|
where
|
||||||
M: Material,
|
M: Material,
|
||||||
{
|
{
|
||||||
pub fn new(stl: &STL, material: M) -> BVHTriangles<M> {
|
pub fn new(stl: &STL, material: M) -> BVHTriangles<M> {
|
||||||
let div3 = 1. / 3.;
|
|
||||||
let triangles: Vec<_> = stl
|
let triangles: Vec<_> = stl
|
||||||
.triangles
|
.triangles
|
||||||
.iter()
|
.iter()
|
||||||
@ -108,7 +55,7 @@ where
|
|||||||
let v0 = t.verts[0];
|
let v0 = t.verts[0];
|
||||||
let v1 = t.verts[1];
|
let v1 = t.verts[1];
|
||||||
let v2 = t.verts[2];
|
let v2 = t.verts[2];
|
||||||
let centroid = (v0 + v1 + v2) * div3;
|
let centroid = (v0 + v1 + v2) * 0.3333;
|
||||||
Triangle {
|
Triangle {
|
||||||
centroid,
|
centroid,
|
||||||
verts: [v0, v1, v2],
|
verts: [v0, v1, v2],
|
||||||
@ -133,7 +80,7 @@ where
|
|||||||
aabb: AABB::default(),
|
aabb: AABB::default(),
|
||||||
left_child: 0,
|
left_child: 0,
|
||||||
first_prim: 0,
|
first_prim: 0,
|
||||||
prim_count: self.triangles.len(),
|
prim_count: self.triangles.len() - 1,
|
||||||
};
|
};
|
||||||
self.bvh_nodes.push(root);
|
self.bvh_nodes.push(root);
|
||||||
self.update_node_bounds(ROOT_NODE_IDX);
|
self.update_node_bounds(ROOT_NODE_IDX);
|
||||||
@ -144,7 +91,7 @@ where
|
|||||||
let node = &mut self.bvh_nodes[node_idx];
|
let node = &mut self.bvh_nodes[node_idx];
|
||||||
let mut aabb_min: Vec3 = f32::MAX.into();
|
let mut aabb_min: Vec3 = f32::MAX.into();
|
||||||
let mut aabb_max: Vec3 = f32::MIN.into();
|
let mut aabb_max: Vec3 = f32::MIN.into();
|
||||||
for i in node.first_prim..(node.first_prim + node.prim_count) {
|
for i in node.first_prim..node.prim_count {
|
||||||
let leaf_tri = &self.triangles[i];
|
let leaf_tri = &self.triangles[i];
|
||||||
aabb_min = vec3::min(aabb_min, leaf_tri.verts[0]);
|
aabb_min = vec3::min(aabb_min, leaf_tri.verts[0]);
|
||||||
aabb_min = vec3::min(aabb_min, leaf_tri.verts[1]);
|
aabb_min = vec3::min(aabb_min, leaf_tri.verts[1]);
|
||||||
@ -164,7 +111,7 @@ where
|
|||||||
let node = &self.bvh_nodes[idx];
|
let node = &self.bvh_nodes[idx];
|
||||||
|
|
||||||
// Compute split plane and position.
|
// Compute split plane and position.
|
||||||
let extent = node.aabb.max() - node.aabb.min();
|
let extent = node.aabb.min() - node.aabb.max();
|
||||||
let axis = node.aabb.longest_axis();
|
let axis = node.aabb.longest_axis();
|
||||||
let split_pos = node.aabb.min()[axis] + extent[axis] * 0.5;
|
let split_pos = node.aabb.min()[axis] + extent[axis] * 0.5;
|
||||||
|
|
||||||
@ -221,37 +168,31 @@ where
|
|||||||
if !node.aabb.hit(r, t_min, t_max) {
|
if !node.aabb.hit(r, t_min, t_max) {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
//dbg!(&self);
|
|
||||||
|
|
||||||
if node.is_leaf() {
|
if node.is_leaf() {
|
||||||
return self
|
for tri in &self.triangles {
|
||||||
.triangles
|
if let Some(RayTriangleResult { t, p }) =
|
||||||
.iter()
|
ray_triangle_intersect_moller_trumbore(r, tri)
|
||||||
.map(|tri| {
|
{
|
||||||
if let Some(RayTriangleResult { t, p }) = intersect_tri(r, tri) {
|
//if let Some(RayTriangleResult { t, p }) = ray_triangle_intersect_geometric(r, tri) {
|
||||||
// We don't support UV (yet?).
|
// We don't support UV (yet?).
|
||||||
let uv = (0.5, 0.5);
|
let uv = (0.5, 0.5);
|
||||||
let v0 = tri.verts[0];
|
let v0 = tri.verts[0];
|
||||||
let v1 = tri.verts[1];
|
let v1 = tri.verts[1];
|
||||||
let v2 = tri.verts[2];
|
let v2 = tri.verts[2];
|
||||||
|
|
||||||
let v0v1 = v1 - v0;
|
let v0v1 = v1 - v0;
|
||||||
let v0v2 = v2 - v0;
|
let v0v2 = v2 - v0;
|
||||||
let normal = cross(v0v1, v0v2).unit_vector();
|
let normal = cross(v0v1, v0v2).unit_vector();
|
||||||
//println!("hit triangle {tri:?}");
|
return Some(HitRecord {
|
||||||
Some(HitRecord {
|
t,
|
||||||
t,
|
uv,
|
||||||
uv,
|
p,
|
||||||
p,
|
normal,
|
||||||
normal,
|
material: &self.material,
|
||||||
material: &self.material,
|
});
|
||||||
})
|
}
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter_map(|hr| hr)
|
|
||||||
.min_by(|a, b| a.t.partial_cmp(&b.t).unwrap());
|
|
||||||
} else {
|
} else {
|
||||||
let r1 = self.intersect_bvh(r, node.left_child, t_min, t_max);
|
let r1 = self.intersect_bvh(r, node.left_child, t_min, t_max);
|
||||||
let r2 = self.intersect_bvh(r, node.left_child + 1, t_min, t_max);
|
let r2 = self.intersect_bvh(r, node.left_child + 1, t_min, t_max);
|
||||||
@ -268,8 +209,26 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<M> Hit for BVHTriangles<M>
|
||||||
|
where
|
||||||
|
M: Material,
|
||||||
|
{
|
||||||
|
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
||||||
|
self.intersect_bvh(r, 0, t_min, t_max)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
||||||
|
Some(self.bvh_nodes[0].aabb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RayTriangleResult {
|
||||||
|
t: f32,
|
||||||
|
p: Vec3,
|
||||||
|
}
|
||||||
|
///
|
||||||
/// Based on https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection.html
|
/// Based on https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection.html
|
||||||
fn intersect_tri(r: Ray, tri: &Triangle) -> Option<RayTriangleResult> {
|
fn ray_triangle_intersect_moller_trumbore(r: Ray, tri: &Triangle) -> Option<RayTriangleResult> {
|
||||||
// #ifdef MOLLER_TRUMBORE
|
// #ifdef MOLLER_TRUMBORE
|
||||||
// Vec3f v0v1 = v1 - v0;
|
// Vec3f v0v1 = v1 - v0;
|
||||||
// Vec3f v0v2 = v2 - v0;
|
// Vec3f v0v2 = v2 - v0;
|
||||||
@ -303,7 +262,7 @@ fn intersect_tri(r: Ray, tri: &Triangle) -> Option<RayTriangleResult> {
|
|||||||
let v0v2 = v2 - v0;
|
let v0v2 = v2 - v0;
|
||||||
let p = cross(r.direction, v0v2);
|
let p = cross(r.direction, v0v2);
|
||||||
let det = dot(v0v1, p);
|
let det = dot(v0v1, p);
|
||||||
if det.abs() < EPSILON {
|
if det < EPSILON {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,97 +290,17 @@ fn intersect_tri(r: Ray, tri: &Triangle) -> Option<RayTriangleResult> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M> Hit for BVHTriangles<M>
|
|
||||||
where
|
|
||||||
M: Material,
|
|
||||||
{
|
|
||||||
fn hit(&self, r: Ray, t_min: f32, t_max: f32) -> Option<HitRecord> {
|
|
||||||
self.intersect_bvh(r, 0, t_min, t_max)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bounding_box(&self, _t_min: f32, _t_max: f32) -> Option<AABB> {
|
|
||||||
Some(self.bvh_nodes[0].aabb)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RayTriangleResult {
|
|
||||||
t: f32,
|
|
||||||
p: Vec3,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bvh_triangles::BVHTriangles,
|
bvh_triangles::BVHTriangles, cuboid::Cuboid, hitable::Hit, material::Dielectric, ray::Ray,
|
||||||
cuboid::Cuboid,
|
|
||||||
hitable::Hit,
|
|
||||||
material::{Dielectric, Lambertian},
|
|
||||||
ray::Ray,
|
|
||||||
texture::ConstantTexture,
|
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use std::{
|
use std::{
|
||||||
io::{BufReader, Cursor},
|
io::{BufReader, Cursor},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use stl::STL;
|
use stl::STL;
|
||||||
|
|
||||||
/*
|
|
||||||
#[test]
|
|
||||||
fn build_bvh() {
|
|
||||||
let stl_triangles: Vec<_> = (0..4)
|
|
||||||
.flat_map(|y| {
|
|
||||||
(0..2).map(move |x| {
|
|
||||||
let x = x as f32;
|
|
||||||
let y = y as f32;
|
|
||||||
stl::Triangle {
|
|
||||||
normal: [1., 0., 0.].into(),
|
|
||||||
verts: [
|
|
||||||
[2. * x + 0., 2. * y + 0., 0.].into(),
|
|
||||||
[2. * x + 1., 2. * y + 0., 0.].into(),
|
|
||||||
[2. * x + 1., 2. * y + 1., 0.].into(),
|
|
||||||
],
|
|
||||||
attr: 0,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let stl = STL {
|
|
||||||
header: [0; 80],
|
|
||||||
triangles: stl_triangles,
|
|
||||||
};
|
|
||||||
/*
|
|
||||||
let mut bvh_triangles: Vec<_> = stl_triangles
|
|
||||||
.iter()
|
|
||||||
.map(|tri| {
|
|
||||||
let div3 = 1. / 3.;
|
|
||||||
let v0 = tri.verts[0];
|
|
||||||
let v1 = tri.verts[1];
|
|
||||||
let v2 = tri.verts[2];
|
|
||||||
let centroid = (v0 + v1 + v2) * div3;
|
|
||||||
Triangle {
|
|
||||||
centroid,
|
|
||||||
verts: tri.verts,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
bvh_triangles.sort_by(|a, b| a.centroid.y.partial_cmp(&b.centroid.y).unwrap());
|
|
||||||
let material = Lambertian::new(ConstantTexture::new([0., 0., 0.]));
|
|
||||||
let bvh_nodes = Default::default();
|
|
||||||
let want = BVHTriangles {
|
|
||||||
triangles: bvh_triangles,
|
|
||||||
bvh_nodes,
|
|
||||||
material,
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
let material = Lambertian::new(ConstantTexture::new([0., 0., 0.]));
|
|
||||||
let bvh = BVHTriangles::new(&stl, material);
|
|
||||||
dbg!(&bvh);
|
|
||||||
assert_eq!(bvh.bvh_nodes.len(), 2 * bvh.triangles.len() - 2);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compare_cuboid() {
|
fn compare_cuboid() {
|
||||||
let c = Cuboid::new(
|
let c = Cuboid::new(
|
||||||
@ -441,78 +320,32 @@ mod tests {
|
|||||||
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
|
//Metal::new(Vec3::new(0.8, 0.8, 0.8), 0.2),
|
||||||
//Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
|
//Lambertian::new(ConstantTexture::new(Vec3::new(1.0, 0.2, 0.2))),
|
||||||
);
|
);
|
||||||
//dbg!(&s);
|
let rays = [
|
||||||
let mut rays: Vec<_> = (1..20)
|
Ray::new([-1., 1., 1.], [1., 0., 0.], 0.),
|
||||||
.flat_map(|y| {
|
Ray::new([21., 1., 1.], [-1., 0., 0.], 0.),
|
||||||
(1..20).flat_map(move |x| {
|
Ray::new([1., -1., 1.], [0., 1., 0.], 0.),
|
||||||
let x = x as f32;
|
Ray::new([1., 21., 1.], [0., -1., 0.], 0.),
|
||||||
let y = y as f32;
|
Ray::new([1., 1., -1.], [0., 0., 1.], 0.),
|
||||||
vec![
|
Ray::new([1., 1., 21.], [0., 0., -1.], 0.),
|
||||||
// Outward in angle
|
// TODO more
|
||||||
Ray::new([-1., x, y], [1., 0., 0.], 0.),
|
];
|
||||||
Ray::new([21., x, y], [-1., 0., 0.], 0.),
|
|
||||||
Ray::new([x, -1., y], [0., 1., 0.], 0.),
|
|
||||||
Ray::new([x, 21., y], [0., -1., 0.], 0.),
|
|
||||||
Ray::new([x, y, -1.], [0., 0., 1.], 0.),
|
|
||||||
Ray::new([x, y, 21.], [0., 0., -1.], 0.),
|
|
||||||
// Inward out (
|
|
||||||
Ray::new([x, y, 10.], [1., 0., 0.], 0.),
|
|
||||||
Ray::new([x, y, 10.], [-1., 0., 0.], 0.),
|
|
||||||
Ray::new([x, 10., y], [1., 0., 0.], 0.),
|
|
||||||
Ray::new([x, 10., y], [-1., 0., 0.], 0.),
|
|
||||||
Ray::new([10., x, y], [1., 0., 0.], 0.),
|
|
||||||
Ray::new([10., x, y], [-1., 0., 0.], 0.),
|
|
||||||
Ray::new([x, y, 10.], [0., 1., 0.], 0.),
|
|
||||||
Ray::new([x, y, 10.], [0., -1., 0.], 0.),
|
|
||||||
Ray::new([x, 10., y], [0., 1., 0.], 0.),
|
|
||||||
Ray::new([x, 10., y], [0., -1., 0.], 0.),
|
|
||||||
Ray::new([10., x, y], [0., 1., 0.], 0.),
|
|
||||||
Ray::new([10., x, y], [0., -1., 0.], 0.),
|
|
||||||
Ray::new([x, y, 10.], [0., 0., 1.], 0.),
|
|
||||||
Ray::new([x, y, 10.], [0., 0., -1.], 0.),
|
|
||||||
Ray::new([x, 10., y], [0., 0., 1.], 0.),
|
|
||||||
Ray::new([x, 10., y], [0., 0., -1.], 0.),
|
|
||||||
Ray::new([10., x, y], [0., 0., 1.], 0.),
|
|
||||||
Ray::new([10., x, y], [0., 0., -1.], 0.),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
// These currently differ between STL and cuboid.
|
|
||||||
if false {
|
|
||||||
// Outward in at an angle.
|
|
||||||
let sqrt2 = 2f32.sqrt();
|
|
||||||
rays.extend(vec![
|
|
||||||
Ray::new([-1., 10., 10.], [sqrt2, sqrt2, 0.], 0.),
|
|
||||||
Ray::new([-1., 10., 10.], [sqrt2, -sqrt2, 0.], 0.),
|
|
||||||
Ray::new([-1., 10., 10.], [sqrt2, 0., sqrt2], 0.),
|
|
||||||
Ray::new([-1., 10., 10.], [sqrt2, 0., -sqrt2], 0.),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(wathiede): proptest this, it's still not perfectly equal when rendering.
|
for (i, r) in rays.into_iter().enumerate() {
|
||||||
|
let c_hit = c.hit(r, 0., f32::MAX).expect("c_hit missed");
|
||||||
for r in rays.into_iter() {
|
let s_hit = s.hit(r, 0., f32::MAX).expect("s_hit missed");
|
||||||
let c_hit = c
|
assert_eq!(
|
||||||
.hit(r, 0., f32::MAX)
|
c_hit.t, s_hit.t,
|
||||||
.expect(&format!("c_hit missed {r:#?}"));
|
"{i}: [t] c_hit: {c_hit:?}, s_hit: {s_hit:?}"
|
||||||
let s_hit = s
|
|
||||||
.hit(r, 0., f32::MAX)
|
|
||||||
.expect(&format!("s_hit missed {r:#?}"));
|
|
||||||
assert!(
|
|
||||||
(c_hit.t - s_hit.t).abs() < EPSILON,
|
|
||||||
"{r:?} [t] c_hit: {c_hit:#?}, s_hit: {s_hit:#?}"
|
|
||||||
);
|
);
|
||||||
// uv isn't valid for BVHTriangles.
|
// uv isn't valid for BVHTriangles.
|
||||||
// assert_eq!( c_hit.uv, s_hit.uv, "{i}: [uv] c_hit: {c_hit:?}, s_hit: {s_hit:?}");
|
// assert_eq!( c_hit.uv, s_hit.uv, "{i}: [uv] c_hit: {c_hit:?}, s_hit: {s_hit:?}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c_hit.p, s_hit.p,
|
c_hit.p, s_hit.p,
|
||||||
"{r:?}: [p] c_hit: {c_hit:#?}, s_hit: {s_hit:#?}"
|
"{i}: [p] c_hit: {c_hit:?}, s_hit: {s_hit:?}"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
c_hit.normal, s_hit.normal,
|
c_hit.normal, s_hit.normal,
|
||||||
"{r:?}: [normal] c_hit: {c_hit:?}, s_hit: {s_hit:?}"
|
"{i}: [normal] c_hit: {c_hit:?}, s_hit: {s_hit:?}"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -251,20 +251,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DebugMaterial {}
|
|
||||||
|
|
||||||
impl Material for DebugMaterial {
|
|
||||||
fn scatter(&self, _r_in: &Ray, rec: &HitRecord) -> ScatterResponse {
|
|
||||||
let dir = Vec3::new(0., -1., -1.).unit_vector();
|
|
||||||
ScatterResponse {
|
|
||||||
scattered: Ray::new(rec.p, dir, 0.),
|
|
||||||
attenutation: [1., 1., 1.].into(),
|
|
||||||
reflected: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@ -501,8 +501,7 @@ fn render_worker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::io::Error> {
|
pub fn render(scene: Scene, output_dir: &Path) -> std::result::Result<(), std::io::Error> {
|
||||||
// Default to half the cores to disable hyperthreading.
|
let num_threads = scene.num_threads.unwrap_or_else(num_cpus::get);
|
||||||
let num_threads = scene.num_threads.unwrap_or_else(|| num_cpus::get() / 2);
|
|
||||||
let (pixel_req_tx, pixel_req_rx) = sync_channel(2 * num_threads);
|
let (pixel_req_tx, pixel_req_rx) = sync_channel(2 * num_threads);
|
||||||
let (pixel_resp_tx, pixel_resp_rx) = sync_channel(2 * num_threads);
|
let (pixel_resp_tx, pixel_resp_rx) = sync_channel(2 * num_threads);
|
||||||
|
|
||||||
|
|||||||
@ -102,7 +102,7 @@ impl From<[f32; 3]> for Vec3 {
|
|||||||
|
|
||||||
impl fmt::Display for Vec3 {
|
impl fmt::Display for Vec3 {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{:>6.2} {:>6.2} {:>6.2}", self.x, self.y, self.z)
|
write!(f, "{} {} {}", self.x, self.y, self.z)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user