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.
24 #include "btGImpactQuantizedBvh.h"
25 #include "LinearMath/btQuickprof.h"
27 #ifdef TRI_COLLISION_PROFILING
28 btClock g_q_tree_clock;
31 float g_q_accum_tree_collision_time = 0;
32 int g_q_count_traversing = 0;
35 void bt_begin_gim02_q_tree_time()
37 g_q_tree_clock.reset();
40 void bt_end_gim02_q_tree_time()
42 g_q_accum_tree_collision_time += g_q_tree_clock.getTimeMicroseconds();
43 g_q_count_traversing++;
47 //! Gets the average time in miliseconds of tree collisions
48 float btGImpactQuantizedBvh::getAverageTreeCollisionTime()
50 if(g_q_count_traversing == 0) return 0;
52 float avgtime = g_q_accum_tree_collision_time;
53 avgtime /= (float)g_q_count_traversing;
55 g_q_accum_tree_collision_time = 0;
56 g_q_count_traversing = 0;
59 // float avgtime = g_q_count_traversing;
60 // g_q_count_traversing = 0;
65 #endif //TRI_COLLISION_PROFILING
67 /////////////////////// btQuantizedBvhTree /////////////////////////////////
69 void btQuantizedBvhTree::calc_quantization(
70 GIM_BVH_DATA_ARRAY & primitive_boxes, btScalar boundMargin)
74 global_bound.invalidate();
76 for (int i=0;i<primitive_boxes.size() ;i++ )
78 global_bound.merge(primitive_boxes[i].m_bound);
81 bt_calc_quantization_parameters(
82 m_global_bound.m_min,m_global_bound.m_max,m_bvhQuantization,global_bound.m_min,global_bound.m_max,boundMargin);
88 int btQuantizedBvhTree::_calc_splitting_axis(
89 GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex)
94 btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
95 btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
96 int numIndices = endIndex-startIndex;
98 for (i=startIndex;i<endIndex;i++)
100 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
101 primitive_boxes[i].m_bound.m_min);
104 means *= (btScalar(1.)/(btScalar)numIndices);
106 for (i=startIndex;i<endIndex;i++)
108 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
109 primitive_boxes[i].m_bound.m_min);
110 btVector3 diff2 = center-means;
111 diff2 = diff2 * diff2;
114 variance *= (btScalar(1.)/ ((btScalar)numIndices-1) );
116 return variance.maxAxis();
120 int btQuantizedBvhTree::_sort_and_calc_splitting_index(
121 GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex,
122 int endIndex, int splitAxis)
125 int splitIndex =startIndex;
126 int numIndices = endIndex - startIndex;
128 // average of centers
129 btScalar splitValue = 0.0f;
131 btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
132 for (i=startIndex;i<endIndex;i++)
134 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
135 primitive_boxes[i].m_bound.m_min);
138 means *= (btScalar(1.)/(btScalar)numIndices);
140 splitValue = means[splitAxis];
143 //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
144 for (i=startIndex;i<endIndex;i++)
146 btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
147 primitive_boxes[i].m_bound.m_min);
148 if (center[splitAxis] > splitValue)
151 primitive_boxes.swap(i,splitIndex);
152 //swapLeafNodes(i,splitIndex);
157 //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
158 //otherwise the tree-building might fail due to stack-overflows in certain cases.
159 //unbalanced1 is unsafe: it can cause stack overflows
160 //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
162 //unbalanced2 should work too: always use center (perfect balanced trees)
163 //bool unbalanced2 = true;
165 //this should be safe too:
166 int rangeBalancedIndices = numIndices/3;
167 bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
171 splitIndex = startIndex+ (numIndices>>1);
174 btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
181 void btQuantizedBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex)
183 int curIndex = m_num_nodes;
186 btAssert((endIndex-startIndex)>0);
188 if ((endIndex-startIndex)==1)
190 //We have a leaf node
191 setNodeBound(curIndex,primitive_boxes[startIndex].m_bound);
192 m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data);
196 //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
199 int splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
201 splitIndex = _sort_and_calc_splitting_index(
202 primitive_boxes,startIndex,endIndex,
203 splitIndex//split axis
207 //calc this node bounding box
210 node_bound.invalidate();
212 for (int i=startIndex;i<endIndex;i++)
214 node_bound.merge(primitive_boxes[i].m_bound);
217 setNodeBound(curIndex,node_bound);
221 _build_sub_tree(primitive_boxes, startIndex, splitIndex );
225 _build_sub_tree(primitive_boxes, splitIndex ,endIndex);
227 m_node_array[curIndex].setEscapeIndex(m_num_nodes - curIndex);
232 //! stackless build tree
233 void btQuantizedBvhTree::build_tree(
234 GIM_BVH_DATA_ARRAY & primitive_boxes)
236 calc_quantization(primitive_boxes);
237 // initialize node count to 0
240 m_node_array.resize(primitive_boxes.size()*2);
242 _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
245 ////////////////////////////////////class btGImpactQuantizedBvh
247 void btGImpactQuantizedBvh::refit()
249 int nodecount = getNodeCount();
252 if(isLeafNode(nodecount))
255 m_primitive_manager->get_primitive_box(getNodeData(nodecount),leafbox);
256 setNodeBound(nodecount,leafbox);
260 //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount);
267 int child_node = getLeftNode(nodecount);
270 getNodeBound(child_node,temp_box);
271 bound.merge(temp_box);
274 child_node = getRightNode(nodecount);
277 getNodeBound(child_node,temp_box);
278 bound.merge(temp_box);
281 setNodeBound(nodecount,bound);
286 //! this rebuild the entire set
287 void btGImpactQuantizedBvh::buildSet()
289 //obtain primitive boxes
290 GIM_BVH_DATA_ARRAY primitive_boxes;
291 primitive_boxes.resize(m_primitive_manager->get_primitive_count());
293 for (int i = 0;i<primitive_boxes.size() ;i++ )
295 m_primitive_manager->get_primitive_box(i,primitive_boxes[i].m_bound);
296 primitive_boxes[i].m_data = i;
299 m_box_tree.build_tree(primitive_boxes);
302 //! returns the indices of the primitives in the m_primitive_manager
303 bool btGImpactQuantizedBvh::boxQuery(const btAABB & box, btAlignedObjectArray<int> & collided_results) const
306 int numNodes = getNodeCount();
310 unsigned short quantizedMin[3];
311 unsigned short quantizedMax[3];
313 m_box_tree.quantizePoint(quantizedMin,box.m_min);
314 m_box_tree.quantizePoint(quantizedMax,box.m_max);
317 while (curIndex < numNodes)
320 //catch bugs in tree data
322 bool aabbOverlap = m_box_tree.testQuantizedBoxOverlapp(curIndex, quantizedMin,quantizedMax);
323 bool isleafnode = isLeafNode(curIndex);
325 if (isleafnode && aabbOverlap)
327 collided_results.push_back(getNodeData(curIndex));
330 if (aabbOverlap || isleafnode)
338 curIndex+= getEscapeNodeIndex(curIndex);
341 if(collided_results.size()>0) return true;
347 //! returns the indices of the primitives in the m_primitive_manager
348 bool btGImpactQuantizedBvh::rayQuery(
349 const btVector3 & ray_dir,const btVector3 & ray_origin ,
350 btAlignedObjectArray<int> & collided_results) const
353 int numNodes = getNodeCount();
355 while (curIndex < numNodes)
358 getNodeBound(curIndex,bound);
360 //catch bugs in tree data
362 bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
363 bool isleafnode = isLeafNode(curIndex);
365 if (isleafnode && aabbOverlap)
367 collided_results.push_back(getNodeData( curIndex));
370 if (aabbOverlap || isleafnode)
378 curIndex+= getEscapeNodeIndex(curIndex);
381 if(collided_results.size()>0) return true;
386 SIMD_FORCE_INLINE bool _quantized_node_collision(
387 const btGImpactQuantizedBvh * boxset0, const btGImpactQuantizedBvh * boxset1,
388 const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0,
389 int node0 ,int node1, bool complete_primitive_tests)
392 boxset0->getNodeBound(node0,box0);
394 boxset1->getNodeBound(node1,box1);
396 return box0.overlapping_trans_cache(box1,trans_cache_1to0,complete_primitive_tests );
397 // box1.appy_transform_trans_cache(trans_cache_1to0);
398 // return box0.has_collision(box1);
403 //stackless recursive collision routine
404 static void _find_quantized_collision_pairs_recursive(
405 const btGImpactQuantizedBvh * boxset0, const btGImpactQuantizedBvh * boxset1,
406 btPairSet * collision_pairs,
407 const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0,
408 int node0, int node1, bool complete_primitive_tests)
413 if( _quantized_node_collision(
414 boxset0,boxset1,trans_cache_1to0,
415 node0,node1,complete_primitive_tests) ==false) return;//avoid colliding internal nodes
417 if(boxset0->isLeafNode(node0))
419 if(boxset1->isLeafNode(node1))
422 collision_pairs->push_pair(
423 boxset0->getNodeData(node0),boxset1->getNodeData(node1));
429 //collide left recursive
431 _find_quantized_collision_pairs_recursive(
433 collision_pairs,trans_cache_1to0,
434 node0,boxset1->getLeftNode(node1),false);
436 //collide right recursive
437 _find_quantized_collision_pairs_recursive(
439 collision_pairs,trans_cache_1to0,
440 node0,boxset1->getRightNode(node1),false);
447 if(boxset1->isLeafNode(node1))
450 //collide left recursive
451 _find_quantized_collision_pairs_recursive(
453 collision_pairs,trans_cache_1to0,
454 boxset0->getLeftNode(node0),node1,false);
457 //collide right recursive
459 _find_quantized_collision_pairs_recursive(
461 collision_pairs,trans_cache_1to0,
462 boxset0->getRightNode(node0),node1,false);
468 //collide left0 left1
472 _find_quantized_collision_pairs_recursive(
474 collision_pairs,trans_cache_1to0,
475 boxset0->getLeftNode(node0),boxset1->getLeftNode(node1),false);
477 //collide left0 right1
479 _find_quantized_collision_pairs_recursive(
481 collision_pairs,trans_cache_1to0,
482 boxset0->getLeftNode(node0),boxset1->getRightNode(node1),false);
485 //collide right0 left1
487 _find_quantized_collision_pairs_recursive(
489 collision_pairs,trans_cache_1to0,
490 boxset0->getRightNode(node0),boxset1->getLeftNode(node1),false);
492 //collide right0 right1
494 _find_quantized_collision_pairs_recursive(
496 collision_pairs,trans_cache_1to0,
497 boxset0->getRightNode(node0),boxset1->getRightNode(node1),false);
499 }// else if node1 is not a leaf
500 }// else if node0 is not a leaf
504 void btGImpactQuantizedBvh::find_collision(const btGImpactQuantizedBvh * boxset0, const btTransform & trans0,
505 const btGImpactQuantizedBvh * boxset1, const btTransform & trans1,
506 btPairSet & collision_pairs)
509 if(boxset0->getNodeCount()==0 || boxset1->getNodeCount()==0 ) return;
511 BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
513 trans_cache_1to0.calc_from_homogenic(trans0,trans1);
515 #ifdef TRI_COLLISION_PROFILING
516 bt_begin_gim02_q_tree_time();
517 #endif //TRI_COLLISION_PROFILING
519 _find_quantized_collision_pairs_recursive(
521 &collision_pairs,trans_cache_1to0,0,0,true);
522 #ifdef TRI_COLLISION_PROFILING
523 bt_end_gim02_q_tree_time();
524 #endif //TRI_COLLISION_PROFILING