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;
33 void bt_begin_gim02_tree_time()
38 void bt_end_gim02_tree_time()
40 g_accum_tree_collision_time += g_tree_clock.getTimeMicroseconds();
44 //! Gets the average time in miliseconds of tree collisions
45 float btGImpactBvh::getAverageTreeCollisionTime()
47 if (g_count_traversing == 0) return 0;
49 float avgtime = g_accum_tree_collision_time;
50 avgtime /= (float)g_count_traversing;
52 g_accum_tree_collision_time = 0;
53 g_count_traversing = 0;
56 // float avgtime = g_count_traversing;
57 // g_count_traversing = 0;
61 #endif //TRI_COLLISION_PROFILING
63 /////////////////////// btBvhTree /////////////////////////////////
65 int btBvhTree::_calc_splitting_axis(
66 GIM_BVH_DATA_ARRAY& primitive_boxes, int startIndex, int endIndex)
70 btVector3 means(btScalar(0.), btScalar(0.), btScalar(0.));
71 btVector3 variance(btScalar(0.), btScalar(0.), btScalar(0.));
72 int numIndices = endIndex - startIndex;
74 for (i = startIndex; i < endIndex; i++)
76 btVector3 center = btScalar(0.5) * (primitive_boxes[i].m_bound.m_max +
77 primitive_boxes[i].m_bound.m_min);
80 means *= (btScalar(1.) / (btScalar)numIndices);
82 for (i = startIndex; i < endIndex; i++)
84 btVector3 center = btScalar(0.5) * (primitive_boxes[i].m_bound.m_max +
85 primitive_boxes[i].m_bound.m_min);
86 btVector3 diff2 = center - means;
87 diff2 = diff2 * diff2;
90 variance *= (btScalar(1.) / ((btScalar)numIndices - 1));
92 return variance.maxAxis();
95 int btBvhTree::_sort_and_calc_splitting_index(
96 GIM_BVH_DATA_ARRAY& primitive_boxes, int startIndex,
97 int endIndex, int splitAxis)
100 int splitIndex = startIndex;
101 int numIndices = endIndex - startIndex;
103 // average of centers
104 btScalar splitValue = 0.0f;
106 btVector3 means(btScalar(0.), btScalar(0.), btScalar(0.));
107 for (i = startIndex; i < endIndex; i++)
109 btVector3 center = btScalar(0.5) * (primitive_boxes[i].m_bound.m_max +
110 primitive_boxes[i].m_bound.m_min);
113 means *= (btScalar(1.) / (btScalar)numIndices);
115 splitValue = means[splitAxis];
117 //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
118 for (i = startIndex; i < endIndex; i++)
120 btVector3 center = btScalar(0.5) * (primitive_boxes[i].m_bound.m_max +
121 primitive_boxes[i].m_bound.m_min);
122 if (center[splitAxis] > splitValue)
125 primitive_boxes.swap(i, splitIndex);
126 //swapLeafNodes(i,splitIndex);
131 //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
132 //otherwise the tree-building might fail due to stack-overflows in certain cases.
133 //unbalanced1 is unsafe: it can cause stack overflows
134 //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
136 //unbalanced2 should work too: always use center (perfect balanced trees)
137 //bool unbalanced2 = true;
139 //this should be safe too:
140 int rangeBalancedIndices = numIndices / 3;
141 bool unbalanced = ((splitIndex <= (startIndex + rangeBalancedIndices)) || (splitIndex >= (endIndex - 1 - rangeBalancedIndices)));
145 splitIndex = startIndex + (numIndices >> 1);
148 btAssert(!((splitIndex == startIndex) || (splitIndex == (endIndex))));
153 void btBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY& primitive_boxes, int startIndex, int endIndex)
155 int curIndex = m_num_nodes;
158 btAssert((endIndex - startIndex) > 0);
160 if ((endIndex - startIndex) == 1)
162 //We have a leaf node
163 setNodeBound(curIndex, primitive_boxes[startIndex].m_bound);
164 m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data);
168 //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
171 int splitIndex = _calc_splitting_axis(primitive_boxes, startIndex, endIndex);
173 splitIndex = _sort_and_calc_splitting_index(
174 primitive_boxes, startIndex, endIndex,
175 splitIndex //split axis
178 //calc this node bounding box
181 node_bound.invalidate();
183 for (int i = startIndex; i < endIndex; i++)
185 node_bound.merge(primitive_boxes[i].m_bound);
188 setNodeBound(curIndex, node_bound);
191 _build_sub_tree(primitive_boxes, startIndex, splitIndex);
194 _build_sub_tree(primitive_boxes, splitIndex, endIndex);
196 m_node_array[curIndex].setEscapeIndex(m_num_nodes - curIndex);
199 //! stackless build tree
200 void btBvhTree::build_tree(
201 GIM_BVH_DATA_ARRAY& primitive_boxes)
203 // initialize node count to 0
206 m_node_array.resize(primitive_boxes.size() * 2);
208 _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
211 ////////////////////////////////////class btGImpactBvh
213 void btGImpactBvh::refit()
215 int nodecount = getNodeCount();
218 if (isLeafNode(nodecount))
221 m_primitive_manager->get_primitive_box(getNodeData(nodecount), leafbox);
222 setNodeBound(nodecount, leafbox);
226 //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount);
233 int child_node = getLeftNode(nodecount);
236 getNodeBound(child_node, temp_box);
237 bound.merge(temp_box);
240 child_node = getRightNode(nodecount);
243 getNodeBound(child_node, temp_box);
244 bound.merge(temp_box);
247 setNodeBound(nodecount, bound);
252 //! this rebuild the entire set
253 void btGImpactBvh::buildSet()
255 //obtain primitive boxes
256 GIM_BVH_DATA_ARRAY primitive_boxes;
257 primitive_boxes.resize(m_primitive_manager->get_primitive_count());
259 for (int i = 0; i < primitive_boxes.size(); i++)
261 m_primitive_manager->get_primitive_box(i, primitive_boxes[i].m_bound);
262 primitive_boxes[i].m_data = i;
265 m_box_tree.build_tree(primitive_boxes);
268 //! returns the indices of the primitives in the m_primitive_manager
269 bool btGImpactBvh::boxQuery(const btAABB& box, btAlignedObjectArray<int>& collided_results) const
272 int numNodes = getNodeCount();
274 while (curIndex < numNodes)
277 getNodeBound(curIndex, bound);
279 //catch bugs in tree data
281 bool aabbOverlap = bound.has_collision(box);
282 bool isleafnode = isLeafNode(curIndex);
284 if (isleafnode && aabbOverlap)
286 collided_results.push_back(getNodeData(curIndex));
289 if (aabbOverlap || isleafnode)
297 curIndex += getEscapeNodeIndex(curIndex);
300 if (collided_results.size() > 0) return true;
304 //! returns the indices of the primitives in the m_primitive_manager
305 bool btGImpactBvh::rayQuery(
306 const btVector3& ray_dir, const btVector3& ray_origin,
307 btAlignedObjectArray<int>& collided_results) const
310 int numNodes = getNodeCount();
312 while (curIndex < numNodes)
315 getNodeBound(curIndex, bound);
317 //catch bugs in tree data
319 bool aabbOverlap = bound.collide_ray(ray_origin, ray_dir);
320 bool isleafnode = isLeafNode(curIndex);
322 if (isleafnode && aabbOverlap)
324 collided_results.push_back(getNodeData(curIndex));
327 if (aabbOverlap || isleafnode)
335 curIndex += getEscapeNodeIndex(curIndex);
338 if (collided_results.size() > 0) return true;
342 SIMD_FORCE_INLINE bool _node_collision(
343 btGImpactBvh* boxset0, btGImpactBvh* boxset1,
344 const BT_BOX_BOX_TRANSFORM_CACHE& trans_cache_1to0,
345 int node0, int node1, bool complete_primitive_tests)
348 boxset0->getNodeBound(node0, box0);
350 boxset1->getNodeBound(node1, box1);
352 return box0.overlapping_trans_cache(box1, trans_cache_1to0, complete_primitive_tests);
353 // box1.appy_transform_trans_cache(trans_cache_1to0);
354 // return box0.has_collision(box1);
357 //stackless recursive collision routine
358 static void _find_collision_pairs_recursive(
359 btGImpactBvh* boxset0, btGImpactBvh* boxset1,
360 btPairSet* collision_pairs,
361 const BT_BOX_BOX_TRANSFORM_CACHE& trans_cache_1to0,
362 int node0, int node1, bool complete_primitive_tests)
365 boxset0, boxset1, trans_cache_1to0,
366 node0, node1, complete_primitive_tests) == false) return; //avoid colliding internal nodes
368 if (boxset0->isLeafNode(node0))
370 if (boxset1->isLeafNode(node1))
373 collision_pairs->push_pair(
374 boxset0->getNodeData(node0), boxset1->getNodeData(node1));
379 //collide left recursive
381 _find_collision_pairs_recursive(
383 collision_pairs, trans_cache_1to0,
384 node0, boxset1->getLeftNode(node1), false);
386 //collide right recursive
387 _find_collision_pairs_recursive(
389 collision_pairs, trans_cache_1to0,
390 node0, boxset1->getRightNode(node1), false);
395 if (boxset1->isLeafNode(node1))
397 //collide left recursive
398 _find_collision_pairs_recursive(
400 collision_pairs, trans_cache_1to0,
401 boxset0->getLeftNode(node0), node1, false);
403 //collide right recursive
405 _find_collision_pairs_recursive(
407 collision_pairs, trans_cache_1to0,
408 boxset0->getRightNode(node0), node1, false);
412 //collide left0 left1
414 _find_collision_pairs_recursive(
416 collision_pairs, trans_cache_1to0,
417 boxset0->getLeftNode(node0), boxset1->getLeftNode(node1), false);
419 //collide left0 right1
421 _find_collision_pairs_recursive(
423 collision_pairs, trans_cache_1to0,
424 boxset0->getLeftNode(node0), boxset1->getRightNode(node1), false);
426 //collide right0 left1
428 _find_collision_pairs_recursive(
430 collision_pairs, trans_cache_1to0,
431 boxset0->getRightNode(node0), boxset1->getLeftNode(node1), false);
433 //collide right0 right1
435 _find_collision_pairs_recursive(
437 collision_pairs, trans_cache_1to0,
438 boxset0->getRightNode(node0), boxset1->getRightNode(node1), false);
440 } // else if node1 is not a leaf
441 } // else if node0 is not a leaf
444 void btGImpactBvh::find_collision(btGImpactBvh* boxset0, const btTransform& trans0,
445 btGImpactBvh* boxset1, const btTransform& trans1,
446 btPairSet& collision_pairs)
448 if (boxset0->getNodeCount() == 0 || boxset1->getNodeCount() == 0) return;
450 BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
452 trans_cache_1to0.calc_from_homogenic(trans0, trans1);
454 #ifdef TRI_COLLISION_PROFILING
455 bt_begin_gim02_tree_time();
456 #endif //TRI_COLLISION_PROFILING
458 _find_collision_pairs_recursive(
460 &collision_pairs, trans_cache_1to0, 0, 0, true);
461 #ifdef TRI_COLLISION_PROFILING
462 bt_end_gim02_tree_time();
463 #endif //TRI_COLLISION_PROFILING