Add octree generation
This commit is contained in:
parent
c5732d64ad
commit
eca59ad82d
|
@ -28,3 +28,6 @@ x64
|
|||
|
||||
*.exr
|
||||
*.png
|
||||
.ccls-cache/
|
||||
|
||||
scenes/pa2/ajax.obj
|
||||
|
|
|
@ -54,6 +54,7 @@ add_executable(nori
|
|||
include/nori/emitter.h
|
||||
include/nori/mesh.h
|
||||
include/nori/object.h
|
||||
include/nori/octree.h
|
||||
include/nori/parser.h
|
||||
include/nori/proplist.h
|
||||
include/nori/ray.h
|
||||
|
@ -78,6 +79,7 @@ add_executable(nori
|
|||
src/mesh.cpp
|
||||
src/obj.cpp
|
||||
src/object.cpp
|
||||
src/octree.cpp
|
||||
src/parser.cpp
|
||||
src/perspective.cpp
|
||||
src/proplist.cpp
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <nori/mesh.h>
|
||||
#include <nori/octree.h>
|
||||
|
||||
NORI_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -65,9 +66,12 @@ public:
|
|||
*/
|
||||
bool rayIntersect(const Ray3f &ray, Intersection &its, bool shadowRay) const;
|
||||
|
||||
uint32_t getIntersectingTriangle(Octree *node, Ray3f &ray, Intersection &its, bool shadowRay = false) const;
|
||||
|
||||
private:
|
||||
Mesh *m_mesh = nullptr; ///< Mesh (only a single one for now)
|
||||
BoundingBox3f m_bbox; ///< Bounding box of the entire scene
|
||||
Octree *m_octree = nullptr; ///< Octree for the mesh
|
||||
};
|
||||
|
||||
NORI_NAMESPACE_END
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <nori/mesh.h>
|
||||
#include <vector>
|
||||
|
||||
NORI_NAMESPACE_BEGIN
|
||||
|
||||
class Octree {
|
||||
public:
|
||||
// Members
|
||||
BoundingBox3f *bbox;
|
||||
Mesh *mesh;
|
||||
std::vector<Octree*> children;
|
||||
std::vector<uint32_t> triangles;
|
||||
|
||||
// Methods
|
||||
explicit Octree(BoundingBox3f *bbox, Mesh *mesh, std::vector<uint32_t> triangles) : bbox(bbox), mesh(mesh), triangles(triangles) {
|
||||
children = std::vector<Octree*>(8, nullptr);
|
||||
}
|
||||
static Octree *build(BoundingBox3f *bbox, Mesh *mesh, std::vector<uint32_t> triangles, int recursionDepth = 0);
|
||||
|
||||
uint32_t getIntersectingTriangle(Ray3f &ray, Intersection &its, bool shadowRay);
|
||||
BoundingBox3f getBoundingBox() const { return *bbox; }
|
||||
};
|
||||
|
||||
NORI_NAMESPACE_END
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <nori/accel.h>
|
||||
#include <Eigen/Geometry>
|
||||
#include <chrono>
|
||||
|
||||
NORI_NAMESPACE_BEGIN
|
||||
|
||||
|
@ -29,32 +30,26 @@ void Accel::addMesh(Mesh *mesh) {
|
|||
}
|
||||
|
||||
void Accel::build() {
|
||||
/* Nothing to do here for now */
|
||||
auto triangles = std::vector<uint32_t>(m_mesh->getTriangleCount());
|
||||
for (uint32_t idx = 0; idx < m_mesh->getTriangleCount(); ++idx) {
|
||||
triangles[idx] = idx;
|
||||
}
|
||||
|
||||
cout << "Building octree" << endl;
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
m_octree = Octree::build(&m_bbox, m_mesh, triangles);
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - start);
|
||||
|
||||
std::cout << "Octree build took " << duration.count()/1000.0f << " s" << std::endl;
|
||||
}
|
||||
|
||||
bool Accel::rayIntersect(const Ray3f &ray_, Intersection &its, bool shadowRay) const {
|
||||
bool foundIntersection = false; // Was an intersection found so far?
|
||||
uint32_t f = (uint32_t) -1; // Triangle index of the closest intersection
|
||||
|
||||
Ray3f ray(ray_); /// Make a copy of the ray (we will need to update its '.maxt' value)
|
||||
|
||||
/* Brute force search through all triangles */
|
||||
for (uint32_t idx = 0; idx < m_mesh->getTriangleCount(); ++idx) {
|
||||
float u, v, t;
|
||||
if (m_mesh->rayIntersect(idx, ray, u, v, t)) {
|
||||
/* An intersection was found! Can terminate
|
||||
immediately if this is a shadow ray query */
|
||||
if (shadowRay)
|
||||
return true;
|
||||
ray.maxt = its.t = t;
|
||||
its.uv = Point2f(u, v);
|
||||
its.mesh = m_mesh;
|
||||
f = idx;
|
||||
foundIntersection = true;
|
||||
}
|
||||
}
|
||||
auto f = m_octree->getIntersectingTriangle(ray, its, shadowRay);
|
||||
bool found = f != (uint32_t) -1;
|
||||
|
||||
if (foundIntersection) {
|
||||
if (found && !shadowRay) {
|
||||
/* At this point, we now know that there is an intersection,
|
||||
and we know the triangle index of the closest such intersection.
|
||||
|
||||
|
@ -107,7 +102,7 @@ bool Accel::rayIntersect(const Ray3f &ray_, Intersection &its, bool shadowRay) c
|
|||
}
|
||||
}
|
||||
|
||||
return foundIntersection;
|
||||
return found;
|
||||
}
|
||||
|
||||
NORI_NAMESPACE_END
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
#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
|
Loading…
Reference in New Issue