Beispiel #1
0
hkDemo::Result BroadphaseAddRemoveDemo::stepDemo()
{	
	#if defined(SELF_BENCHMARK)
	LARGE_INTEGER	counter0;
	printf("Benchmarking...\r\n");
	::QueryPerformanceCounter(&counter0);	
	for(int i=0;i<512;++i)
	{
		spawnFirework();
	}
	LARGE_INTEGER	counter1;
	LARGE_INTEGER	frequency;
	::QueryPerformanceCounter(&counter1);
	::QueryPerformanceFrequency(&frequency);
	printf("Time: %.I64d ms\r\n",((counter1.QuadPart-counter0.QuadPart)*1000)/frequency.QuadPart);
	exit(1);
	#endif
	
	if(m_env->m_window->getKeyboard().wasKeyPressed('B'))
	{
		m_useBatch=!m_useBatch;
	}
	if(m_env->m_window->getKeyboard().wasKeyPressed('D'))
	{
		m_draw=!m_draw;
	}
	
	if(m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_2)) m_useBatch=!m_useBatch;
	if(m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_3)) m_draw=!m_draw;

	m_world->lock();
	m_timer-=m_world->getSolverInfo()->m_deltaTime;
	if(m_timer<0)
	{
		HK_TIMER_BEGIN_LIST( "DemoAddBodies", "Add" );
		spawnFirework();
		if(m_bodies.getSize()>=m_maxbodies) m_timer+=m_rate;
		HK_TIMER_SPLIT_LIST( "Remove" );		
		flushFirework();
		HK_TIMER_END_LIST();
	}
	m_world->unlock();
	char		text[256];
	hkString::sprintf(text,"%d bodies [%d bodies per second]\r\n[B]atchs: %s\r\n[D]raw: %s",m_bodies.getSize(),(int)(m_count/m_rate),
																					m_useBatch?"ON":"OFF",
																					m_draw?"ON":"OFF");
	m_env->m_textDisplay->outputText(text,8,(int)m_env->m_window->getHeight()-96);
	
	return hkDefaultPhysicsDemo::stepDemo();
}
hkDemo::Result OptimizedWorldRaycastDemo::stepDemo()
{
	m_world->lock();

	m_time += m_timestep;

	//
	//	Create a number of ray directions
	//
	const int NUM_DIRECTIONS = 8; const hkReal increment = 2.0f;
	//const int NUM_DIRECTIONS = 125; const hkReal increment = 0.5f;

	hkVector4 rayDirections[NUM_DIRECTIONS];
	{
		int i = 0;
		for (hkReal x = -1.0f; x <= 1.0f; x += increment)
		{
			for (hkReal y = -1.0f; y <= 1.0f; y += increment)
			{
				for (hkReal z = -1.0f; z <= 1.0f; z+= increment)
				{
					rayDirections[i++].set(x,y,z);
				}
			}
		}
	}

	
	hkReal angle = 0.5f * m_time;
	
	// In these first chapter we simply call the hkpWorld castRay version with no further optimizations
	{
		angle += HK_REAL_PI * 0.3f;

		hkReal xPos = m_rayLength * 3.0f * hkMath::sin(angle);
		hkReal zPos = m_rayLength * 3.0f * hkMath::cos(angle);

		hkpWorldRayCastInput      inputs[NUM_DIRECTIONS];
		hkpClosestRayHitCollector collectors[NUM_DIRECTIONS];

		HK_TIMER_BEGIN("NotOptimized", HK_NULL);
		{
			for (int i = 0; i < NUM_DIRECTIONS; i++)
			{
				inputs[i].m_from.set( xPos, 0, zPos);
				inputs[i].m_to.setAddMul4(inputs[i].m_from, rayDirections[i], 1.f*m_rayLength);
				m_world->castRay(inputs[i], collectors[i]);
			}
		}
		HK_TIMER_END();
		displayHits( inputs, NUM_DIRECTIONS, collectors, hkColor::RED);
	}
	
	// This second set of raycasts (yellow) is using a the group functionality of the hkpWorldRayCaster.
	// Internally it builds an the aabb cache. This is an optimization for broadphase raycasts. 
	// Note that we need to pass in array of collectors to the hkpWorldRayCaster.
	// As the hkpWorldRayCaster has no clue about the size of each collector, we have to pass in the size.
	// Interesting if we use a size of 0, than all raycast will report to the same collector.
	{
		angle += HK_REAL_PI * 0.3f;

		hkReal xPos = m_rayLength * 3.0f * hkMath::sin(angle);
		hkReal zPos = m_rayLength * 3.0f * hkMath::cos(angle);

		hkpWorldRayCastInput inputs[NUM_DIRECTIONS];
		hkpClosestRayHitCollector collectors[NUM_DIRECTIONS];

		//
		//	Cast Rays
		//
		HK_TIMER_BEGIN("CastRayGroup", HK_NULL);
		{
			for (int i = 0; i < NUM_DIRECTIONS; i++)
			{
				inputs[i].m_from.set( xPos, 0, zPos);
				inputs[i].m_to.setAddMul4(inputs[i].m_from, rayDirections[i], 1.f*m_rayLength);

			}
			hkpWorldRayCaster rayCaster;
			rayCaster.castRayGroup( *m_world->getBroadPhase(), inputs, NUM_DIRECTIONS, m_world->getCollisionFilter(), collectors, sizeof(collectors[0]) ); 
		}
		HK_TIMER_END();
		displayHits( inputs, NUM_DIRECTIONS, collectors, hkColor::CYAN);
	}
	
	// This set of raycasts (yellow) is using a the hkpBroadPhaseAabbCache.
	// So by building the aabb cache. This is an optimization for broadphase raycasts. 
	// The idea is that the aabb cache is actually a reduced broadphase, just storing
	// objects inside the aabb. Therefore using this cache can speed up rayCasts significantly.
	// Unfortunately we cannot use our simple hkpWorld::castRay() function, but have to use
	// a small helper class hkpWorldRayCaster (which is actually used by the hkpWorld::castRay()).
	{
		angle += HK_REAL_PI * 0.3f;

		hkReal xPos = m_rayLength * 3.0f * hkMath::sin(angle);
		hkReal zPos = m_rayLength * 3.0f * hkMath::cos(angle);

		hkpWorldRayCastInput inputs[NUM_DIRECTIONS];
		hkpClosestRayHitCollector collectors[NUM_DIRECTIONS];

		//
		//	Calc Cache
		//
		HK_TIMER_BEGIN_LIST("UseAabbCache", "CalcCache");
		hkpBroadPhaseAabbCache* cache;
		int                    cacheSize;
		{	
			hkAabb aabb;
			aabb.m_min.set( xPos - m_rayLength, -m_rayLength, zPos-m_rayLength);
			aabb.m_max.set( xPos + m_rayLength, +m_rayLength, zPos+m_rayLength);

			cacheSize = m_world->getBroadPhase()->getAabbCacheSize();
			cache     = reinterpret_cast<hkpBroadPhaseAabbCache*>(hkAllocateStack<char>(cacheSize));
			
			m_world->getBroadPhase()->calcAabbCache( aabb, cache );
		}

		//
		//	Cast Rays
		//
		HK_TIMER_SPLIT_LIST("CastRays");
		{
			for (int i = 0; i < NUM_DIRECTIONS; i++)
			{
				inputs[i].m_from.set( xPos, 0, zPos);
				inputs[i].m_to.setAddMul4(inputs[i].m_from, rayDirections[i], 1.f*m_rayLength);

				hkpWorldRayCaster rayCaster;
				rayCaster.castRay( *m_world->getBroadPhase(), inputs[i], m_world->getCollisionFilter(), cache, collectors[i] ); 
			}
		}
		HK_TIMER_END_LIST();
		hkDeallocateStack<char>( (char*)cache);
		displayHits( inputs, NUM_DIRECTIONS, collectors, hkColor::YELLOW);
	}
	
	
	// This third set of raycasts (blue) is using a the hkpBroadPhaseAabbCache and
	// also makes use of the fact that many rays starting at the same position can
	// be handled specially.
	// Unfortunately we cannot use our simple hkpWorld::castRay() function, but have to use
	// a small helper class hkpWorldRayCaster (which is actually used by the hkpWorld::castRay()).
	{
		angle += HK_REAL_PI * 0.3f;

		hkReal xPos = m_rayLength * 3.0f * hkMath::sin(angle);
		hkReal zPos = m_rayLength * 3.0f * hkMath::cos(angle);

		hkpWorldRayCastInput      inputs[NUM_DIRECTIONS];
		hkpClosestRayHitCollector collectors[NUM_DIRECTIONS];

		//
		//	Calc Cache
		//
		HK_TIMER_BEGIN_LIST("CacheSameStart", "CalcCache");
		hkpBroadPhaseAabbCache* cache;
		int                    cacheSize;
		{	
			hkAabb aabb;
			aabb.m_min.set( xPos - m_rayLength, -m_rayLength, zPos-m_rayLength);
			aabb.m_max.set( xPos + m_rayLength, +m_rayLength, zPos+m_rayLength);

			cacheSize = m_world->getBroadPhase()->getAabbCacheSize();
			cache = reinterpret_cast<hkpBroadPhaseAabbCache*>(hkAllocateStack<char>(cacheSize));
			
			m_world->getBroadPhase()->calcAabbCache( aabb, cache );
		}
		
		//
		//	Cast Rays
		//
		HK_TIMER_SPLIT_LIST("CastRays");
		{
			for (int i = 0; i < NUM_DIRECTIONS; i++)
			{
				inputs[i].m_from.set( xPos, 0, zPos);
				inputs[i].m_to.setAddMul4(inputs[i].m_from, rayDirections[i], 1.f*m_rayLength);
			}
			hkpWorldRayCaster rayCaster;
			rayCaster.castRaysFromSinglePoint( *m_world->getBroadPhase(), inputs, NUM_DIRECTIONS, m_world->getCollisionFilter(), cache, collectors, hkSizeOf( collectors[0] ) ); 
		}
		HK_TIMER_END_LIST();
		hkDeallocateStack<char>( (char*)cache);
		displayHits( inputs, NUM_DIRECTIONS, collectors, hkColor::BLUE);
	}

	// This 4th set of raycasts (green) is using a the AabbPhantom
	// A phantom is like a persistent aabb cache, so it only makes sense if our aabb shows some
	// framecoherency. 
	// Unfortunetaly the current phantom implementations simply casts the ray against all objects
	// overlapping with the phantom. Therefor, if too many objects are intersecting the phantoms
	// aabb, performance could get bad.
	{
		angle += HK_REAL_PI * 0.3f;
		hkReal xPos = m_rayLength * 3.0f * hkMath::sin(angle);
		hkReal zPos = m_rayLength * 3.0f * hkMath::cos(angle);

		hkpWorldRayCastInput inputs[NUM_DIRECTIONS];
		hkpClosestRayHitCollector collectors[NUM_DIRECTIONS];

		HK_TIMER_BEGIN_LIST("AabbPhantom", "MovePhantom");
		{	
			hkAabb aabb;
			aabb.m_min.set( xPos - m_rayLength, -m_rayLength, zPos-m_rayLength);
			aabb.m_max.set( xPos + m_rayLength, +m_rayLength, zPos+m_rayLength);

			m_phantom->setAabb( aabb );
		}
		
		HK_TIMER_SPLIT_LIST("CastRays");

		{
			for (int i = 0; i < NUM_DIRECTIONS; i++)
			{
				inputs[i].m_from.set( xPos, 0, zPos);
				inputs[i].m_to.setAddMul4(inputs[i].m_from, rayDirections[i], 1.f*m_rayLength);
				m_phantom->castRay(inputs[i], collectors[i]);
			}
		}

		HK_TIMER_END_LIST();
		displayHits( inputs, NUM_DIRECTIONS, collectors, hkColor::GREEN);
	}

	// fastest (purple), combine all optimizations above
	// We are using a phantom to set up the broadphase cache. This avoids the problem of the hkpPhantom::castRay()
	{
		angle += HK_REAL_PI * 0.3f;
		hkReal xPos = m_rayLength * 3.0f * hkMath::sin(angle);
		hkReal zPos = m_rayLength * 3.0f * hkMath::cos(angle);

		hkpWorldRayCastInput inputs[NUM_DIRECTIONS];
		hkpClosestRayHitCollector collectors[NUM_DIRECTIONS];

		hkpBroadPhaseAabbCache* cache;
		int                    cacheSize;
		HK_TIMER_BEGIN_LIST("AllOpt.", "MovePhantomAndDoCache");
		{	
			hkAabb aabb;
			aabb.m_min.set( xPos - m_rayLength, -m_rayLength, zPos-m_rayLength);
			aabb.m_max.set( xPos + m_rayLength, +m_rayLength, zPos+m_rayLength);

			m_phantomUseCache->setAabb( aabb );

			cacheSize = m_world->getBroadPhase()->getAabbCacheSize();
			cache = reinterpret_cast<hkpBroadPhaseAabbCache*>(hkAllocateStack<char>(cacheSize));
			
			m_world->getBroadPhase()->calcAabbCache( m_phantomUseCache->getOverlappingCollidables(), cache );
		}

		HK_TIMER_SPLIT_LIST("CastRays");

		{
			for (int i = 0; i < NUM_DIRECTIONS; i++)
			{
				inputs[i].m_from.set( xPos, 0, zPos);
				inputs[i].m_to.setAddMul4(inputs[i].m_from, rayDirections[i], 1.f*m_rayLength);
			}
			hkpWorldRayCaster rayCaster;
			rayCaster.castRaysFromSinglePoint( *m_world->getBroadPhase(), inputs, NUM_DIRECTIONS, m_world->getCollisionFilter(), cache, collectors, hkSizeOf( collectors[0] ) ); 
		}

		HK_TIMER_END_LIST();
		hkDeallocateStack<char>( (char*)cache);
		displayHits( inputs, NUM_DIRECTIONS, collectors, hkColor::PURPLE);
	}

	m_world->unlock();

	return hkDefaultPhysicsDemo::stepDemo();
}
void AabbQueryDemo::queryAabbMT()
{
	HK_TIMER_BEGIN_LIST("queryAabbMT", "setup");

	hkAabb aabb;
	// Grab a body from the world, and compute it's AABB + some padding
	const hkpCollidable* queryCollidable;
	{
		queryCollidable = m_collidables[m_collIdx];
		hkpRigidBody* rb = hkGetRigidBody(queryCollidable);
		queryCollidable->getShape()->getAabb(rb->getTransform(), 20.0f, aabb);
	}

	hkArray<hkpKdTreeAabbCommand> commands;
	commands.setSize(numQueries);
	
	//
	// For performance timings, we query the same AABB multiple times and overwrite the results.
	// When using this, make sure to use different output arrays!
	//
	hkArray<hkPrimitiveId> output;
	output.setSize(50);

	//
	// Set up the commands for the job
	//
	for (int i=0; i<commands.getSize(); i++)
	{
		hkpKdTreeAabbCommand& command = commands[i];
		command.m_aabb = aabb;
		command.m_results = output.begin();
		command.m_resultsCapacity = output.getSize();
		command.m_numResultsOut = 0;
	}


	// 
	// Setup the job
	//
	hkArray<hkpRayCastQueryJobHeader> header(1);
	hkpKdTreeAabbJob aabbJob(header.begin(), commands.begin(), commands.getSize(), &m_semaphore);
	aabbJob.m_numTrees = 1;
	aabbJob.m_trees[0] = m_world->m_kdTreeManager->getTree();

	m_jobQueue->addJob( *reinterpret_cast<hkJobQueue::JobQueueEntry*>(&aabbJob), hkJobQueue::JOB_HIGH_PRIORITY );

	HK_TIMER_SPLIT_LIST("process");
	m_jobThreadPool->processAllJobs( m_jobQueue );
	m_jobThreadPool->waitForCompletion();
	m_semaphore.acquire();

	HK_TIMER_END_LIST();

	//
	// Run the same query on the broadphase for comparison purposes
	//
	hkArray<hkpBroadPhaseHandlePair> sapHits;
	{
		HK_TIME_CODE_BLOCK("BroadphaseQueryAabb", HK_NULL);
		for (int i=0; i<numQueries; i++)
		{
			sapHits.clear();
			m_world->getBroadPhase()->querySingleAabb( aabb, sapHits );
		}

	}

	//
	// Check results and draw 
	//
	for (int i=0; i<commands.getSize(); i++)
	{
		hkpKdTreeAabbCommand& command = commands[i];
		hkBool jobOk = compareHitArrays(command.m_aabb, command.m_results, command.m_numResultsOut, sapHits); 

		for (int j=0; j<command.m_numResultsOut; j++)
		{
			HK_SET_OBJECT_COLOR(command.m_results[j], hkColor::YELLOW);
		}
		HK_SET_OBJECT_COLOR((hkUlong)queryCollidable, hkColor::LIME);

		if( !jobOk )
		{
			m_env->m_textDisplay->outputText("MT Hit lits differed!", 20, 250, (hkUint32) hkColor::RED);
		}
	}


}