1 /*---------------------------------------------------------------------------*\
5 * Copyright (C) 2011 by the OpenSG Forum *
9 * contact: dirk@opensg.org, gerrit.voss@vossg.org, jbehr@zgdv.de *
11 \*---------------------------------------------------------------------------*/
12 /*---------------------------------------------------------------------------*\
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. *
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. *
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. *
28 \*---------------------------------------------------------------------------*/
30 #include "OSGIntersectKDTree.h"
32 #include "OSGFastTriangleIterator.h"
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).
51 explicit BBox(const Pnt3f
&min
, const Pnt3f
&max
);
52 explicit BBox(const Pnt3f
&p0
,
56 void extendBy(const Pnt3f
&p
);
57 void extendBy(const BBox
&b
);
59 Real32
surface (void ) const;
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() )
77 BBox::BBox(const Pnt3f
&min
, const Pnt3f
&max
)
84 BBox::BBox(const Pnt3f
&p0
,
90 for(UInt32 i
= 0; i
< 3; ++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
;
124 BBox::extendBy(const Pnt3f
&p
)
126 for(UInt32 i
= 0; i
< 3; ++i
)
137 BBox::extendBy(const BBox
&b
)
139 for(UInt32 i
= 0; i
< 3; ++i
)
141 if(b
._min
[i
] < _min
[i
])
144 if(b
._max
[i
] > _max
[i
])
150 BBox::surface(void) const
152 Vec3f diag
= _max
- _min
;
154 return 2.f
* (diag
[0] * diag
[1] +
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.
168 const IntersectKDTreeNode
*_node
;
173 // =======================================================================
184 BoundEdge(Real32 pos
, UInt32 triIdx
, TypeE type
);
192 BoundEdge::BoundEdge(void)
200 BoundEdge::BoundEdge(Real32 pos
, UInt32 triIdx
, TypeE type
)
208 operator<(const BoundEdge
&lhs
, const BoundEdge
&rhs
)
212 if(lhs
._pos
== rhs
._pos
)
214 result
= (lhs
._type
< rhs
._type
);
218 result
= (lhs
._pos
< rhs
._pos
);
224 // =======================================================================
226 // BuildState - keeps a bunch of "global" variables for buildTree() and
227 // avoids passing them as individual arguments.
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
;
255 BuildState(const BuildState
&other
);
256 void operator =(const BuildState
&rhs
);
259 // =======================================================================
261 // recursively constructs a KDTree
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
||
278 (*state
._mfNodes
)[currNode
].setLeaf(triCount
, state
._mfTriIndices
->size32());
280 for(UInt32 i
= 0; i
< triCount
; ++i
)
281 state
._mfTriIndices
->push_back(triIdx
[i
]);
286 // Choose split axis position for interior node
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
;
296 UInt32 axis
= d
.maxDim();
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
)
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
;
342 travCost
+ isectCost
* (1.f
- eb
) * (belowP
* belowCount
+
343 aboveP
* aboveCount
);
353 if(state
._edges
[axis
][i
]._type
== BoundEdge::EdgeStart
)
357 OSG_ASSERT(belowCount
== triCount
&& aboveCount
== 0);
359 // retry on pathological cases
360 if(bestAxis
== -1 && retries
< 2)
367 // split does not improve cost - accept and hope child nodes
369 if(bestCost
> oldCost
)
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) ||
378 (*state
._mfNodes
)[currNode
].setLeaf(triCount
, state
._mfTriIndices
->size32());
380 for(UInt32 i
= 0; i
< triCount
; ++i
)
381 state
._mfTriIndices
->push_back(triIdx
[i
]);
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)
429 doBuildSplitPlanePositions(const BBox
&bounds
,
430 const MFIntersectKDTreeNode
*mfNodes
,
433 GeoPnt3fProperty::StoredFieldType
*pnts
)
435 typedef IntersectKDTreeNode KDNode
;
437 const KDNode
*node
= &(*mfNodes
)[currNode
];
439 if(node
->isLeaf() || depth
== 0)
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
;
455 p
[axis0
] = bounds
._min
[axis0
];
456 p
[axis1
] = bounds
._min
[axis1
];
459 p
[axis0
] = bounds
._min
[axis0
];
460 p
[axis1
] = bounds
._max
[axis1
];
463 p
[axis0
] = bounds
._max
[axis0
];
464 p
[axis1
] = bounds
._max
[axis1
];
467 p
[axis0
] = bounds
._max
[axis0
];
468 p
[axis1
] = bounds
._min
[axis1
];
471 doBuildSplitPlanePositions(belowBounds
, mfNodes
,
472 currNode
+1, depth
-1, pnts
);
473 doBuildSplitPlanePositions(aboveBounds
, mfNodes
,
474 node
->getChildOffset(), depth
-1, pnts
);
479 /*! Builds a KDTree from geo by filling mfNodes and mfTriIndices.
480 If maxDepth is negative a suitable maximum depth is automatically
485 buildIntersectKDTree(Geometry
*geo
,
487 MFIntersectKDTreeNode
*mfNodes
,
488 MFUInt32
*mfTriIndices
)
491 FastTriangleIterator
triIt(geo
);
494 std::vector
<UInt32
> tris
;
498 mfTriIndices
->clear();
500 // record BBox for every triangle and overall volume
501 for(; !triIt
.isAtEnd(); ++triIt
)
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());
514 SWARNING
<< "buildIntersectKDTree: geometry does not contain any "
515 << "triangles, ignored."
522 state
._maxDepth
= osgRound2Int(8 + 1.3f
* osgLog2Int(triCount
));
526 state
._maxDepth
= maxDepth
;
529 for(UInt32 i
= 0; i
< 3; ++i
)
530 state
._edges
[i
].resize(2 * triCount
);
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(),
544 /*! Fills pnts with corners points of the split planes of the
545 KDTree with nodes mfNodes.
548 buildSplitPlanePositions(const BoxVolume
&bounds
,
549 const MFIntersectKDTreeNode
*mfNodes
,
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.
576 intersectIntersectKDTree(const Line
&ray
,
577 const BoxVolume
&bounds
,
579 const MFIntersectKDTreeNode
*mfNodes
,
580 const MFUInt32
*mfTriIndices
,
586 typedef IntersectKDTreeNode KDNode
;
588 const Pnt3f
&rayP
= ray
.getPosition ();
589 const Vec3f
&rayD
= ray
.getDirection();
591 // determine where ray enters/leaves bounding volume
595 if(bounds
.intersect(ray
, boundMinT
, boundMaxT
) == false)
598 boundMaxT
= osgMin(boundMaxT
, closestHitT
);
600 // keep track of relevant part of the ray that can intersect
602 // Real32 rayMinT = boundMinT - 10.f * Eps;
603 Real32 rayMaxT
= boundMaxT
+ 10.f
* Eps
;
604 Vec3f
invDir(1.f
/ rayD
[0],
608 const UInt32 maxItems
= 64;
610 TravItem items
[maxItems
];
611 FastTriangleIterator
triIt(geo
);
615 const KDNode
*node
= &(*mfNodes
)[0];
619 // stop if ray ends before current node bounds
620 if(rayMaxT
< boundMinT
)
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
);
638 child1
= &(*mfNodes
)[node
->getChildOffset()];
642 child0
= &(*mfNodes
)[node
->getChildOffset()];
646 if(splitT
> boundMaxT
|| splitT
<= 0.f
)
650 else if(splitT
< boundMinT
)
656 items
[currItem
]._node
= child1
;
657 items
[currItem
]._minT
= splitT
;
658 items
[currItem
]._maxT
= boundMaxT
;
668 UInt32 triCount
= node
->getTriCount ();
669 UInt32 triOffset
= node
->getTriOffset();
671 for(UInt32 i
= 0; i
< triCount
; ++i
)
673 UInt32 triIdx
= (*mfTriIndices
)[triOffset
+ i
];
680 if(ray
.intersect(triIt
.getPropertyValue
<Pnt3f
>(Geometry::PositionsIndex
, 0),
681 triIt
.getPropertyValue
<Pnt3f
>(Geometry::PositionsIndex
, 1),
682 triIt
.getPropertyValue
<Pnt3f
>(Geometry::PositionsIndex
, 2),
685 if(triT
>= 0.f
&& triT
< closestHitT
)
688 hitTriangle
= triIdx
;
695 // process todo items
700 node
= items
[currItem
]._node
;
701 boundMinT
= items
[currItem
]._minT
;
702 boundMaxT
= items
[currItem
]._maxT
;