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;
30 float g_q_accum_tree_collision_time = 0;
31 int g_q_count_traversing = 0;
33 void bt_begin_gim02_q_tree_time()
35 g_q_tree_clock.reset();
38 void bt_end_gim02_q_tree_time()
40 g_q_accum_tree_collision_time += g_q_tree_clock.getTimeMicroseconds();
41 g_q_count_traversing++;
44 //! Gets the average time in miliseconds of tree collisions
45 float btGImpactQuantizedBvh::getAverageTreeCollisionTime()
47 if (g_q_count_traversing == 0) return 0;
49 float avgtime = g_q_accum_tree_collision_time;
50 avgtime /= (float)g_q_count_traversing;
52 g_q_accum_tree_collision_time = 0;
53 g_q_count_traversing = 0;
56 // float avgtime = g_q_count_traversing;
57 // g_q_count_traversing = 0;
61 #endif //TRI_COLLISION_PROFILING
63 /////////////////////// btQuantizedBvhTree /////////////////////////////////
65 void btQuantizedBvhTree::calc_quantization(
66 GIM_BVH_DATA_ARRAY& primitive_boxes, btScalar boundMargin)
70 global_bound.invalidate();
72 for (int i = 0; i < primitive_boxes.size(); i++)
74 global_bound.merge(primitive_boxes[i].m_bound);
77 bt_calc_quantization_parameters(
78 m_global_bound.m_min, m_global_bound.m_max, m_bvhQuantization, global_bound.m_min, global_bound.m_max, boundMargin);
81 int btQuantizedBvhTree::_calc_splitting_axis(
82 GIM_BVH_DATA_ARRAY& primitive_boxes, int startIndex, int endIndex)
86 btVector3 means(btScalar(0.), btScalar(0.), btScalar(0.));
87 btVector3 variance(btScalar(0.), btScalar(0.), btScalar(0.));
88 int numIndices = endIndex - startIndex;
90 for (i = startIndex; i < endIndex; i++)
92 btVector3 center = btScalar(0.5) * (primitive_boxes[i].m_bound.m_max +
93 primitive_boxes[i].m_bound.m_min);
96 means *= (btScalar(1.) / (btScalar)numIndices);
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);
102 btVector3 diff2 = center - means;
103 diff2 = diff2 * diff2;
106 variance *= (btScalar(1.) / ((btScalar)numIndices - 1));
108 return variance.maxAxis();
111 int btQuantizedBvhTree::_sort_and_calc_splitting_index(
112 GIM_BVH_DATA_ARRAY& primitive_boxes, int startIndex,
113 int endIndex, int splitAxis)
116 int splitIndex = startIndex;
117 int numIndices = endIndex - startIndex;
119 // average of centers
120 btScalar splitValue = 0.0f;
122 btVector3 means(btScalar(0.), btScalar(0.), btScalar(0.));
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);
129 means *= (btScalar(1.) / (btScalar)numIndices);
131 splitValue = means[splitAxis];
133 //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
134 for (i = startIndex; i < endIndex; i++)
136 btVector3 center = btScalar(0.5) * (primitive_boxes[i].m_bound.m_max +
137 primitive_boxes[i].m_bound.m_min);
138 if (center[splitAxis] > splitValue)
141 primitive_boxes.swap(i, splitIndex);
142 //swapLeafNodes(i,splitIndex);
147 //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
148 //otherwise the tree-building might fail due to stack-overflows in certain cases.
149 //unbalanced1 is unsafe: it can cause stack overflows
150 //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
152 //unbalanced2 should work too: always use center (perfect balanced trees)
153 //bool unbalanced2 = true;
155 //this should be safe too:
156 int rangeBalancedIndices = numIndices / 3;
157 bool unbalanced = ((splitIndex <= (startIndex + rangeBalancedIndices)) || (splitIndex >= (endIndex - 1 - rangeBalancedIndices)));
161 splitIndex = startIndex + (numIndices >> 1);
164 btAssert(!((splitIndex == startIndex) || (splitIndex == (endIndex))));
169 void btQuantizedBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY& primitive_boxes, int startIndex, int endIndex)
171 int curIndex = m_num_nodes;
174 btAssert((endIndex - startIndex) > 0);
176 if ((endIndex - startIndex) == 1)
178 //We have a leaf node
179 setNodeBound(curIndex, primitive_boxes[startIndex].m_bound);
180 m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data);
184 //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
187 int splitIndex = _calc_splitting_axis(primitive_boxes, startIndex, endIndex);
189 splitIndex = _sort_and_calc_splitting_index(
190 primitive_boxes, startIndex, endIndex,
191 splitIndex //split axis
194 //calc this node bounding box
197 node_bound.invalidate();
199 for (int i = startIndex; i < endIndex; i++)
201 node_bound.merge(primitive_boxes[i].m_bound);
204 setNodeBound(curIndex, node_bound);
207 _build_sub_tree(primitive_boxes, startIndex, splitIndex);
210 _build_sub_tree(primitive_boxes, splitIndex, endIndex);
212 m_node_array[curIndex].setEscapeIndex(m_num_nodes - curIndex);
215 //! stackless build tree
216 void btQuantizedBvhTree::build_tree(
217 GIM_BVH_DATA_ARRAY& primitive_boxes)
219 calc_quantization(primitive_boxes);
220 // initialize node count to 0
223 m_node_array.resize(primitive_boxes.size() * 2);
225 _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
228 ////////////////////////////////////class btGImpactQuantizedBvh
230 void btGImpactQuantizedBvh::refit()
232 int nodecount = getNodeCount();
235 if (isLeafNode(nodecount))
238 m_primitive_manager->get_primitive_box(getNodeData(nodecount), leafbox);
239 setNodeBound(nodecount, leafbox);
243 //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount);
250 int child_node = getLeftNode(nodecount);
253 getNodeBound(child_node, temp_box);
254 bound.merge(temp_box);
257 child_node = getRightNode(nodecount);
260 getNodeBound(child_node, temp_box);
261 bound.merge(temp_box);
264 setNodeBound(nodecount, bound);
269 //! this rebuild the entire set
270 void btGImpactQuantizedBvh::buildSet()
272 //obtain primitive boxes
273 GIM_BVH_DATA_ARRAY primitive_boxes;
274 primitive_boxes.resize(m_primitive_manager->get_primitive_count());
276 for (int i = 0; i < primitive_boxes.size(); i++)
278 m_primitive_manager->get_primitive_box(i, primitive_boxes[i].m_bound);
279 primitive_boxes[i].m_data = i;
282 m_box_tree.build_tree(primitive_boxes);
285 //! returns the indices of the primitives in the m_primitive_manager
286 bool btGImpactQuantizedBvh::boxQuery(const btAABB& box, btAlignedObjectArray<int>& collided_results) const
289 int numNodes = getNodeCount();
293 unsigned short quantizedMin[3];
294 unsigned short quantizedMax[3];
296 m_box_tree.quantizePoint(quantizedMin, box.m_min);
297 m_box_tree.quantizePoint(quantizedMax, box.m_max);
299 while (curIndex < numNodes)
301 //catch bugs in tree data
303 bool aabbOverlap = m_box_tree.testQuantizedBoxOverlapp(curIndex, quantizedMin, quantizedMax);
304 bool isleafnode = isLeafNode(curIndex);
306 if (isleafnode && aabbOverlap)
308 collided_results.push_back(getNodeData(curIndex));
311 if (aabbOverlap || isleafnode)
319 curIndex += getEscapeNodeIndex(curIndex);
322 if (collided_results.size() > 0) return true;
326 //! returns the indices of the primitives in the m_primitive_manager
327 bool btGImpactQuantizedBvh::rayQuery(
328 const btVector3& ray_dir, const btVector3& ray_origin,
329 btAlignedObjectArray<int>& collided_results) const
332 int numNodes = getNodeCount();
334 while (curIndex < numNodes)
337 getNodeBound(curIndex, bound);
339 //catch bugs in tree data
341 bool aabbOverlap = bound.collide_ray(ray_origin, ray_dir);
342 bool isleafnode = isLeafNode(curIndex);
344 if (isleafnode && aabbOverlap)
346 collided_results.push_back(getNodeData(curIndex));
349 if (aabbOverlap || isleafnode)
357 curIndex += getEscapeNodeIndex(curIndex);
360 if (collided_results.size() > 0) return true;
364 SIMD_FORCE_INLINE bool _quantized_node_collision(
365 const btGImpactQuantizedBvh* boxset0, const btGImpactQuantizedBvh* boxset1,
366 const BT_BOX_BOX_TRANSFORM_CACHE& trans_cache_1to0,
367 int node0, int node1, bool complete_primitive_tests)
370 boxset0->getNodeBound(node0, box0);
372 boxset1->getNodeBound(node1, box1);
374 return box0.overlapping_trans_cache(box1, trans_cache_1to0, complete_primitive_tests);
375 // box1.appy_transform_trans_cache(trans_cache_1to0);
376 // return box0.has_collision(box1);
379 //stackless recursive collision routine
380 static void _find_quantized_collision_pairs_recursive(
381 const btGImpactQuantizedBvh* boxset0, const btGImpactQuantizedBvh* boxset1,
382 btPairSet* collision_pairs,
383 const BT_BOX_BOX_TRANSFORM_CACHE& trans_cache_1to0,
384 int node0, int node1, bool complete_primitive_tests)
386 if (_quantized_node_collision(
387 boxset0, boxset1, trans_cache_1to0,
388 node0, node1, complete_primitive_tests) == false) return; //avoid colliding internal nodes
390 if (boxset0->isLeafNode(node0))
392 if (boxset1->isLeafNode(node1))
395 collision_pairs->push_pair(
396 boxset0->getNodeData(node0), boxset1->getNodeData(node1));
401 //collide left recursive
403 _find_quantized_collision_pairs_recursive(
405 collision_pairs, trans_cache_1to0,
406 node0, boxset1->getLeftNode(node1), false);
408 //collide right recursive
409 _find_quantized_collision_pairs_recursive(
411 collision_pairs, trans_cache_1to0,
412 node0, boxset1->getRightNode(node1), false);
417 if (boxset1->isLeafNode(node1))
419 //collide left recursive
420 _find_quantized_collision_pairs_recursive(
422 collision_pairs, trans_cache_1to0,
423 boxset0->getLeftNode(node0), node1, false);
425 //collide right recursive
427 _find_quantized_collision_pairs_recursive(
429 collision_pairs, trans_cache_1to0,
430 boxset0->getRightNode(node0), node1, false);
434 //collide left0 left1
436 _find_quantized_collision_pairs_recursive(
438 collision_pairs, trans_cache_1to0,
439 boxset0->getLeftNode(node0), boxset1->getLeftNode(node1), false);
441 //collide left0 right1
443 _find_quantized_collision_pairs_recursive(
445 collision_pairs, trans_cache_1to0,
446 boxset0->getLeftNode(node0), boxset1->getRightNode(node1), false);
448 //collide right0 left1
450 _find_quantized_collision_pairs_recursive(
452 collision_pairs, trans_cache_1to0,
453 boxset0->getRightNode(node0), boxset1->getLeftNode(node1), false);
455 //collide right0 right1
457 _find_quantized_collision_pairs_recursive(
459 collision_pairs, trans_cache_1to0,
460 boxset0->getRightNode(node0), boxset1->getRightNode(node1), false);
462 } // else if node1 is not a leaf
463 } // else if node0 is not a leaf
466 void btGImpactQuantizedBvh::find_collision(const btGImpactQuantizedBvh* boxset0, const btTransform& trans0,
467 const btGImpactQuantizedBvh* boxset1, const btTransform& trans1,
468 btPairSet& collision_pairs)
470 if (boxset0->getNodeCount() == 0 || boxset1->getNodeCount() == 0) return;
472 BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
474 trans_cache_1to0.calc_from_homogenic(trans0, trans1);
476 #ifdef TRI_COLLISION_PROFILING
477 bt_begin_gim02_q_tree_time();
478 #endif //TRI_COLLISION_PROFILING
480 _find_quantized_collision_pairs_recursive(
482 &collision_pairs, trans_cache_1to0, 0, 0, true);
483 #ifdef TRI_COLLISION_PROFILING
484 bt_end_gim02_q_tree_time();
485 #endif //TRI_COLLISION_PROFILING