115 lines
3.8 KiB
C++
115 lines
3.8 KiB
C++
#include <future>
|
|
#include <nori/octree.h>
|
|
#include <tbb/tbb.h>
|
|
|
|
NORI_NAMESPACE_BEGIN
|
|
|
|
|
|
Octree *Octree::build(BoundingBox3f *bbox, Mesh *mesh, std::vector<uint32_t> triangles, int recursionDepth) {
|
|
if (triangles.empty()) {
|
|
return nullptr;
|
|
}
|
|
if (triangles.size() <= 20 || recursionDepth > 10 || bbox->getVolume() < 0.001f) {
|
|
return new Octree(bbox, mesh, triangles);
|
|
}
|
|
|
|
auto m_F = mesh->getIndices();
|
|
auto m_V = mesh->getVertexPositions();
|
|
|
|
Octree *node = new Octree(bbox, mesh, std::vector<uint32_t>());
|
|
auto bMin = bbox->min;
|
|
auto w = bbox->max.x() - bMin.x();
|
|
auto h = bbox->max.y() - bMin.y();
|
|
auto d = bbox->max.z() - bMin.z();
|
|
auto w2 = w / 2.0f, h2 = h / 2.0f, d2 = d / 2.0f;
|
|
BoundingBox3f *newBboxes[8] = {
|
|
new BoundingBox3f(bMin + Vector3f(0, 0, 0), bMin + Vector3f(w2, h2, d2)),
|
|
new BoundingBox3f(bMin + Vector3f(w2, 0, 0), bMin + Vector3f(w, h2, d2)),
|
|
new BoundingBox3f(bMin + Vector3f(0, h2, 0), bMin + Vector3f(w2, h, d2)),
|
|
new BoundingBox3f(bMin + Vector3f(w2, h2, 0), bMin + Vector3f(w, h, d2)),
|
|
new BoundingBox3f(bMin + Vector3f(0, 0, d2), bMin + Vector3f(w2, h2, d)),
|
|
new BoundingBox3f(bMin + Vector3f(w2, 0, d2), bMin + Vector3f(w, h2, d)),
|
|
new BoundingBox3f(bMin + Vector3f(0, h2, d2), bMin + Vector3f(w2, h, d)),
|
|
new BoundingBox3f(bMin + Vector3f(w2, h2, d2), bMin + Vector3f(w, h, d))
|
|
};
|
|
|
|
std::vector<uint32_t> newTriangles[8];
|
|
BoundingBox3f triangleBbox;
|
|
for(int i = 0; i < 8; i++) {
|
|
newTriangles[i].reserve(triangles.size() / 8);
|
|
for (uint32_t idx : triangles) {
|
|
auto a = m_V.col(m_F(0, idx));
|
|
auto b = m_V.col(m_F(1, idx));
|
|
auto c = m_V.col(m_F(2, idx));
|
|
triangleBbox.min = a.cwiseMin(b).cwiseMin(c);
|
|
triangleBbox.max = a.cwiseMax(b).cwiseMax(c);
|
|
if (newBboxes[i]->overlaps(triangleBbox)) {
|
|
newTriangles[i].push_back(idx);
|
|
}
|
|
}
|
|
newTriangles[i].shrink_to_fit();
|
|
}
|
|
|
|
if (recursionDepth < 2) {
|
|
tbb::parallel_for(tbb::blocked_range<size_t>(0, 8), [&](const tbb::blocked_range<size_t> &range) {
|
|
for (size_t i = range.begin(); i != range.end(); ++i) {
|
|
node->children[i] = build(newBboxes[i], mesh, newTriangles[i], recursionDepth + 1);
|
|
}
|
|
});
|
|
} else {
|
|
for (int i = 0; i < 8; i++) {
|
|
node->children[i] = build(newBboxes[i], mesh, newTriangles[i], recursionDepth + 1);
|
|
}
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
|
|
uint32_t Octree::getIntersectingTriangle(Ray3f &ray, Intersection &its, bool shadowRay) {
|
|
float u, v, t;
|
|
uint32_t closestTriangle = -1;
|
|
uint32_t triangle;
|
|
|
|
if (triangles.empty()) {
|
|
std::sort(children.begin(), children.end(), [ray](Octree *a, Octree *b) {
|
|
if (a == nullptr) {
|
|
return false;
|
|
}
|
|
if (b == nullptr) {
|
|
return true;
|
|
}
|
|
return a->bbox->distanceTo(ray.o) < b->bbox->distanceTo(ray.o);
|
|
});
|
|
for (auto child : children) {
|
|
if (child == nullptr || !child->bbox->rayIntersect(ray)) {
|
|
continue;
|
|
}
|
|
triangle = child->getIntersectingTriangle(ray, its, shadowRay);
|
|
if (triangle != (uint32_t) -1) {
|
|
return triangle;
|
|
}
|
|
}
|
|
|
|
return closestTriangle;
|
|
}
|
|
|
|
for (auto triangle : triangles) {
|
|
if (mesh->rayIntersect(triangle, ray, u, v, t)) {
|
|
if (shadowRay) {
|
|
return triangle;
|
|
}
|
|
if (t < ray.maxt) {
|
|
ray.maxt = its.t = t;
|
|
its.uv = Point2f(u, v);
|
|
its.mesh = mesh;
|
|
closestTriangle = triangle;
|
|
}
|
|
}
|
|
}
|
|
|
|
return closestTriangle;
|
|
}
|
|
|
|
NORI_NAMESPACE_END
|