changed: gcc8 base update
[opensg.git] / Source / System / NodeCores / Drawables / Geometry / Util / OSGIntersectKDTree.cpp
bloba34d4040aa944d6278b9653dd0bc57adb58e9789
1 /*---------------------------------------------------------------------------*\
2 * OpenSG *
3 * *
4 * *
5 * Copyright (C) 2011 by the OpenSG Forum *
6 * *
7 * www.opensg.org *
8 * *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
10 * *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
13 * License *
14 * *
15 * This library is free software; you can redistribute it and/or modify it *
16 * under the terms of the GNU Library General Public License as published *
17 * by the Free Software Foundation, version 2. *
18 * *
19 * This library is distributed in the hope that it will be useful, but *
20 * WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
22 * Library General Public License for more details. *
23 * *
24 * You should have received a copy of the GNU Library General Public *
25 * License along with this library; if not, write to the Free Software *
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
27 * *
28 \*---------------------------------------------------------------------------*/
30 #include "OSGIntersectKDTree.h"
32 #include "OSGFastTriangleIterator.h"
34 OSG_BEGIN_NAMESPACE
36 namespace
38 const Real32 travCost = 1.f;
39 const Real32 isectCost = 10.f;
40 const Real32 emptyBonus = 0.5f;
42 // =======================================================================
44 // BBox - axis aligned bounding box (simpler, slightly smaller than BoxVolume)
45 // if constructed from three points (a triangle) it never has
46 // zero extend in x,y, or z (see below).
48 struct BBox
50 explicit BBox(void );
51 explicit BBox(const Pnt3f &min, const Pnt3f &max);
52 explicit BBox(const Pnt3f &p0,
53 const Pnt3f &p1,
54 const Pnt3f &p2 );
56 void extendBy(const Pnt3f &p);
57 void extendBy(const BBox &b);
59 Real32 surface (void ) const;
61 Pnt3f _min;
62 Pnt3f _max;
65 /* explicit */ inline
66 BBox::BBox(void)
67 : _min(TypeTraits<Real32>::getMax(),
68 TypeTraits<Real32>::getMax(),
69 TypeTraits<Real32>::getMax() ),
70 _max(TypeTraits<Real32>::getMin(),
71 TypeTraits<Real32>::getMin(),
72 TypeTraits<Real32>::getMin() )
76 /* explicit */ inline
77 BBox::BBox(const Pnt3f &min, const Pnt3f &max)
78 : _min(min),
79 _max(max)
83 /* explicit */ inline
84 BBox::BBox(const Pnt3f &p0,
85 const Pnt3f &p1,
86 const Pnt3f &p2 )
87 : _min(p0),
88 _max(p0)
90 for(UInt32 i = 0; i < 3; ++i)
92 if(p1[i] < _min[i])
93 _min[i] = p1[i];
94 if(p1[i] > _max[i])
95 _max[i] = p1[i];
97 if(p2[i] < _min[i])
98 _min[i] = p2[i];
99 if(p2[i] > _max[i])
100 _max[i] = p2[i];
103 // We can not allow a bbox of zero extend in any dimension:
104 // When selecting the split position we sort end before start
105 // edges. If a BBox has zero extend in the split dimension
106 // the triangle is not included in any of the two child nodes.
107 // Sorting start before end edges could avoid that, but is results
108 // in triangles being unnecessarily contained in both children.
109 for(UInt32 i = 0; i < 3; ++i)
111 Real32 eps = TypeTraits<Real32>::getDefaultEps();
113 while(_max[i] - _min[i] <= TypeTraits<Real32>::getDefaultEps())
115 _min[i] = _min[i] - eps;
116 _max[i] = _max[i] + eps;
118 eps *= 2.f;
123 inline void
124 BBox::extendBy(const Pnt3f &p)
126 for(UInt32 i = 0; i < 3; ++i)
128 if(p[i] < _min[i])
129 _min[i] = p[i];
131 if(p[i] > _max[i])
132 _max[i] = p[i];
136 inline void
137 BBox::extendBy(const BBox &b)
139 for(UInt32 i = 0; i < 3; ++i)
141 if(b._min[i] < _min[i])
142 _min[i] = b._min[i];
144 if(b._max[i] > _max[i])
145 _max[i] = b._max[i];
149 inline Real32
150 BBox::surface(void) const
152 Vec3f diag = _max - _min;
154 return 2.f * (diag[0] * diag[1] +
155 diag[0] * diag[2] +
156 diag[1] * diag[2] );
159 typedef std::vector<BBox> BBoxStore;
161 // =======================================================================
163 // TravItem - used during KDTree traversal to keep track of nodes that
164 // still need to be visited.
166 struct TravItem
168 const IntersectKDTreeNode *_node;
169 Real32 _minT;
170 Real32 _maxT;
173 // =======================================================================
175 struct BoundEdge
177 enum TypeE
179 EdgeStart = 1,
180 EdgeEnd = 0
183 BoundEdge(void );
184 BoundEdge(Real32 pos, UInt32 triIdx, TypeE type);
186 Real32 _pos;
187 UInt32 _triIdx;
188 TypeE _type;
191 inline
192 BoundEdge::BoundEdge(void)
193 : _pos (),
194 _triIdx(),
195 _type (EdgeStart)
199 inline
200 BoundEdge::BoundEdge(Real32 pos, UInt32 triIdx, TypeE type)
201 : _pos (pos),
202 _triIdx(triIdx),
203 _type (type)
207 inline bool
208 operator<(const BoundEdge &lhs, const BoundEdge &rhs)
210 bool result;
212 if(lhs._pos == rhs._pos)
214 result = (lhs._type < rhs._type);
216 else
218 result = (lhs._pos < rhs._pos);
221 return result;
224 // =======================================================================
226 // BuildState - keeps a bunch of "global" variables for buildTree() and
227 // avoids passing them as individual arguments.
229 struct BuildState
231 UInt32 _maxDepth;
232 UInt32 _maxTri;
233 BBoxStore _triBounds;
235 std::vector<BoundEdge> _edges[3];
236 std::vector<UInt32 > _trisBelow;
237 std::vector<UInt32 > _trisAbove;
239 MFIntersectKDTreeNode *_mfNodes;
240 MFUInt32 *_mfTriIndices;
242 BuildState(void):
243 _maxDepth (0 ),
244 _maxTri (0 ),
245 _triBounds ( ),
246 _trisBelow ( ),
247 _trisAbove ( ),
248 _mfNodes (NULL),
249 _mfTriIndices(NULL)
253 private:
255 BuildState(const BuildState &other);
256 void operator =(const BuildState &rhs);
259 // =======================================================================
261 // recursively constructs a KDTree
263 void
264 buildTree(BuildState &state, const BBox &bounds,
265 UInt32 triCount, UInt32 *triIdx,
266 UInt32 *trisBelow, UInt32 *trisAbove,
267 UInt32 depth, UInt32 badRefines)
269 UInt32 currNode = state._mfNodes->size32();
271 state._mfNodes->push_back(IntersectKDTreeNode());
273 // create leaf if only few triangles are left or
274 // maxDepth is reached
275 if(triCount <= state._maxTri ||
276 depth == 0 )
278 (*state._mfNodes)[currNode].setLeaf(triCount, state._mfTriIndices->size32());
280 for(UInt32 i = 0; i < triCount; ++i)
281 state._mfTriIndices->push_back(triIdx[i]);
283 return;
286 // Choose split axis position for interior node
287 Int32 bestAxis = -1;
288 Int32 bestOffset = -1;
289 Real32 bestCost = TypeTraits<Real32>::getMax();
290 Real32 oldCost = isectCost * triCount;
291 Real32 totalSA = bounds.surface();
292 Real32 invTotalSA = 1.f / totalSA;
293 Vec3f d = bounds._max - bounds._min;
295 UInt32 retries = 0;
296 UInt32 axis = d.maxDim();
298 while(true)
300 // init edges and sort
301 for(UInt32 i = 0; i < triCount; ++i)
303 UInt32 ti = triIdx[i];
304 const BBox &bbox = state._triBounds[ti];
306 state._edges[axis][2*i ] = BoundEdge(bbox._min[axis], ti, BoundEdge::EdgeStart);
307 state._edges[axis][2*i + 1] = BoundEdge(bbox._max[axis], ti, BoundEdge::EdgeEnd );
310 std::sort(state._edges[axis].begin(),
311 state._edges[axis].begin() + 2 * triCount);
313 // find best split position along axis
314 UInt32 belowCount = 0;
315 UInt32 aboveCount = triCount;
317 for(UInt32 i = 0; i < 2 * triCount; ++i)
319 if(state._edges[axis][i]._type == BoundEdge::EdgeEnd)
320 --aboveCount;
322 Real32 edgeT = state._edges[axis][i]._pos;
324 if(edgeT > bounds._min[axis] &&
325 edgeT < bounds._max[axis] )
327 // compute cost for splitting here
328 UInt32 otherAxis0 = (axis + 1) % 3;
329 UInt32 otherAxis1 = (axis + 2) % 3;
331 Real32 belowSA = 2.f * (d[otherAxis0] * d[otherAxis1] +
332 (edgeT - bounds._min[axis]) *
333 (d[otherAxis0] + d[otherAxis1]));
334 Real32 aboveSA = 2.f * (d[otherAxis0] * d[otherAxis1] +
335 (bounds._max[axis] - edgeT) *
336 (d[otherAxis0] + d[otherAxis1]));
338 Real32 belowP = belowSA * invTotalSA;
339 Real32 aboveP = aboveSA * invTotalSA;
340 Real32 eb = (belowCount == 0 || aboveCount == 0) ? emptyBonus : 0.f;
341 Real32 cost =
342 travCost + isectCost * (1.f - eb) * (belowP * belowCount +
343 aboveP * aboveCount );
345 if(cost < bestCost)
347 bestCost = cost;
348 bestAxis = axis;
349 bestOffset = i;
353 if(state._edges[axis][i]._type == BoundEdge::EdgeStart)
354 ++belowCount;
357 OSG_ASSERT(belowCount == triCount && aboveCount == 0);
359 // retry on pathological cases
360 if(bestAxis == -1 && retries < 2)
362 ++retries;
363 axis = (axis+1) % 3;
364 continue;
367 // split does not improve cost - accept and hope child nodes
368 // can do better
369 if(bestCost > oldCost)
370 ++badRefines;
372 // accept bad split and create leaf for small number of triangles or
373 // if splitting does not improve cost
374 if((bestCost > 4.f * oldCost && triCount < 16) ||
375 bestAxis == -1 ||
376 badRefines >= 3 )
378 (*state._mfNodes)[currNode].setLeaf(triCount, state._mfTriIndices->size32());
380 for(UInt32 i = 0; i < triCount; ++i)
381 state._mfTriIndices->push_back(triIdx[i]);
383 return;
386 break;
389 // classify triangles with respect to split
390 UInt32 belowCount = 0;
391 UInt32 aboveCount = 0;
393 for(Int32 i = 0; i < bestOffset; ++i)
395 if(state._edges[bestAxis][i]._type == BoundEdge::EdgeStart)
396 trisBelow[belowCount++] = state._edges[bestAxis][i]._triIdx;
399 for(UInt32 i = bestOffset+1; i < 2 * triCount; ++i)
401 if(state._edges[bestAxis][i]._type == BoundEdge::EdgeEnd)
402 trisAbove[aboveCount++] = state._edges[bestAxis][i]._triIdx;
405 // recurse to child nodes
406 Real32 splitPos = state._edges[bestAxis][bestOffset]._pos;
407 BBox belowBounds = bounds;
408 BBox aboveBounds = bounds;
409 belowBounds._max[bestAxis] = splitPos;
410 aboveBounds._min[bestAxis] = splitPos;
412 // build tree for triangles below split plane
413 buildTree(state, belowBounds, belowCount,
414 trisBelow, trisBelow, trisAbove + triCount,
415 depth - 1, badRefines);
417 // initialize interior node
418 (*state._mfNodes)[currNode].setInterior(static_cast<IntersectKDTreeNode::FlagsE>(bestAxis),
419 state._mfNodes->size32(), splitPos);
421 // build tree for triangles above split plane
422 buildTree(state, aboveBounds, aboveCount,
423 trisAbove, trisBelow, trisAbove + triCount,
424 depth - 1, badRefines);
427 // Fills pnts with positions of split planes (to be rendered as GL_QUADS)
428 void
429 doBuildSplitPlanePositions(const BBox &bounds,
430 const MFIntersectKDTreeNode *mfNodes,
431 UInt32 currNode,
432 UInt32 depth,
433 GeoPnt3fProperty::StoredFieldType *pnts)
435 typedef IntersectKDTreeNode KDNode;
437 const KDNode *node = &(*mfNodes)[currNode];
439 if(node->isLeaf() || depth == 0)
440 return;
442 Real32 split = node->getSplit ();
443 UInt32 axisS = node->getSplitAxis();
444 UInt32 axis0 = (axisS + 1) % 3;
445 UInt32 axis1 = (axisS + 2) % 3;
447 BBox belowBounds = bounds;
448 BBox aboveBounds = bounds;
450 belowBounds._max[axisS] = split;
451 aboveBounds._min[axisS] = split;
453 Pnt3f p;
454 p[axisS] = split;
455 p[axis0] = bounds._min[axis0];
456 p[axis1] = bounds._min[axis1];
457 pnts->push_back(p);
459 p[axis0] = bounds._min[axis0];
460 p[axis1] = bounds._max[axis1];
461 pnts->push_back(p);
463 p[axis0] = bounds._max[axis0];
464 p[axis1] = bounds._max[axis1];
465 pnts->push_back(p);
467 p[axis0] = bounds._max[axis0];
468 p[axis1] = bounds._min[axis1];
469 pnts->push_back(p);
471 doBuildSplitPlanePositions(belowBounds, mfNodes,
472 currNode+1, depth-1, pnts );
473 doBuildSplitPlanePositions(aboveBounds, mfNodes,
474 node->getChildOffset(), depth-1, pnts);
477 } // namespace
479 /*! Builds a KDTree from geo by filling mfNodes and mfTriIndices.
480 If maxDepth is negative a suitable maximum depth is automatically
481 determined.
484 void
485 buildIntersectKDTree(Geometry *geo,
486 Int32 maxDepth,
487 MFIntersectKDTreeNode *mfNodes,
488 MFUInt32 *mfTriIndices)
490 BuildState state;
491 FastTriangleIterator triIt(geo);
493 UInt32 triCount = 0;
494 std::vector<UInt32> tris;
495 BBox bounds;
497 mfNodes ->clear();
498 mfTriIndices->clear();
500 // record BBox for every triangle and overall volume
501 for(; !triIt.isAtEnd(); ++triIt)
503 ++triCount;
504 tris .push_back(triIt.getIndex());
505 state._triBounds.push_back(
506 BBox(triIt.getPropertyValue<Pnt3f>(Geometry::PositionsIndex, 0),
507 triIt.getPropertyValue<Pnt3f>(Geometry::PositionsIndex, 1),
508 triIt.getPropertyValue<Pnt3f>(Geometry::PositionsIndex, 2) ));
509 bounds.extendBy(state._triBounds.back());
512 if(triCount == 0)
514 SWARNING << "buildIntersectKDTree: geometry does not contain any "
515 << "triangles, ignored."
516 << std::endl;
517 return;
520 if(maxDepth < 0)
522 state._maxDepth = osgRound2Int(8 + 1.3f * osgLog2Int(triCount));
524 else
526 state._maxDepth = maxDepth;
529 for(UInt32 i = 0; i < 3; ++i)
530 state._edges[i].resize(2 * triCount);
532 state._maxTri = 5;
533 state._trisBelow.resize( triCount);
534 state._trisAbove.resize((state._maxDepth+1) * triCount);
535 state._mfNodes = mfNodes;
536 state._mfTriIndices = mfTriIndices;
538 // call recursive build function
539 buildTree(state, bounds, triCount,
540 &tris.front(), &state._trisBelow.front(), &state._trisAbove.front(),
541 state._maxDepth, 0);
544 /*! Fills pnts with corners points of the split planes of the
545 KDTree with nodes mfNodes.
547 void
548 buildSplitPlanePositions(const BoxVolume &bounds,
549 const MFIntersectKDTreeNode *mfNodes,
550 UInt32 maxDepth,
551 GeoPnt3fProperty *pnts )
553 GeoPnt3fProperty::StoredFieldType *p = pnts->editFieldPtr();
555 BBox bbox(bounds.getMin(), bounds.getMax());
557 Vec3f diag = bbox._max - bbox._min;
558 diag[0] = osgMax(diag[0], 0.5f);
559 diag[1] = osgMax(diag[1], 0.5f);
560 diag[2] = osgMax(diag[2], 0.5f);
562 bbox._min -= 0.1f * diag;
563 bbox._max += 0.1f * diag;
565 doBuildSplitPlanePositions(bbox, mfNodes, 0, maxDepth, p);
568 /*! Returns if ray intersects geo using the KDTree described by
569 mfNodes and mfTriIndices to accelerate the test.
570 If there is an intersection closestHitT contains the distance
571 along the ray of the closest hit, hitNormal the normal
572 at the intersection point and hitTriangle the index of the
573 intersected triangle.
575 bool
576 intersectIntersectKDTree(const Line &ray,
577 const BoxVolume &bounds,
578 Geometry *geo,
579 const MFIntersectKDTreeNode *mfNodes,
580 const MFUInt32 *mfTriIndices,
581 Real32 &closestHitT,
582 Vec3f &hitNormal,
583 UInt32 &hitTriangle,
584 UInt32 *numTris )
586 typedef IntersectKDTreeNode KDNode;
588 const Pnt3f &rayP = ray.getPosition ();
589 const Vec3f &rayD = ray.getDirection();
591 // determine where ray enters/leaves bounding volume
592 Real32 boundMinT;
593 Real32 boundMaxT;
595 if(bounds.intersect(ray, boundMinT, boundMaxT) == false)
596 return false;
598 boundMaxT = osgMin(boundMaxT, closestHitT);
600 // keep track of relevant part of the ray that can intersect
601 // with the KDTree
602 // Real32 rayMinT = boundMinT - 10.f * Eps;
603 Real32 rayMaxT = boundMaxT + 10.f * Eps;
604 Vec3f invDir(1.f / rayD[0],
605 1.f / rayD[1],
606 1.f / rayD[2] );
608 const UInt32 maxItems = 64;
609 UInt32 currItem = 0;
610 TravItem items[maxItems];
611 FastTriangleIterator triIt(geo);
613 UInt32 triTests = 0;
614 bool hit = false;
615 const KDNode *node = &(*mfNodes)[0];
617 while(node != NULL)
619 // stop if ray ends before current node bounds
620 if(rayMaxT < boundMinT)
621 break;
623 if(!node->isLeaf())
625 // interior node
626 UInt32 axis = node->getSplitAxis();
627 Real32 splitT = (node->getSplit() - rayP[axis]) * invDir[axis];
629 const KDNode *child0;
630 const KDNode *child1;
632 bool belowFirst = (rayP[axis] < node->getSplit() ) ||
633 (rayP[axis] == node->getSplit() && rayD[axis] <= 0.f);
635 if(belowFirst)
637 child0 = node + 1;
638 child1 = &(*mfNodes)[node->getChildOffset()];
640 else
642 child0 = &(*mfNodes)[node->getChildOffset()];
643 child1 = node + 1;
646 if(splitT > boundMaxT || splitT <= 0.f)
648 node = child0;
650 else if(splitT < boundMinT)
652 node = child1;
654 else
656 items[currItem]._node = child1;
657 items[currItem]._minT = splitT;
658 items[currItem]._maxT = boundMaxT;
659 ++currItem;
661 node = child0;
662 boundMaxT = splitT;
665 else
667 // leaf node
668 UInt32 triCount = node->getTriCount ();
669 UInt32 triOffset = node->getTriOffset();
671 for(UInt32 i = 0; i < triCount; ++i)
673 UInt32 triIdx = (*mfTriIndices)[triOffset + i];
674 Real32 triT;
676 triIt.seek(triIdx);
678 ++triTests;
680 if(ray.intersect(triIt.getPropertyValue<Pnt3f>(Geometry::PositionsIndex, 0),
681 triIt.getPropertyValue<Pnt3f>(Geometry::PositionsIndex, 1),
682 triIt.getPropertyValue<Pnt3f>(Geometry::PositionsIndex, 2),
683 triT, &hitNormal ))
685 if(triT >= 0.f && triT < closestHitT)
687 hit = true;
688 hitTriangle = triIdx;
689 rayMaxT = triT;
690 closestHitT = triT;
695 // process todo items
696 if(currItem > 0)
698 --currItem;
700 node = items[currItem]._node;
701 boundMinT = items[currItem]._minT;
702 boundMaxT = items[currItem]._maxT;
704 else
706 break;
711 if(numTris != NULL)
712 *numTris = triTests;
714 return hit;
717 OSG_END_NAMESPACE