Home | History | Annotate | Download | only in Gimpact
      1 /*! \file gim_box_set.h
      2 \author Francisco Leon Najera
      3 */
      4 /*
      5 This source file is part of GIMPACT Library.
      6 
      7 For the latest info, see http://gimpact.sourceforge.net/
      8 
      9 Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371.
     10 email: projectileman (at) yahoo.com
     11 
     12 
     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:
     18 
     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.
     22 */
     23 
     24 #include "btGImpactQuantizedBvh.h"
     25 #include "LinearMath/btQuickprof.h"
     26 
     27 #ifdef TRI_COLLISION_PROFILING
     28 btClock g_q_tree_clock;
     29 
     30 
     31 float g_q_accum_tree_collision_time = 0;
     32 int g_q_count_traversing = 0;
     33 
     34 
     35 void bt_begin_gim02_q_tree_time()
     36 {
     37 	g_q_tree_clock.reset();
     38 }
     39 
     40 void bt_end_gim02_q_tree_time()
     41 {
     42 	g_q_accum_tree_collision_time += g_q_tree_clock.getTimeMicroseconds();
     43 	g_q_count_traversing++;
     44 }
     45 
     46 
     47 //! Gets the average time in miliseconds of tree collisions
     48 float btGImpactQuantizedBvh::getAverageTreeCollisionTime()
     49 {
     50 	if(g_q_count_traversing == 0) return 0;
     51 
     52 	float avgtime = g_q_accum_tree_collision_time;
     53 	avgtime /= (float)g_q_count_traversing;
     54 
     55 	g_q_accum_tree_collision_time = 0;
     56 	g_q_count_traversing = 0;
     57 	return avgtime;
     58 
     59 //	float avgtime = g_q_count_traversing;
     60 //	g_q_count_traversing = 0;
     61 //	return avgtime;
     62 
     63 }
     64 
     65 #endif //TRI_COLLISION_PROFILING
     66 
     67 /////////////////////// btQuantizedBvhTree /////////////////////////////////
     68 
     69 void btQuantizedBvhTree::calc_quantization(
     70 	GIM_BVH_DATA_ARRAY & primitive_boxes, btScalar boundMargin)
     71 {
     72 	//calc globa box
     73 	btAABB global_bound;
     74 	global_bound.invalidate();
     75 
     76 	for (int i=0;i<primitive_boxes.size() ;i++ )
     77 	{
     78 		global_bound.merge(primitive_boxes[i].m_bound);
     79 	}
     80 
     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);
     83 
     84 }
     85 
     86 
     87 
     88 int btQuantizedBvhTree::_calc_splitting_axis(
     89 	GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex,  int endIndex)
     90 {
     91 
     92 	int i;
     93 
     94 	btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
     95 	btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.));
     96 	int numIndices = endIndex-startIndex;
     97 
     98 	for (i=startIndex;i<endIndex;i++)
     99 	{
    100 		btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
    101 					 primitive_boxes[i].m_bound.m_min);
    102 		means+=center;
    103 	}
    104 	means *= (btScalar(1.)/(btScalar)numIndices);
    105 
    106 	for (i=startIndex;i<endIndex;i++)
    107 	{
    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;
    112 		variance += diff2;
    113 	}
    114 	variance *= (btScalar(1.)/	((btScalar)numIndices-1)	);
    115 
    116 	return variance.maxAxis();
    117 }
    118 
    119 
    120 int btQuantizedBvhTree::_sort_and_calc_splitting_index(
    121 	GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex,
    122 	int endIndex, int splitAxis)
    123 {
    124 	int i;
    125 	int splitIndex =startIndex;
    126 	int numIndices = endIndex - startIndex;
    127 
    128 	// average of centers
    129 	btScalar splitValue = 0.0f;
    130 
    131 	btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.));
    132 	for (i=startIndex;i<endIndex;i++)
    133 	{
    134 		btVector3 center = btScalar(0.5)*(primitive_boxes[i].m_bound.m_max +
    135 					 primitive_boxes[i].m_bound.m_min);
    136 		means+=center;
    137 	}
    138 	means *= (btScalar(1.)/(btScalar)numIndices);
    139 
    140 	splitValue = means[splitAxis];
    141 
    142 
    143 	//sort leafNodes so all values larger then splitValue comes first, and smaller values start from 'splitIndex'.
    144 	for (i=startIndex;i<endIndex;i++)
    145 	{
    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)
    149 		{
    150 			//swap
    151 			primitive_boxes.swap(i,splitIndex);
    152 			//swapLeafNodes(i,splitIndex);
    153 			splitIndex++;
    154 		}
    155 	}
    156 
    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)));
    161 
    162 	//unbalanced2 should work too: always use center (perfect balanced trees)
    163 	//bool unbalanced2 = true;
    164 
    165 	//this should be safe too:
    166 	int rangeBalancedIndices = numIndices/3;
    167 	bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices)));
    168 
    169 	if (unbalanced)
    170 	{
    171 		splitIndex = startIndex+ (numIndices>>1);
    172 	}
    173 
    174 	btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex))));
    175 
    176 	return splitIndex;
    177 
    178 }
    179 
    180 
    181 void btQuantizedBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex,  int endIndex)
    182 {
    183 	int curIndex = m_num_nodes;
    184 	m_num_nodes++;
    185 
    186 	btAssert((endIndex-startIndex)>0);
    187 
    188 	if ((endIndex-startIndex)==1)
    189 	{
    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);
    193 
    194 		return;
    195 	}
    196 	//calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'.
    197 
    198 	//split axis
    199 	int splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex);
    200 
    201 	splitIndex = _sort_and_calc_splitting_index(
    202 			primitive_boxes,startIndex,endIndex,
    203 			splitIndex//split axis
    204 			);
    205 
    206 
    207 	//calc this node bounding box
    208 
    209 	btAABB node_bound;
    210 	node_bound.invalidate();
    211 
    212 	for (int i=startIndex;i<endIndex;i++)
    213 	{
    214 		node_bound.merge(primitive_boxes[i].m_bound);
    215 	}
    216 
    217 	setNodeBound(curIndex,node_bound);
    218 
    219 
    220 	//build left branch
    221 	_build_sub_tree(primitive_boxes, startIndex, splitIndex );
    222 
    223 
    224 	//build right branch
    225 	 _build_sub_tree(primitive_boxes, splitIndex ,endIndex);
    226 
    227 	m_node_array[curIndex].setEscapeIndex(m_num_nodes - curIndex);
    228 
    229 
    230 }
    231 
    232 //! stackless build tree
    233 void btQuantizedBvhTree::build_tree(
    234 	GIM_BVH_DATA_ARRAY & primitive_boxes)
    235 {
    236 	calc_quantization(primitive_boxes);
    237 	// initialize node count to 0
    238 	m_num_nodes = 0;
    239 	// allocate nodes
    240 	m_node_array.resize(primitive_boxes.size()*2);
    241 
    242 	_build_sub_tree(primitive_boxes, 0, primitive_boxes.size());
    243 }
    244 
    245 ////////////////////////////////////class btGImpactQuantizedBvh
    246 
    247 void btGImpactQuantizedBvh::refit()
    248 {
    249 	int nodecount = getNodeCount();
    250 	while(nodecount--)
    251 	{
    252 		if(isLeafNode(nodecount))
    253 		{
    254 			btAABB leafbox;
    255 			m_primitive_manager->get_primitive_box(getNodeData(nodecount),leafbox);
    256 			setNodeBound(nodecount,leafbox);
    257 		}
    258 		else
    259 		{
    260 			//const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount);
    261 			//get left bound
    262 			btAABB bound;
    263 			bound.invalidate();
    264 
    265 			btAABB temp_box;
    266 
    267 			int child_node = getLeftNode(nodecount);
    268 			if(child_node)
    269 			{
    270 				getNodeBound(child_node,temp_box);
    271 				bound.merge(temp_box);
    272 			}
    273 
    274 			child_node = getRightNode(nodecount);
    275 			if(child_node)
    276 			{
    277 				getNodeBound(child_node,temp_box);
    278 				bound.merge(temp_box);
    279 			}
    280 
    281 			setNodeBound(nodecount,bound);
    282 		}
    283 	}
    284 }
    285 
    286 //! this rebuild the entire set
    287 void btGImpactQuantizedBvh::buildSet()
    288 {
    289 	//obtain primitive boxes
    290 	GIM_BVH_DATA_ARRAY primitive_boxes;
    291 	primitive_boxes.resize(m_primitive_manager->get_primitive_count());
    292 
    293 	for (int i = 0;i<primitive_boxes.size() ;i++ )
    294 	{
    295 		 m_primitive_manager->get_primitive_box(i,primitive_boxes[i].m_bound);
    296 		 primitive_boxes[i].m_data = i;
    297 	}
    298 
    299 	m_box_tree.build_tree(primitive_boxes);
    300 }
    301 
    302 //! returns the indices of the primitives in the m_primitive_manager
    303 bool btGImpactQuantizedBvh::boxQuery(const btAABB & box, btAlignedObjectArray<int> & collided_results) const
    304 {
    305 	int curIndex = 0;
    306 	int numNodes = getNodeCount();
    307 
    308 	//quantize box
    309 
    310 	unsigned short quantizedMin[3];
    311 	unsigned short quantizedMax[3];
    312 
    313 	m_box_tree.quantizePoint(quantizedMin,box.m_min);
    314 	m_box_tree.quantizePoint(quantizedMax,box.m_max);
    315 
    316 
    317 	while (curIndex < numNodes)
    318 	{
    319 
    320 		//catch bugs in tree data
    321 
    322 		bool aabbOverlap = m_box_tree.testQuantizedBoxOverlapp(curIndex, quantizedMin,quantizedMax);
    323 		bool isleafnode = isLeafNode(curIndex);
    324 
    325 		if (isleafnode && aabbOverlap)
    326 		{
    327 			collided_results.push_back(getNodeData(curIndex));
    328 		}
    329 
    330 		if (aabbOverlap || isleafnode)
    331 		{
    332 			//next subnode
    333 			curIndex++;
    334 		}
    335 		else
    336 		{
    337 			//skip node
    338 			curIndex+= getEscapeNodeIndex(curIndex);
    339 		}
    340 	}
    341 	if(collided_results.size()>0) return true;
    342 	return false;
    343 }
    344 
    345 
    346 
    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
    351 {
    352 	int curIndex = 0;
    353 	int numNodes = getNodeCount();
    354 
    355 	while (curIndex < numNodes)
    356 	{
    357 		btAABB bound;
    358 		getNodeBound(curIndex,bound);
    359 
    360 		//catch bugs in tree data
    361 
    362 		bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir);
    363 		bool isleafnode = isLeafNode(curIndex);
    364 
    365 		if (isleafnode && aabbOverlap)
    366 		{
    367 			collided_results.push_back(getNodeData( curIndex));
    368 		}
    369 
    370 		if (aabbOverlap || isleafnode)
    371 		{
    372 			//next subnode
    373 			curIndex++;
    374 		}
    375 		else
    376 		{
    377 			//skip node
    378 			curIndex+= getEscapeNodeIndex(curIndex);
    379 		}
    380 	}
    381 	if(collided_results.size()>0) return true;
    382 	return false;
    383 }
    384 
    385 
    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)
    390 {
    391 	btAABB box0;
    392 	boxset0->getNodeBound(node0,box0);
    393 	btAABB box1;
    394 	boxset1->getNodeBound(node1,box1);
    395 
    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);
    399 
    400 }
    401 
    402 
    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)
    409 {
    410 
    411 
    412 
    413 	if( _quantized_node_collision(
    414 		boxset0,boxset1,trans_cache_1to0,
    415 		node0,node1,complete_primitive_tests) ==false) return;//avoid colliding internal nodes
    416 
    417 	if(boxset0->isLeafNode(node0))
    418 	{
    419 		if(boxset1->isLeafNode(node1))
    420 		{
    421 			// collision result
    422 			collision_pairs->push_pair(
    423 				boxset0->getNodeData(node0),boxset1->getNodeData(node1));
    424 			return;
    425 		}
    426 		else
    427 		{
    428 
    429 			//collide left recursive
    430 
    431 			_find_quantized_collision_pairs_recursive(
    432 								boxset0,boxset1,
    433 								collision_pairs,trans_cache_1to0,
    434 								node0,boxset1->getLeftNode(node1),false);
    435 
    436 			//collide right recursive
    437 			_find_quantized_collision_pairs_recursive(
    438 								boxset0,boxset1,
    439 								collision_pairs,trans_cache_1to0,
    440 								node0,boxset1->getRightNode(node1),false);
    441 
    442 
    443 		}
    444 	}
    445 	else
    446 	{
    447 		if(boxset1->isLeafNode(node1))
    448 		{
    449 
    450 			//collide left recursive
    451 			_find_quantized_collision_pairs_recursive(
    452 								boxset0,boxset1,
    453 								collision_pairs,trans_cache_1to0,
    454 								boxset0->getLeftNode(node0),node1,false);
    455 
    456 
    457 			//collide right recursive
    458 
    459 			_find_quantized_collision_pairs_recursive(
    460 								boxset0,boxset1,
    461 								collision_pairs,trans_cache_1to0,
    462 								boxset0->getRightNode(node0),node1,false);
    463 
    464 
    465 		}
    466 		else
    467 		{
    468 			//collide left0 left1
    469 
    470 
    471 
    472 			_find_quantized_collision_pairs_recursive(
    473 				boxset0,boxset1,
    474 				collision_pairs,trans_cache_1to0,
    475 				boxset0->getLeftNode(node0),boxset1->getLeftNode(node1),false);
    476 
    477 			//collide left0 right1
    478 
    479 			_find_quantized_collision_pairs_recursive(
    480 				boxset0,boxset1,
    481 				collision_pairs,trans_cache_1to0,
    482 				boxset0->getLeftNode(node0),boxset1->getRightNode(node1),false);
    483 
    484 
    485 			//collide right0 left1
    486 
    487 			_find_quantized_collision_pairs_recursive(
    488 				boxset0,boxset1,
    489 				collision_pairs,trans_cache_1to0,
    490 				boxset0->getRightNode(node0),boxset1->getLeftNode(node1),false);
    491 
    492 			//collide right0 right1
    493 
    494 			_find_quantized_collision_pairs_recursive(
    495 				boxset0,boxset1,
    496 				collision_pairs,trans_cache_1to0,
    497 				boxset0->getRightNode(node0),boxset1->getRightNode(node1),false);
    498 
    499 		}// else if node1 is not a leaf
    500 	}// else if node0 is not a leaf
    501 }
    502 
    503 
    504 void btGImpactQuantizedBvh::find_collision(const btGImpactQuantizedBvh * boxset0, const btTransform & trans0,
    505 		const btGImpactQuantizedBvh * boxset1, const btTransform & trans1,
    506 		btPairSet & collision_pairs)
    507 {
    508 
    509 	if(boxset0->getNodeCount()==0 || boxset1->getNodeCount()==0 ) return;
    510 
    511 	BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0;
    512 
    513 	trans_cache_1to0.calc_from_homogenic(trans0,trans1);
    514 
    515 #ifdef TRI_COLLISION_PROFILING
    516 	bt_begin_gim02_q_tree_time();
    517 #endif //TRI_COLLISION_PROFILING
    518 
    519 	_find_quantized_collision_pairs_recursive(
    520 		boxset0,boxset1,
    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
    525 
    526 }
    527 
    528 
    529