nori/src/octree.cpp

138 lines
4.3 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) {
auto node = new Octree(bbox, mesh);
if (triangles.size() <= 20 || recursionDepth > 6) {
node->setTriangles(triangles);
return node;
}
auto m_F = mesh->getIndices();
auto m_V = mesh->getVertexPositions();
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> childTriangles[8];
BoundingBox3f triangleBbox;
for(int i = 0; i < 8; i++) {
childTriangles[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)) {
childTriangles[i].push_back(idx);
}
}
childTriangles[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) {
if (childTriangles[i].empty()) {
node->children[i] = nullptr;
continue;
}
node->children[i] = build(newBboxes[i], mesh, childTriangles[i], recursionDepth + 1);
}
});
} else {
for (int i = 0; i < 8; i++) {
if (childTriangles[i].empty()) {
node->children[i] = nullptr;
continue;
}
node->children[i] = build(newBboxes[i], mesh, childTriangles[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;
Octree *tmpChildren[8];
double distances[8];
float nearT, farT;
int n = 0;
int i, j, k;
if (triangles.empty()) {
for (i = 0; i < 8; i++) {
if (children[i] == nullptr) {
continue;
}
if (!children[i]->bbox->rayIntersect(ray, nearT, farT)) {
continue;
}
for (j = 0; j < n; j++) {
if (farT >= distances[j]) {
continue;
}
for (k = n; k > j; k--) {
distances[k] = distances[k - 1];
tmpChildren[k] = tmpChildren[k - 1];
}
break;
}
distances[j] = farT;
tmpChildren[j] = children[i];
n++;
}
for (i = 0; i < n; i++) {
triangle = tmpChildren[i]->getIntersectingTriangle(ray, its, shadowRay);
if (triangle != (uint32_t) -1) {
return triangle;
}
}
return -1;
}
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