1 /*! \file gim_box_set.h
2 \author Francisco Leon Najera
5 This source file is part of GIMPACT Library.
7 For the latest info, see http://gimpact.sourceforge.net/
9 Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371.
10 email: projectileman@yahoo.com
13 This software is provided 'as-is', without any express or implied warranty.
14 In no event will the authors be held liable for any damages arising from the use of this software.
15 Permission is granted to anyone to use this software for any purpose,
16 including commercial applications, and to alter it and redistribute it freely,
17 subject to the following restrictions:
19 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
20 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
21 3. This notice may not be removed or altered from any source distribution.
23 #include "btGImpactBvh.h"
24 #include "LinearMath/btQuickprof.h"
26 #ifdef TRI_COLLISION_PROFILING
30 float g_accum_tree_collision_time = 0;
31 int g_count_traversing = 0;
34 void bt_begin_gim02_tree_time()
39 void bt_end_gim02_tree_time()
41 g_accum_tree_collision_time += g_tree_clock.getTimeMicroseconds();
45 //! Gets the average time in miliseconds of tree collisions
46 float btGImpactBvh::getAverageTreeCollisionTime()
48 if(g_count_traversing == 0) return 0;
50 float avgtime = g_accum_tree_collision_time;
51 avgtime /= (float)g_count_traversing;
53 g_accum_tree_collision_time = 0;
54 g_count_traversing = 0;
57 // float avgtime = g_count_traversing;
58 // g_count_traversing = 0;
63 #endif //TRI_COLLISION_PROFILING
65 /////////////////////// btBvhTree /////////////////////////////////
67 int btBvhTree::_calc_splitting_axis(
68 GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex)
73 btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
74 btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
75 int numIndices = endIndex-startIndex;
77 for (i=startIndex;i<endIndex;i++)
79 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
80 primitive_boxes[i].m_bound.m_min);
83 means *= (btScalar(1.)/(btScalar)numIndices);
85 for (i=startIndex;i<endIndex;i++)
87 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
88 primitive_boxes[i].m_bound.m_min);
89 btVector3 diff2 = center-means;
90 diff2 = diff2 * diff2;
93 variance *= (btScalar(1.)/ ((btScalar)numIndices-1) );
95 return variance.maxAxis();
99 int btBvhTree::_sort_and_calc_splitting_index(
100 GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex,
101 int endIndex, int splitAxis)
104 int splitIndex =startIndex;
105 int numIndices = endIndex - startIndex;
107 // average of centers
108 btScalar splitValue = 0.0f;
110 btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
111 for (i=startIndex;i<endIndex;i++)
113 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
114 primitive_boxes[i].m_bound.m_min);
117 means *= (btScalar(1.)/(btScalar)numIndices);
119 splitValue = means[splitAxis];
122 //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
123 for (i=startIndex;i<endIndex;i++)
125 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
126 primitive_boxes[i].m_bound.m_min);
127 if (center[splitAxis] > splitValue)
130 primitive_boxes.swap(i,splitIndex);
131 //swapLeafNodes(i,splitIndex);
136 //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
137 //otherwise the tree-building might fail due to stack-overflows in certain cases.
138 //unbalanced1 is unsafe: it can cause stack overflows
139 //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
141 //unbalanced2 should work too: always use center (perfect balanced trees)
142 //bool unbalanced2 = true;
144 //this should be safe too:
145 int rangeBalancedIndices = numIndices/3;
146 bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
150 splitIndex = startIndex+ (numIndices>>1);
153 btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
160 void btBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex)
162 int curIndex = m_num_nodes;
165 btAssert((endIndex-startIndex)>0);
167 if ((endIndex-startIndex)==1)
169 //We have a leaf node
170 setNodeBound(curIndex,primitive_boxes[startIndex].m_bound);
171 m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data);
175 //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
178 int splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
180 splitIndex = _sort_and_calc_splitting_index(
181 primitive_boxes,startIndex,endIndex,
182 splitIndex//split axis
186 //calc this node bounding box
189 node_bound.invalidate();
191 for (int i=startIndex;i<endIndex;i++)
193 node_bound.merge(primitive_boxes[i].m_bound);
196 setNodeBound(curIndex,node_bound);
200 _build_sub_tree(primitive_boxes, startIndex, splitIndex );
204 _build_sub_tree(primitive_boxes, splitIndex ,endIndex);
206 m_node_array[curIndex].setEscapeIndex(m_num_nodes - curIndex);
211 //! stackless build tree
212 void btBvhTree::build_tree(
213 GIM_BVH_DATA_ARRAY & primitive_boxes)
215 // initialize node count to 0
218 m_node_array.resize(primitive_boxes.size()*2);
220 _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
223 ////////////////////////////////////class btGImpactBvh
225 void btGImpactBvh::refit()
227 int nodecount = getNodeCount();
230 if(isLeafNode(nodecount))
233 m_primitive_manager->get_primitive_box(getNodeData(nodecount),leafbox);
234 setNodeBound(nodecount,leafbox);
238 //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount);
245 int child_node = getLeftNode(nodecount);
248 getNodeBound(child_node,temp_box);
249 bound.merge(temp_box);
252 child_node = getRightNode(nodecount);
255 getNodeBound(child_node,temp_box);
256 bound.merge(temp_box);
259 setNodeBound(nodecount,bound);
264 //! this rebuild the entire set
265 void btGImpactBvh::buildSet()
267 //obtain primitive boxes
268 GIM_BVH_DATA_ARRAY primitive_boxes;
269 primitive_boxes.resize(m_primitive_manager->get_primitive_count());
271 for (int i = 0;i<primitive_boxes.size() ;i++ )
273 m_primitive_manager->get_primitive_box(i,primitive_boxes[i].m_bound);
274 primitive_boxes[i].m_data = i;
277 m_box_tree.build_tree(primitive_boxes);
280 //! returns the indices of the primitives in the m_primitive_manager
281 bool btGImpactBvh::boxQuery(const btAABB & box, btAlignedObjectArray<int> & collided_results) const
284 int numNodes = getNodeCount();
286 while (curIndex < numNodes)
289 getNodeBound(curIndex,bound);
291 //catch bugs in tree data
293 bool aabbOverlap = bound.has_collision(box);
294 bool isleafnode = isLeafNode(curIndex);
296 if (isleafnode && aabbOverlap)
298 collided_results.push_back(getNodeData(curIndex));
301 if (aabbOverlap || isleafnode)
309 curIndex+= getEscapeNodeIndex(curIndex);
312 if(collided_results.size()>0) return true;
318 //! returns the indices of the primitives in the m_primitive_manager
319 bool btGImpactBvh::rayQuery(
320 const btVector3 & ray_dir,const btVector3 & ray_origin ,
321 btAlignedObjectArray<int> & collided_results) const
324 int numNodes = getNodeCount();
326 while (curIndex < numNodes)
329 getNodeBound(curIndex,bound);
331 //catch bugs in tree data
333 bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
334 bool isleafnode = isLeafNode(curIndex);
336 if (isleafnode && aabbOverlap)
338 collided_results.push_back(getNodeData( curIndex));
341 if (aabbOverlap || isleafnode)
349 curIndex+= getEscapeNodeIndex(curIndex);
352 if(collided_results.size()>0) return true;
357 SIMD_FORCE_INLINE bool _node_collision(
358 btGImpactBvh * boxset0, btGImpactBvh * boxset1,
359 const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0,
360 int node0 ,int node1, bool complete_primitive_tests)
363 boxset0->getNodeBound(node0,box0);
365 boxset1->getNodeBound(node1,box1);
367 return box0.overlapping_trans_cache(box1,trans_cache_1to0,complete_primitive_tests );
368 // box1.appy_transform_trans_cache(trans_cache_1to0);
369 // return box0.has_collision(box1);
374 //stackless recursive collision routine
375 static void _find_collision_pairs_recursive(
376 btGImpactBvh * boxset0, btGImpactBvh * boxset1,
377 btPairSet * collision_pairs,
378 const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0,
379 int node0, int node1, bool complete_primitive_tests)
385 boxset0,boxset1,trans_cache_1to0,
386 node0,node1,complete_primitive_tests) ==false) return;//avoid colliding internal nodes
388 if(boxset0->isLeafNode(node0))
390 if(boxset1->isLeafNode(node1))
393 collision_pairs->push_pair(
394 boxset0->getNodeData(node0),boxset1->getNodeData(node1));
400 //collide left recursive
402 _find_collision_pairs_recursive(
404 collision_pairs,trans_cache_1to0,
405 node0,boxset1->getLeftNode(node1),false);
407 //collide right recursive
408 _find_collision_pairs_recursive(
410 collision_pairs,trans_cache_1to0,
411 node0,boxset1->getRightNode(node1),false);
418 if(boxset1->isLeafNode(node1))
421 //collide left recursive
422 _find_collision_pairs_recursive(
424 collision_pairs,trans_cache_1to0,
425 boxset0->getLeftNode(node0),node1,false);
428 //collide right recursive
430 _find_collision_pairs_recursive(
432 collision_pairs,trans_cache_1to0,
433 boxset0->getRightNode(node0),node1,false);
439 //collide left0 left1
443 _find_collision_pairs_recursive(
445 collision_pairs,trans_cache_1to0,
446 boxset0->getLeftNode(node0),boxset1->getLeftNode(node1),false);
448 //collide left0 right1
450 _find_collision_pairs_recursive(
452 collision_pairs,trans_cache_1to0,
453 boxset0->getLeftNode(node0),boxset1->getRightNode(node1),false);
456 //collide right0 left1
458 _find_collision_pairs_recursive(
460 collision_pairs,trans_cache_1to0,
461 boxset0->getRightNode(node0),boxset1->getLeftNode(node1),false);
463 //collide right0 right1
465 _find_collision_pairs_recursive(
467 collision_pairs,trans_cache_1to0,
468 boxset0->getRightNode(node0),boxset1->getRightNode(node1),false);
470 }// else if node1 is not a leaf
471 }// else if node0 is not a leaf
475 void btGImpactBvh::find_collision(btGImpactBvh * boxset0, const btTransform & trans0,
476 btGImpactBvh * boxset1, const btTransform & trans1,
477 btPairSet & collision_pairs)
480 if(boxset0->getNodeCount()==0 || boxset1->getNodeCount()==0 ) return;
482 BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
484 trans_cache_1to0.calc_from_homogenic(trans0,trans1);
486 #ifdef TRI_COLLISION_PROFILING
487 bt_begin_gim02_tree_time();
488 #endif //TRI_COLLISION_PROFILING
490 _find_collision_pairs_recursive(
492 &collision_pairs,trans_cache_1to0,0,0,true);
493 #ifdef TRI_COLLISION_PROFILING
494 bt_end_gim02_tree_time();
495 #endif //TRI_COLLISION_PROFILING