123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /*! \file gim_box_set.h
- \author Francisco Leon Najera
- */
- /*
- This source file is part of GIMPACT Library.
- For the latest info, see http://gimpact.sourceforge.net/
- Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371.
- email: projectileman@yahoo.com
- This software is provided 'as-is', without any express or implied warranty.
- In no event will the authors be held liable for any damages arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it freely,
- subject to the following restrictions:
- 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.
- 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "btGImpactQuantizedBvh.h"
- #include "LinearMath/btQuickprof.h"
- #ifdef TRI_COLLISION_PROFILING
- btClock g_q_tree_clock;
- float g_q_accum_tree_collision_time = 0;
- int g_q_count_traversing = 0;
- void bt_begin_gim02_q_tree_time()
- {
- g_q_tree_clock.reset();
- }
- void bt_end_gim02_q_tree_time()
- {
- g_q_accum_tree_collision_time += g_q_tree_clock.getTimeMicroseconds();
- g_q_count_traversing++;
- }
- //! Gets the average time in miliseconds of tree collisions
- float btGImpactQuantizedBvh::getAverageTreeCollisionTime()
- {
- if(g_q_count_traversing == 0) return 0;
- float avgtime = g_q_accum_tree_collision_time;
- avgtime /= (float)g_q_count_traversing;
- g_q_accum_tree_collision_time = 0;
- g_q_count_traversing = 0;
- return avgtime;
- // float avgtime = g_q_count_traversing;
- // g_q_count_traversing = 0;
- // return avgtime;
- }
- #endif //TRI_COLLISION_PROFILING
- /////////////////////// btQuantizedBvhTree /////////////////////////////////
- void btQuantizedBvhTree::calc_quantization(
- GIM_BVH_DATA_ARRAY & primitive_boxes, btScalar boundMargin)
- {
- //calc globa box
- btAABB global_bound;
- global_bound.invalidate();
- for (int i=0;i<primitive_boxes.size() ;i++ )
- {
- global_bound.merge(primitive_boxes[i].m_bound);
- }
- bt_calc_quantization_parameters(
- m_global_bound.m_min,m_global_bound.m_max,m_bvhQuantization,global_bound.m_min,global_bound.m_max,boundMargin);
- }
- int btQuantizedBvhTree::_calc_splitting_axis(
- GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex)
- {
- int i;
- btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
- btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
- int numIndices = endIndex-startIndex;
- for (i=startIndex;i<endIndex;i++)
- {
- btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
- primitive_boxes[i].m_bound.m_min);
- means+=center;
- }
- means *= (btScalar(1.)/(btScalar)numIndices);
- for (i=startIndex;i<endIndex;i++)
- {
- btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
- primitive_boxes[i].m_bound.m_min);
- btVector3 diff2 = center-means;
- diff2 = diff2 * diff2;
- variance += diff2;
- }
- variance *= (btScalar(1.)/ ((btScalar)numIndices-1) );
- return variance.maxAxis();
- }
- int btQuantizedBvhTree::_sort_and_calc_splitting_index(
- GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex,
- int endIndex, int splitAxis)
- {
- int i;
- int splitIndex =startIndex;
- int numIndices = endIndex - startIndex;
- // average of centers
- btScalar splitValue = 0.0f;
- btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
- for (i=startIndex;i<endIndex;i++)
- {
- btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
- primitive_boxes[i].m_bound.m_min);
- means+=center;
- }
- means *= (btScalar(1.)/(btScalar)numIndices);
- splitValue = means[splitAxis];
- //sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
- for (i=startIndex;i<endIndex;i++)
- {
- btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
- primitive_boxes[i].m_bound.m_min);
- if (center[splitAxis] > splitValue)
- {
- //swap
- primitive_boxes.swap(i,splitIndex);
- //swapLeafNodes(i,splitIndex);
- splitIndex++;
- }
- }
- //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex
- //otherwise the tree-building might fail due to stack-overflows in certain cases.
- //unbalanced1 is unsafe: it can cause stack overflows
- //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1)));
- //unbalanced2 should work too: always use center (perfect balanced trees)
- //bool unbalanced2 = true;
- //this should be safe too:
- int rangeBalancedIndices = numIndices/3;
- bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
- if (unbalanced)
- {
- splitIndex = startIndex+ (numIndices>>1);
- }
- btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
- return splitIndex;
- }
- void btQuantizedBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex)
- {
- int curIndex = m_num_nodes;
- m_num_nodes++;
- btAssert((endIndex-startIndex)>0);
- if ((endIndex-startIndex)==1)
- {
- //We have a leaf node
- setNodeBound(curIndex,primitive_boxes[startIndex].m_bound);
- m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data);
- return;
- }
- //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
- //split axis
- int splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
- splitIndex = _sort_and_calc_splitting_index(
- primitive_boxes,startIndex,endIndex,
- splitIndex//split axis
- );
- //calc this node bounding box
- btAABB node_bound;
- node_bound.invalidate();
- for (int i=startIndex;i<endIndex;i++)
- {
- node_bound.merge(primitive_boxes[i].m_bound);
- }
- setNodeBound(curIndex,node_bound);
- //build left branch
- _build_sub_tree(primitive_boxes, startIndex, splitIndex );
- //build right branch
- _build_sub_tree(primitive_boxes, splitIndex ,endIndex);
- m_node_array[curIndex].setEscapeIndex(m_num_nodes - curIndex);
- }
- //! stackless build tree
- void btQuantizedBvhTree::build_tree(
- GIM_BVH_DATA_ARRAY & primitive_boxes)
- {
- calc_quantization(primitive_boxes);
- // initialize node count to 0
- m_num_nodes = 0;
- // allocate nodes
- m_node_array.resize(primitive_boxes.size()*2);
- _build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
- }
- ////////////////////////////////////class btGImpactQuantizedBvh
- void btGImpactQuantizedBvh::refit()
- {
- int nodecount = getNodeCount();
- while(nodecount--)
- {
- if(isLeafNode(nodecount))
- {
- btAABB leafbox;
- m_primitive_manager->get_primitive_box(getNodeData(nodecount),leafbox);
- setNodeBound(nodecount,leafbox);
- }
- else
- {
- //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount);
- //get left bound
- btAABB bound;
- bound.invalidate();
- btAABB temp_box;
- int child_node = getLeftNode(nodecount);
- if(child_node)
- {
- getNodeBound(child_node,temp_box);
- bound.merge(temp_box);
- }
- child_node = getRightNode(nodecount);
- if(child_node)
- {
- getNodeBound(child_node,temp_box);
- bound.merge(temp_box);
- }
- setNodeBound(nodecount,bound);
- }
- }
- }
- //! this rebuild the entire set
- void btGImpactQuantizedBvh::buildSet()
- {
- //obtain primitive boxes
- GIM_BVH_DATA_ARRAY primitive_boxes;
- primitive_boxes.resize(m_primitive_manager->get_primitive_count());
- for (int i = 0;i<primitive_boxes.size() ;i++ )
- {
- m_primitive_manager->get_primitive_box(i,primitive_boxes[i].m_bound);
- primitive_boxes[i].m_data = i;
- }
- m_box_tree.build_tree(primitive_boxes);
- }
- //! returns the indices of the primitives in the m_primitive_manager
- bool btGImpactQuantizedBvh::boxQuery(const btAABB & box, btAlignedObjectArray<int> & collided_results) const
- {
- int curIndex = 0;
- int numNodes = getNodeCount();
- //quantize box
- unsigned short quantizedMin[3];
- unsigned short quantizedMax[3];
- m_box_tree.quantizePoint(quantizedMin,box.m_min);
- m_box_tree.quantizePoint(quantizedMax,box.m_max);
- while (curIndex < numNodes)
- {
- //catch bugs in tree data
- bool aabbOverlap = m_box_tree.testQuantizedBoxOverlapp(curIndex, quantizedMin,quantizedMax);
- bool isleafnode = isLeafNode(curIndex);
- if (isleafnode && aabbOverlap)
- {
- collided_results.push_back(getNodeData(curIndex));
- }
- if (aabbOverlap || isleafnode)
- {
- //next subnode
- curIndex++;
- }
- else
- {
- //skip node
- curIndex+= getEscapeNodeIndex(curIndex);
- }
- }
- if(collided_results.size()>0) return true;
- return false;
- }
- //! returns the indices of the primitives in the m_primitive_manager
- bool btGImpactQuantizedBvh::rayQuery(
- const btVector3 & ray_dir,const btVector3 & ray_origin ,
- btAlignedObjectArray<int> & collided_results) const
- {
- int curIndex = 0;
- int numNodes = getNodeCount();
- while (curIndex < numNodes)
- {
- btAABB bound;
- getNodeBound(curIndex,bound);
- //catch bugs in tree data
- bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
- bool isleafnode = isLeafNode(curIndex);
- if (isleafnode && aabbOverlap)
- {
- collided_results.push_back(getNodeData( curIndex));
- }
- if (aabbOverlap || isleafnode)
- {
- //next subnode
- curIndex++;
- }
- else
- {
- //skip node
- curIndex+= getEscapeNodeIndex(curIndex);
- }
- }
- if(collided_results.size()>0) return true;
- return false;
- }
- SIMD_FORCE_INLINE bool _quantized_node_collision(
- const btGImpactQuantizedBvh * boxset0, const btGImpactQuantizedBvh * boxset1,
- const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0,
- int node0 ,int node1, bool complete_primitive_tests)
- {
- btAABB box0;
- boxset0->getNodeBound(node0,box0);
- btAABB box1;
- boxset1->getNodeBound(node1,box1);
- return box0.overlapping_trans_cache(box1,trans_cache_1to0,complete_primitive_tests );
- // box1.appy_transform_trans_cache(trans_cache_1to0);
- // return box0.has_collision(box1);
- }
- //stackless recursive collision routine
- static void _find_quantized_collision_pairs_recursive(
- const btGImpactQuantizedBvh * boxset0, const btGImpactQuantizedBvh * boxset1,
- btPairSet * collision_pairs,
- const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0,
- int node0, int node1, bool complete_primitive_tests)
- {
- if( _quantized_node_collision(
- boxset0,boxset1,trans_cache_1to0,
- node0,node1,complete_primitive_tests) ==false) return;//avoid colliding internal nodes
- if(boxset0->isLeafNode(node0))
- {
- if(boxset1->isLeafNode(node1))
- {
- // collision result
- collision_pairs->push_pair(
- boxset0->getNodeData(node0),boxset1->getNodeData(node1));
- return;
- }
- else
- {
- //collide left recursive
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- node0,boxset1->getLeftNode(node1),false);
- //collide right recursive
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- node0,boxset1->getRightNode(node1),false);
- }
- }
- else
- {
- if(boxset1->isLeafNode(node1))
- {
- //collide left recursive
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- boxset0->getLeftNode(node0),node1,false);
- //collide right recursive
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- boxset0->getRightNode(node0),node1,false);
- }
- else
- {
- //collide left0 left1
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- boxset0->getLeftNode(node0),boxset1->getLeftNode(node1),false);
- //collide left0 right1
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- boxset0->getLeftNode(node0),boxset1->getRightNode(node1),false);
- //collide right0 left1
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- boxset0->getRightNode(node0),boxset1->getLeftNode(node1),false);
- //collide right0 right1
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- collision_pairs,trans_cache_1to0,
- boxset0->getRightNode(node0),boxset1->getRightNode(node1),false);
- }// else if node1 is not a leaf
- }// else if node0 is not a leaf
- }
- void btGImpactQuantizedBvh::find_collision(const btGImpactQuantizedBvh * boxset0, const btTransform & trans0,
- const btGImpactQuantizedBvh * boxset1, const btTransform & trans1,
- btPairSet & collision_pairs)
- {
- if(boxset0->getNodeCount()==0 || boxset1->getNodeCount()==0 ) return;
- BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
- trans_cache_1to0.calc_from_homogenic(trans0,trans1);
- #ifdef TRI_COLLISION_PROFILING
- bt_begin_gim02_q_tree_time();
- #endif //TRI_COLLISION_PROFILING
- _find_quantized_collision_pairs_recursive(
- boxset0,boxset1,
- &collision_pairs,trans_cache_1to0,0,0,true);
- #ifdef TRI_COLLISION_PROFILING
- bt_end_gim02_q_tree_time();
- #endif //TRI_COLLISION_PROFILING
- }
|