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
btGImpactQuantizedBvh * boxset0, 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
btGImpactQuantizedBvh * boxset0, 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(btGImpactQuantizedBvh * boxset0, const btTransform & trans0,
505
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