23 template <
typename IT>
29 Node(
const std::vector<int> &triangleIndices,
30 const size_t nTriangles,
44 const std::shared_ptr<Node> &left,
45 const std::shared_ptr<Node> &right) {
50 m_minX = std::min(left->m_minX, right->m_minX);
51 m_minY = std::min(left->m_minY, right->m_minY);
52 m_minZ = std::min(left->m_minZ, right->m_minZ);
53 m_maxX = std::max(left->m_maxX, right->m_maxX);
54 m_maxY = std::max(left->m_maxY, right->m_maxY);
55 m_maxZ = std::max(left->m_maxZ, right->m_maxZ);
76 void init(
const int &index,
77 const float ¢roid_x,
78 const float ¢roid_y,
79 const float ¢roid_z,
98 const IT *connectivityList,
99 const size_t &nTriangles) {
100 std::vector<Triangle> triangles;
103 this->nodes =
buildTree(triangles, 0, nTriangles);
108 std::shared_ptr<Node>
109 buildTree(std::vector<Triangle> &triangles,
size_t start,
size_t end) {
111 float minX, minY, minZ;
112 float maxX, maxY, maxZ;
113 minX = minY = minZ = std::numeric_limits<float>::max();
114 maxX = maxY = maxZ = std::numeric_limits<float>::min();
115 for(
size_t i = start; i <
end; i++) {
117 minX = std::min(t.
m_minX, minX);
118 minY = std::min(t.
m_minY, minY);
119 minZ = std::min(t.
m_minZ, minZ);
121 maxX = std::max(t.
m_maxX, maxX);
122 maxY = std::max(t.
m_maxY, maxY);
123 maxZ = std::max(t.
m_maxZ, maxZ);
125 const int numberTriangles =
end - start;
126 if(numberTriangles == 1) {
127 const Triangle &t = triangles[start];
128 std::vector<int>
const indices = {t.
m_index};
131 return std::make_shared<Node>(indices, 1, pMin, pMax);
135 float cminX, cminY, cminZ;
136 float cmaxX, cmaxY, cmaxZ;
137 cminX = cminY = cminZ = std::numeric_limits<float>::max();
138 cmaxX = cmaxY = cmaxZ = std::numeric_limits<float>::min();
139 for(
size_t i = start; i <
end; i++) {
150 const float diffX = std::abs(cmaxX - cminX);
151 const float diffY = std::abs(cmaxY - cminY);
152 const float diffZ = std::abs(cmaxZ - cminZ);
153 const float maximumExtent = std::max({diffX, diffY, diffZ});
155 float minToCheck, maxToCheck;
156 if(maximumExtent == diffX) {
160 }
else if(maximumExtent == diffY) {
169 size_t const half = (start +
end) / 2;
171 if(minToCheck == maxToCheck) {
173 std::vector<int> triangleIndices;
174 for(
size_t i = start; i <
end; i++) {
175 triangleIndices.push_back(triangles[i].m_index);
177 float pMin[3] = {minX, minY, minZ};
178 float pMax[3] = {maxX, maxY, maxZ};
179 return std::make_shared<Node>(
180 triangleIndices, triangleIndices.size(), pMin, pMax);
183 std::nth_element(&triangles[start], &triangles[half],
184 &triangles[
end - 1] + 1,
200 return std::make_shared<Node>(axis,
buildTree(triangles, start, half),
209 const IT *connectivityList,
210 const size_t &nTriangles) {
211 triangles.resize(nTriangles);
212 for(
size_t ti = 0; ti < nTriangles; ti++) {
214 const IT v1 = connectivityList[ti * 3 + 0] * 3;
215 const IT v2 = connectivityList[ti * 3 + 1] * 3;
216 const IT v3 = connectivityList[ti * 3 + 2] * 3;
218 const float &x1 = coords[v1 + 0];
219 const float &x2 = coords[v2 + 0];
220 const float &x3 = coords[v3 + 0];
222 const float &y1 = coords[v1 + 1];
223 const float &y2 = coords[v2 + 1];
224 const float &y3 = coords[v3 + 1];
226 const float &z1 = coords[v1 + 2];
227 const float &z2 = coords[v2 + 2];
228 const float &z3 = coords[v3 + 2];
230 const float pMin[3] = {std::min({x1, x2, x3}), std::min({y1, y2, y3}),
231 std::min({z1, z2, z3})};
232 const float pMax[3] = {std::max({x1, x2, x3}), std::max({y1, y2, y3}),
233 std::max({z1, z2, z3})};
235 triangles[ti].init(ti, findCentroid(x1, x2, x3),
236 findCentroid(y1, y2, y3), findCentroid(z1, z2, z3),
247 const float *vertexCoords)
const {
248 constexpr float kEpsilon = 1e-8;
250 float v0v1[3], v0v2[3], pvec[3], tvec[3], qvec[3];
252 &vertexCoords[v0], &vertexCoords[v1], v0v1);
254 &vertexCoords[v0], &vertexCoords[v2], v0v2);
257 if(det > -kEpsilon && det < kEpsilon)
260 const float invDet = 1.0f / det;
264 if(u < 0.0 || u > 1.0)
269 if(v < 0.0 || u + v > 1.0)
281 const IT *connectivityList,
282 const float *vertexCoords,
285 std::vector<int> &triangles,
286 std::vector<float> &distances,
287 bool segmentIntersection =
false)
const {
289 float nearestTriangle = std::numeric_limits<float>::max();
290 std::stack<Node *> stack;
291 Node *node = &nodes.get()[0];
296 while(stack.size() != 0) {
305 int const triIdx = node->
indices[i];
307 IT v0 = connectivityList[triIdx * 3 + 0];
308 IT v1 = connectivityList[triIdx * 3 + 1];
309 IT v2 = connectivityList[triIdx * 3 + 2];
315 and (not segmentIntersection
318 triangles.emplace_back(triIdx);
321 *triangleIndex = triIdx;
330 stack.push(node->
m_right.get());
332 if(node->
m_left !=
nullptr) {
333 stack.push(node->
m_left.get());
342 const IT *connectivityList,
343 const float *vertexCoords,
346 bool segmentIntersection =
false)
const {
347 std::vector<int> triangles;
348 std::vector<float> distances;
349 return intersect(r, connectivityList, vertexCoords, triangleIndex,
350 distance, triangles, distances, segmentIntersection);
354 const IT *connectivityList,
355 const float *vertexCoords,
356 std::vector<int> &triangles,
357 std::vector<float> &distances,
358 bool segmentIntersection =
false)
const {
361 return intersect(r, connectivityList, vertexCoords, &triangleIndex,
362 &distance, triangles, distances, segmentIntersection);
370 std::swap(tmin, tmax);
376 std::swap(tymin, tymax);
378 if((tmin > tymax) || (tymin > tmax))
391 std::swap(tzmin, tzmax);
393 if((tmin > tzmax) || (tzmin > tmax))
406 std::shared_ptr<Node> nodes;
407 float findCentroid(
const float &v1,
const float &v2,
const float &v3) {
408 return (v1 + v2 + v3) / 3;
Acceleration structure for native ray tracer. Based on implementation described in Physically Based R...
int buildTriangleList(std::vector< Triangle > &triangles, const float *coords, const IT *connectivityList, const size_t &nTriangles)
bool MollerTrumbore(Ray &ray, const IT v0, const IT v1, const IT v2, const float *vertexCoords) const
bool intersect(Ray &r, const IT *connectivityList, const float *vertexCoords, std::vector< int > &triangles, std::vector< float > &distances, bool segmentIntersection=false) const
BoundingVolumeHierarchy(const float *coords, const IT *connectivityList, const size_t &nTriangles)
bool wasNodeHit(const Ray &r, Node *n) const
std::shared_ptr< Node > buildTree(std::vector< Triangle > &triangles, size_t start, size_t end)
bool intersect(Ray &r, const IT *connectivityList, const float *vertexCoords, int *triangleIndex, float *distance, bool segmentIntersection=false) const
~BoundingVolumeHierarchy()=default
bool intersect(Ray &r, const IT *connectivityList, const float *vertexCoords, int *triangleIndex, float *distance, std::vector< int > &triangles, std::vector< float > &distances, bool segmentIntersection=false) const
Data structure for a ray.
T dotProduct(const T *vA0, const T *vA1, const T *vB0, const T *vB1)
int subtractVectors(const T *a, const T *b, T *out, const int &dimension=3)
int crossProduct(const T *vA0, const T *vA1, const T *vB0, const T *vB1, std::array< T, 3 > &crossProduct)
T end(std::pair< T, T > &p)
std::shared_ptr< Node > m_left
std::shared_ptr< Node > m_right
Node(const int axis, const std::shared_ptr< Node > &left, const std::shared_ptr< Node > &right)
Node(const std::vector< int > &triangleIndices, const size_t nTriangles, const float *pMin, const float *pMax)
std::vector< int > indices
void init(const int &index, const float ¢roid_x, const float ¢roid_y, const float ¢roid_z, const float *pMin, const float *pMax)