示例#1
0
void ScrapeParticleListener::contactProcessCallback(hkpContactProcessEvent& event)
{
	HK_TIMER_BEGIN("ScrapeParticleListener CB", this);

	hkpProcessCollisionData* collisionData = event.m_collisionData;

	for(int i = 0; i < collisionData->getNumContactPoints(); ++i)
	{
		hkpSimpleConstraintContactMgr* mgr = static_cast<hkpSimpleConstraintContactMgr*>(event.m_internalContactMgr);
		hkpRigidBody* rigidBodyA = mgr->getConstraintInstance()->getRigidBodyA();
		hkpRigidBody* rigidBodyB = mgr->getConstraintInstance()->getRigidBodyB();

		if(rigidBodyA->hasProperty(m_emitPropertyKey) && rigidBodyB->hasProperty(m_emitPropertyKey))
		{
			// Compute relative velocity at contact point.
			hkContactPoint& contactPoint = collisionData->getContactPoint(i).m_contact;
			hkVector4 velocityA, velocityB, relativeVelocity;
			rigidBodyA->getPointVelocity(contactPoint.getPosition(), velocityA);
			rigidBodyB->getPointVelocity(contactPoint.getPosition(), velocityB);
			relativeVelocity.setSub4(velocityA, velocityB);
			hkReal relativeSpeed = relativeVelocity.length3();

			if(relativeSpeed > m_relativeSpeedThreshold)
			{
				hkVector4 direction, normal;
				if(velocityA.lengthSquared3() > velocityB.lengthSquared3())
				{
					direction.setNeg4(relativeVelocity);
					normal = contactPoint.getNormal();
				}
				else
				{
					direction = relativeVelocity;
					normal.setNeg4(contactPoint.getNormal());
				}
				direction.normalize3();

				// Bend the velocity towards the contact normal. This looks slightly better but can be commented out if desired.
				const hkReal t = 0.7f;
				direction.mul4(t);
				direction.addMul4(1.f-t, normal);
				direction.normalize3();

				// A critical section has to be used here since listener callbacks can be called from different threads.
				m_criticalSection.enter();
				ContactInfo& contactInfo = m_contacts.expandOne();
				contactInfo.m_position = contactPoint.getPosition();
				contactInfo.m_direction = direction;
				contactInfo.m_relativeSpeed = relativeSpeed;
				m_criticalSection.leave();
			}
		}
	}

	HK_TIMER_END();
}
void SlidingWorldDemo::recalcAabbsAfterBroadphaseRecenter( hkpWorld* world )
{
	HK_TIMER_BEGIN("RecalcAabbs", HK_NULL );

	// Iterate over all simulation islands.
	{
		// Fixed island
		const hkpSimulationIsland* island = world->getFixedIsland();
		for (int b = 0; b < island->getEntities().getSize(); b++ )
		{
			hkpRigidBody* body =  static_cast<hkpRigidBody*>( island->getEntities()[b]);
			body->updateCachedAabb();
		}
	}
	{
		// Inactive islands
		const hkArray<hkpSimulationIsland*>& islands = world->getInactiveSimulationIslands();
		for (int i = 0; i < islands.getSize(); i++ )
		{
			hkpSimulationIsland* island = islands[i];
			for (int b = 0; b < island->getEntities().getSize(); b++ )
			{
				hkpRigidBody* body =  static_cast<hkpRigidBody*>( island->getEntities()[b]);
				body->updateCachedAabb();
			}
		}
	}
	{
		// Active Islands
		const hkArray<hkpSimulationIsland*>& islands = world->getActiveSimulationIslands();
		for (int i = 0; i < islands.getSize(); i++ )
		{
			hkpSimulationIsland* island = islands[i];
			for (int b = 0; b < island->getEntities().getSize(); b++ )
			{
				hkpRigidBody* body =  static_cast<hkpRigidBody*>( island->getEntities()[b]);
				body->updateCachedAabb();
			}
		}
	}

	HK_TIMER_END();
}
hkDemo::Result AsymetricCharacterRbDemo::stepDemo()
{

	// Update actual time
	m_time += m_timestep;	


	hkQuaternion orient;
	{
		m_world->lock();

		hkReal posX = 0.f;
		hkReal posY = 0.f;
		{
			float deltaAngle = 0.f;
			CharacterUtils::getUserInputForCharacter(m_env, deltaAngle, posX, posY);
			m_currentAngle += deltaAngle;
			orient.setAxisAngle(UP, m_currentAngle);
		}

		hkpCharacterInput input;
		hkpCharacterOutput output;
		{
			input.m_inputLR = posX;
			input.m_inputUD = posY;

			input.m_wantJump =  m_env->m_window->getMouse().wasButtonPressed(HKG_MOUSE_LEFT_BUTTON)
				|| m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_1);
			input.m_atLadder = false;

			input.m_up = UP;
			input.m_forward.set(1,0,0);
			input.m_forward.setRotatedDir( orient, input.m_forward );

			hkStepInfo stepInfo;
			stepInfo.m_deltaTime = m_timestep;
			stepInfo.m_invDeltaTime = 1.0f/m_timestep;
			stepInfo.m_endTime = m_time;
			
			input.m_stepInfo = stepInfo;
			
			input.m_characterGravity.set(0,-16,0);
			input.m_velocity = m_characterRigidBody->getLinearVelocity();
			input.m_position = m_characterRigidBody->getPosition();

			hkpSurfaceInfo ground;
			m_characterRigidBody->checkSupport( stepInfo, ground);
		
			// Avoid accidental state changes (Smooth movement on stairs)
			// During transition supported->unsupported continue to return N-frames hkpSurfaceInfo data from previous supported state
			{

				// Number of frames to skip (continue with previous hkpSurfaceInfo data)
				const int skipFramesInAir = 5;

				if (input.m_wantJump)
				{
					m_framesInAir = skipFramesInAir;
				}

				if ( ground.m_supportedState != hkpSurfaceInfo::SUPPORTED )
				{
					if (m_framesInAir < skipFramesInAir)
					{
						input.m_isSupported = true;
						input.m_surfaceNormal = m_previousGround->m_surfaceNormal;
						input.m_surfaceVelocity = m_previousGround->m_surfaceVelocity;
						input.m_surfaceMotionType = m_previousGround->m_surfaceMotionType;
					}
					else
					{
						input.m_isSupported = false;
						input.m_surfaceNormal = ground.m_surfaceNormal;
						input.m_surfaceVelocity = ground.m_surfaceVelocity;
						input.m_surfaceMotionType = ground.m_surfaceMotionType;
					}			

					m_framesInAir++;
				}
				else
				{
					input.m_isSupported = true;
					input.m_surfaceNormal = ground.m_surfaceNormal;
					input.m_surfaceVelocity = ground.m_surfaceVelocity;
					input.m_surfaceMotionType = ground.m_surfaceMotionType;

					m_previousGround->set(ground);

					// Reset old number of frames
					if (m_framesInAir > skipFramesInAir)
					{
						m_framesInAir = 0;
					}			

				}
			}			
	
		}

		// Apply the character state machine
		{
			HK_TIMER_BEGIN( "update character state", HK_NULL );

			m_characterContext->update(input, output);

			HK_TIMER_END();
		}

		// Apply the player character controller
		{
			HK_TIMER_BEGIN( "simulate character", HK_NULL );

			m_characterRigidBody->setLinearVelocity(output.m_velocity, m_timestep);	

			HK_TIMER_END();
		}

		// Rotate the character
		{
			hkVector4 offset; offset.set(1,0,0);
			offset.setRotatedDir( orient , offset);

			hkRotation rotation;
			hkVector4& col0 = rotation.getColumn(0);
			hkVector4& col1 = rotation.getColumn(1);
			hkVector4& col2 = rotation.getColumn(2);

			// Smoothed surface normal
			hkVector4 surfaceNorm;
			surfaceNorm = input.m_isSupported ? input.m_surfaceNormal : (hkVector4)UP;
			m_rigidBodyNormal.addMul4( 0.05f, surfaceNorm );
			m_rigidBodyNormal.normalize3();

			col1 = m_rigidBodyNormal;
			col2.setCross( col1, offset); 
			col2.normalize3();
			col0.setCross( col1, col2 );

#ifdef HK_DEBUG

			HK_DISPLAY_ARROW(m_characterRigidBody->getPosition(), col0, 0xffff00ff);
			HK_DISPLAY_ARROW(m_characterRigidBody->getPosition(), col1, 0xff00ffff);
			HK_DISPLAY_ARROW(m_characterRigidBody->getPosition(), col2, 0xff0000ff);

#endif
			// Forward orientation controller
			reorientCharacter( rotation );

		}

		// Display states infos
		{
			// classical controller state
			hkpCharacterStateType state = m_characterContext->getState();
			char * stateStr;

			switch (state)
			{
			case HK_CHARACTER_ON_GROUND:
				stateStr = "On Ground";	break;
			case HK_CHARACTER_JUMPING:
				stateStr = "Jumping"; break;
			case HK_CHARACTER_IN_AIR:
				stateStr = "In Air"; break;
			case HK_CHARACTER_CLIMBING:
				stateStr = "Climbing"; break;
			default:
				stateStr = "Other";	break;
			}

			char buffer[255];
			hkString::snprintf(buffer, 255, "State: %s ", stateStr);
			m_env->m_textDisplay->outputText(buffer, 20, 450, 0xffffffff);			
		
		m_world->unlock();

		}

		// Step the world
		{
			hkDefaultPhysicsDemo::stepDemo();
		}
		
		m_world->lock();

		// Camera Handling
		{
			const hkReal height = 1.25f;
			hkVector4 forward;
			forward.set(1,0,0);
			forward.setRotatedDir( orient, forward );

			hkVector4 from, to;
			to = m_characterRigidBody->getRigidBody()->getPosition();

			hkVector4 dir;
			dir.setMul4( height, UP );
			dir.addMul4( -4.0f, forward);

			from.setAdd4(to, dir);
			setupDefaultCameras(m_env, from, to, UP, 1.0f);
		}

		m_world->unlock();
	
	}

	return hkDemo::DEMO_OK;
}
示例#4
0
hkDemo::Result UnevenTerrainVsDemo::stepDemo()
{
	HK_TIMER_BEGIN( "simulate multiply characters", HK_NULL );

	m_world->lock();

	hkVector4 up;
	up.setNeg4( m_world->getGravity() );
	up.normalize3();

	m_tick++;

	hkpCharacterInput inputRb;
	hkpCharacterInput inputProxy;
	// Fill in the state machine input structure for character rigid body
	{
		inputRb.m_atLadder = false;
		inputRb.m_up = up;

		// Steer the characters
		inputRb.m_inputLR = 0.0f;
		inputRb.m_inputUD = 1.0f;
		{
			// The factor 70.0f gives a turning circle which fits in the level 
			// for the default walk speed of 10.0f.
			hkReal walkSpeedFactor = m_options.m_characterWalkSpeed / 70.0f;
			hkReal time = hkReal(m_tick) * walkSpeedFactor / 60.0f;
			const hkReal x = hkMath::sin(time);
			const hkReal z = hkMath::cos(time);
			inputRb.m_forward.set( x, 0, z );
			inputRb.m_forward.normalize3();
		}

		inputRb.m_wantJump = false;
	
		hkStepInfo stepInfo;
		stepInfo.m_deltaTime = m_timestep;
		stepInfo.m_invDeltaTime = 1.0f/m_timestep;

		inputRb.m_stepInfo = stepInfo;

		inputRb.m_characterGravity.set( 0.0f, m_options.m_characterGravity, 0.0f );
		
		inputProxy = inputRb;

		// character rigid body specific code

		inputRb.m_velocity = m_characterRigidBody->getLinearVelocity();
		inputRb.m_position = m_characterRigidBody->getPosition();
		m_characterRigidBody->checkSupport(stepInfo, inputRb.m_surfaceInfo);

		filterStates( m_filterRigidBody, inputRb.m_surfaceInfo );

		m_supportHistoryRb <<= 1;
		if ( inputRb.m_surfaceInfo.m_supportedState == hkpSurfaceInfo::SUPPORTED )
		{
			++m_supportHistoryRb;
		}
		else
		{
			++m_unsupportedFramesCountRb;
		}


		// character proxy specific code

		inputProxy.m_velocity = m_characterProxy->getLinearVelocity();
		inputProxy.m_position = m_characterProxy->getPosition();
		hkVector4 down;	down.setNeg4(UP);
		m_characterProxy->checkSupport(down, inputProxy.m_surfaceInfo);

		filterStates( m_filterProxy, inputProxy.m_surfaceInfo );
		
		m_supportHistoryProxy <<= 1;
		if ( inputProxy.m_surfaceInfo.m_supportedState == hkpSurfaceInfo::SUPPORTED )
		{
			++m_supportHistoryProxy;
		}
		else
		{
			++m_unsupportedFramesCountProxy;
		}
	}

	hkpCharacterOutput outputRb;
	hkpCharacterOutput outputProxy;
	// Apply the character state machine
	{
		HK_TIMER_BEGIN( "update character state", HK_NULL );

		m_characterContext->update(inputRb, outputRb);
		m_characterProxyContext->update(inputProxy, outputProxy);

		HK_TIMER_END();

	}

	//Apply the character controllers
	{
		HK_TIMER_BEGIN( "simulate character", HK_NULL );

		// Feed the output velocity from state machine into character rigid body
		m_characterRigidBody->setLinearVelocity(outputRb.m_velocity, m_timestep);
		
		m_characterProxy->setLinearVelocity(outputProxy.m_velocity );
		hkStepInfo si;
		si.m_deltaTime = m_timestep;
		si.m_invDeltaTime = 1.0f/m_timestep;
		m_characterProxy->integrate( si, m_world->getGravity() );

		HK_TIMER_END();
	}

	{
		// If the character has fallen off the world we reposition them
		if ( ( m_characterProxy->getPosition()(1) < -10.0f ) || ( m_characterRigidBody->getPosition()(1) < -10.0f ) )
		{
			m_characterProxy->setPosition( characterStart );
			m_characterProxy->setLinearVelocity( hkVector4::getZero() );
			m_characterRigidBody->getRigidBody()->setPosition(characterStart);
			m_characterRigidBody->setLinearVelocity( hkVector4::getZero(), m_timestep );
			m_tick = 0;
		}
	}

	m_world->unlock();
	
	// Display state
	{
		char historyRb[33];
		char historyProxy[33];
		char buffer[255];

		for ( int i = 0; i < 32; ++i )
		{
			historyRb[i] = m_supportHistoryRb & ( 1 << i ) ? '#' : '_';
			historyProxy[i] = m_supportHistoryProxy & ( 1 << i ) ? '#' : '_';
		}
		historyRb[32] = '\0';
		historyProxy[32] = '\0';

		hkString::sprintf( buffer, "Rigid body unsupported frames: %d\n"
								   "Proxy unsupported frames:      %d\n\n"
								   "Rigid body support history:    %s\n"
								   "Proxy support history:         %s\n", m_unsupportedFramesCountRb, m_unsupportedFramesCountProxy, historyRb, historyProxy );

		m_env->m_textDisplay->outputText( buffer, 20, 200, 0xffffffff );
	}

	// Step the world
	{
		hkDefaultPhysicsDemo::stepDemo();
	}

	HK_TIMER_END();

	return hkDemo::DEMO_OK;
}
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 SlidingWorldDemo::shiftAllGameObjectDataSilently( hkpWorld* world, const hkVector4& effectiveShiftDistance )
{
	HK_TIMER_BEGIN("ShiftObjects", HK_NULL );

	// Iterate over all simulation islands.
	{
		// Fixed island
		const hkpSimulationIsland* island = world->getFixedIsland();
		for (int b = 0; b < island->getEntities().getSize(); b++ )
		{
			hkpRigidBody* body =  static_cast<hkpRigidBody*>( island->getEntities()[b]);
			hkVector4 newPos = body->getPosition();
			newPos.add4( effectiveShiftDistance );
			body->getRigidMotion()->setPosition( newPos );
			body->updateCachedAabb();
			HK_UPDATE_GEOMETRY( body->getTransform(), (hkUlong)body->getCollidable() );
		}
	}
	{
		// Inactive islands
		const hkArray<hkpSimulationIsland*>& islands = world->getInactiveSimulationIslands();
		for (int i = 0; i < islands.getSize(); i++ )
		{
			hkpSimulationIsland* island = islands[i];
			for (int b = 0; b < island->getEntities().getSize(); b++ )
			{
				hkpRigidBody* body =  static_cast<hkpRigidBody*>( island->getEntities()[b]);
				hkVector4 newPos = body->getPosition();
				newPos.add4( effectiveShiftDistance );
				body->getRigidMotion()->setPosition( newPos );
				body->updateCachedAabb();
				HK_UPDATE_GEOMETRY( body->getTransform(), (hkUlong)body->getCollidable() );
			}
		}
	}
	{
		// Active Islands
		const hkArray<hkpSimulationIsland*>& islands = world->getActiveSimulationIslands();
		for (int i = 0; i < islands.getSize(); i++ )
		{
			hkpSimulationIsland* island = islands[i];
			for (int b = 0; b < island->getEntities().getSize(); b++ )
			{
				hkpRigidBody* body =  static_cast<hkpRigidBody*>( island->getEntities()[b]);
				hkVector4 newPos = body->getPosition();
				newPos.add4( effectiveShiftDistance );
				body->getRigidMotion()->setPosition( newPos );
				body->updateCachedAabb();
				HK_UPDATE_GEOMETRY( body->getTransform(), (hkUlong)body->getCollidable() );

				// You also need to shift contact points to prevent them from becoming stale.
				// To do this iterate over all contact points maintained by the entity's collision agents.
				//
				// Each entity, if in contact with another entity, has a collision agent to manage contacts.
				// The collision agents in turn manage contact points via a contact point
				// manager.  To shift contact points we shift all contact points in the manager by the
				// effectiveShiftDistance passed in.
				hkpLinkedCollidable& collidableEx = *body->getLinkedCollidable();
				for (int collidableIndex = 0; collidableIndex < collidableEx.m_collisionEntries.getSize(); collidableIndex++)
				{
					hkpAgentNnEntry* entry = collidableEx.m_collisionEntries[collidableIndex].m_agentEntry;

					hkpDynamicsContactMgr* contactManager = static_cast<hkpDynamicsContactMgr*>(entry->m_contactMgr);

					HK_ASSERT(0x0, contactManager != HK_NULL);

					hkArray<hkContactPointId> contactPointIds;
					contactManager->getAllContactPointIds( contactPointIds );

					for( int contactPointIndex = 0; contactPointIndex < contactPointIds.getSize(); ++contactPointIndex )
					{
						hkContactPoint* contactPoint = contactManager->getContactPoint( contactPointIds[contactPointIndex] );

						hkVector4 nPos = contactPoint->getPosition();
						nPos.add4( effectiveShiftDistance );
						contactPoint->setPosition( nPos );
					}
				}
			}
		}
	}

	// Iterate over all phantoms, *except for the ones attached to the broadphase*, ie the borders
	{
		for ( int p = 0; p < world->getPhantoms().getSize(); p++ )
		{
			hkpPhantom* phantom = world->getPhantoms()[p];

			if( phantom->getCollidable()->getType() != hkpWorldObject::BROAD_PHASE_BORDER ) 
			{
				switch( phantom->getType())
				{
				case HK_PHANTOM_AABB:
					{
						hkpAabbPhantom* aabbPhantom = static_cast<hkpAabbPhantom*>( phantom );
						// Now do a bad trick to move the aabb.
						hkAabb& aabb = const_cast<hkAabb&>( aabbPhantom->getAabb() );
						aabb.m_min.add4( effectiveShiftDistance );
						aabb.m_max.add4( effectiveShiftDistance );
						break;
					}
				case HK_PHANTOM_SIMPLE_SHAPE:
				case HK_PHANTOM_CACHING_SHAPE:
					{
						hkpShapePhantom* shapePhantom = static_cast<hkpShapePhantom*>( phantom );
						hkTransform& transform = const_cast<hkTransform&>( shapePhantom->getTransform());
						transform.getTranslation().add4( effectiveShiftDistance );
						break;
					}
				default:
					HK_ASSERT2(0xf041604,0,"Unknown Phantom Type" );
				}
			}
		}
	}
	HK_TIMER_END();
}
hkDemo::Result PlatformsCharacterRbDemo::stepDemo()
{
	// Process inputs, calculate state, set new velocity
	{
		m_world->lock();

		// update total run time
		m_time += m_timestep;

		//	Get user input data
		hkReal posX = 0.f;
		hkReal posY = 0.f;
		{
			float deltaAngle = 0.f;
			CharacterUtils::getUserInputForCharacter(m_env, deltaAngle, posX, posY);
			m_currentAngle += deltaAngle;
			m_currentOrient.setAxisAngle(UP, m_currentAngle);
		}

		hkpCharacterInput input;
		hkpCharacterOutput output;
		{
			input.m_inputLR = posX;
			input.m_inputUD = posY;

			input.m_wantJump =  m_env->m_window->getMouse().wasButtonPressed(HKG_MOUSE_LEFT_BUTTON)
				|| m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_1);
			input.m_atLadder = false;

			input.m_up = UP;
			input.m_forward.set(1,0,0);
			input.m_forward.setRotatedDir( m_currentOrient, input.m_forward );

			hkStepInfo stepInfo;
			stepInfo.m_deltaTime = m_timestep;
			stepInfo.m_invDeltaTime = 1.0f/m_timestep;
			stepInfo.m_endTime = m_time;

			input.m_stepInfo = stepInfo;
			input.m_characterGravity.set(0,0,-16);
			input.m_velocity = m_characterRigidBody->getLinearVelocity();
			input.m_position = m_characterRigidBody->getPosition();

			hkpSurfaceInfo ground;
			m_characterRigidBody->checkSupport(stepInfo,ground);

			input.m_isSupported = (ground.m_supportedState == hkpSurfaceInfo::SUPPORTED);
			input.m_surfaceNormal = ground.m_surfaceNormal;
			input.m_surfaceVelocity = ground.m_surfaceVelocity;
			input.m_surfaceMotionType = ground.m_surfaceMotionType;
			
		}

		// Apply the character state machine
		{
			HK_TIMER_BEGIN( "update character state", HK_NULL );

			m_characterContext->update(input, output);

			HK_TIMER_END();
		}

		//Apply the player character controller
		{
			HK_TIMER_BEGIN( "simulate character", HK_NULL );

			// Feed output velocity from state machine into character rigid body
			m_characterRigidBody->setLinearVelocity(output.m_velocity, m_timestep);

			HK_TIMER_END();
		}

		// Display state
		{
			hkpCharacterStateType state = m_characterContext->getState();
			char * stateStr;

			switch (state)
			{
			case HK_CHARACTER_ON_GROUND:
				stateStr = "On Ground";	break;
			case HK_CHARACTER_JUMPING:
				stateStr = "Jumping"; break;
			case HK_CHARACTER_IN_AIR:
				stateStr = "In Air"; break;
			case HK_CHARACTER_CLIMBING:
				stateStr = "Climbing"; break;
			default:
				stateStr = "Other";	break;
			}
			char buffer[255];
			hkString::snprintf(buffer, 255, "State : %s", stateStr);
			m_env->m_textDisplay->outputText(buffer, 20, 270, 0xffffffff);
		}

		m_world->unlock();
	}

	// Step the world
	{
		hkDefaultPhysicsDemo::stepDemo();
	}
	
	// Move the platforms
	{
		m_world->lock();

		moveHorizontalPlatform();

		moveVerticalPlatform();

		m_world->unlock();
	}

	// Transparent camera handling
	{
		m_world->lock();

		cameraHandling();

		m_world->unlock();
	}

	return hkDemo::DEMO_OK;
}
hkDemo::Result CharacterDemo::stepDemo()
{

	hkVector4 up;
	hkQuaternion orient;

	{
		m_world->lock();

		//	Get user input data
		int m_upAxisIndex = 2;
		up.setZero4();
		up(m_upAxisIndex) = 1;

		hkReal posX = 0.f;
		hkReal posY = 0.f;
		{
			float deltaAngle = 0.f;
			CharacterUtils::getUserInputForCharacter(m_env, deltaAngle, posX, posY);
			m_currentAngle += deltaAngle;
			orient.setAxisAngle(up, m_currentAngle);
		}

		hkpCharacterInput input;
		hkpCharacterOutput output;
		{
			input.m_inputLR = posX;
			input.m_inputUD = posY;

			input.m_wantJump =  m_env->m_window->getMouse().wasButtonPressed(HKG_MOUSE_LEFT_BUTTON)
				|| m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_1);
			input.m_atLadder = m_listener->m_atLadder;

			input.m_up = up;
			input.m_forward.set(1,0,0);
			input.m_forward.setRotatedDir( orient, input.m_forward );

			input.m_stepInfo.m_deltaTime = m_timestep;
			input.m_stepInfo.m_invDeltaTime = 1.0f / m_timestep;
			input.m_characterGravity.set(0,0,-16);
			input.m_velocity = m_characterProxy->getLinearVelocity();
			input.m_position = m_characterProxy->getPosition();

			if (m_listener->m_atLadder)
			{
				hkVector4 right, ladderUp;
				right.setCross( up, m_listener->m_ladderNorm );
				ladderUp.setCross( m_listener->m_ladderNorm, right );
				// Calculate the up vector for the ladder
				if (ladderUp.lengthSquared3() > HK_REAL_EPSILON)
				{
					ladderUp.normalize3();
				}

				// Reorient the forward vector so it points up along the ladder
				input.m_forward.addMul4( -m_listener->m_ladderNorm.dot3(input.m_forward), m_listener->m_ladderNorm);
				input.m_forward.add4( ladderUp );
				input.m_forward.normalize3();

				input.m_surfaceNormal = m_listener->m_ladderNorm;
				input.m_surfaceVelocity = m_listener->m_ladderVelocity;
			}
			else 
			{
				hkVector4 down;	down.setNeg4(up);
				hkpSurfaceInfo ground;
				m_characterProxy->checkSupport(down, ground);
				input.m_isSupported = ground.m_supportedState == hkpSurfaceInfo::SUPPORTED;

				input.m_surfaceNormal = ground.m_surfaceNormal;
				input.m_surfaceVelocity = ground.m_surfaceVelocity;
			}
		}

		// Apply the character state machine
		{
			HK_TIMER_BEGIN( "update character state", HK_NULL );

			m_characterContext->update(input, output);

			HK_TIMER_END();
		}

		//Apply the player character controller
		{
			HK_TIMER_BEGIN( "simulate character", HK_NULL );

			// Feed output from state machine into character proxy
			m_characterProxy->setLinearVelocity(output.m_velocity);

			hkStepInfo si;
			si.m_deltaTime = m_timestep;
			si.m_invDeltaTime = 1.0f/m_timestep;
			m_characterProxy->integrate( si, m_world->getGravity() );

			HK_TIMER_END();
		}

		// Display state
		{
			hkpCharacterStateType state = m_characterContext->getState();
			char * stateStr;

			switch (state)
			{
			case HK_CHARACTER_ON_GROUND:
				stateStr = "On Ground";	break;
			case HK_CHARACTER_JUMPING:
				stateStr = "Jumping"; break;
			case HK_CHARACTER_IN_AIR:
				stateStr = "In Air"; break;
			case HK_CHARACTER_CLIMBING:
				stateStr = "Climbing"; break;
			default:
				stateStr = "Other";	break;
			}
			char buffer[255];
			hkString::snprintf(buffer, 255, "State : %s", stateStr);
			m_env->m_textDisplay->outputText(buffer, 20, 270, 0xffffffff);
		}

		//
		// Handle crouching
		//
		{
			hkBool wantCrouch = ( m_env->m_window->getMouse().getButtonState() & HKG_MOUSE_RIGHT_BUTTON )
				|| (m_env->m_gamePad->getButtonState() & HKG_PAD_BUTTON_2);

			hkBool isCrouching = m_phantom->getCollidable()->getShape() == m_crouchShape;


			// We want to stand
			if (isCrouching && !wantCrouch)
			{
				swapPhantomShape(m_standShape);
			}

			// We want to crouch
			if (!isCrouching && wantCrouch)
			{
				swapPhantomShape(m_crouchShape);
			}
		}
		m_world->unlock();
	}

	// Step the world
	hkDefaultPhysicsDemo::stepDemo();

	// Camera Handling
	{
		m_world->lock();
		{
			const hkReal height = .7f;
			hkVector4 forward;
			forward.set(1,0,0);
			forward.setRotatedDir( orient, forward );

			hkVector4 from, to;
			to = m_characterProxy->getPosition();
			to.addMul4(height, up);

			hkVector4 dir;
			dir.setMul4( height, up );
			dir.addMul4( -4.f, forward);

			from.setAdd4(to, dir);
			setupDefaultCameras(m_env, from, to, up, 1.0f);
		}

		m_world->unlock();
	}

	return hkDemo::DEMO_OK;
}
示例#9
0
void ShapeQueryDemo::phantomRayCast( hkpWorld* world, hkReal time, hkArray<hkpAabbPhantom*>& phantoms, hkBool useCollector )
{
	const int N_RAY_CASTS = 10;

	hkpWorldRayCastInput  rayInputs[N_RAY_CASTS];
	hkpWorldRayCastOutput rayOutputs[N_RAY_CASTS];
	hkpClosestRayHitCollector rayCollector[ N_RAY_CASTS ];

	hkVector4 displacement( 0.0f, -30.0f, 0.0f );

	//	Perform all queries in one go (do not interleave with examining the results,
	//  as this is bad for code and data cache.
	{
		for ( int i = 0; i < N_RAY_CASTS; i++ )
		{
			hkpWorldRayCastInput& in = rayInputs[i];

			// create a new position: all objects move in a circle
			hkReal t = time + (HK_REAL_PI * 2 * i) / N_RAY_CASTS;
			hkVector4 pos( hkMath::sin( t ) * 12.0f, 10.0f, hkMath::cos( t ) * 12.0f );

			//	Set our position in our input structure
			in.m_from = pos;
			in.m_to.setAdd4( pos, displacement );


			//
			// Query for intersecting objects
			//
			for (int k = 0; k < NUM_ITER ; k++ )
			{
				HK_TIMER_BEGIN("raycast", HK_NULL);

				//	Move our phantom so it encapsulates our ray
				hkpAabbPhantom* phantom = phantoms[i];
				{
					hkAabb aabb;
					aabb.m_min.setMin4( in.m_to, in.m_from );
					aabb.m_max.setMax4( in.m_to, in.m_from );
					phantom->setAabb( aabb );
				}

				if ( useCollector )
				{
					hkpClosestRayHitCollector& collector = rayCollector[i];
					collector.reset();
					phantom->castRay( in, collector );
				}
				else
				{
					hkpWorldRayCastOutput& out = rayOutputs[i];
					out.reset();
					phantom->castRay( in, out );
				}
				HK_TIMER_END( );
			}
		}
	}

	//
	//	Batch display the results
	//	NOTE that phantom displays have been forced off for this variant.
	//
	{
		for ( int i = 0; i < N_RAY_CASTS; i++ )
		{
			hkpWorldRayCastInput& in = rayInputs[i];

			const hkpWorldRayCastOutput* out;
			if ( useCollector )
			{
				 out = &rayCollector[i].getHit();
				 hkVector4 off(.1f,0,0);
				 in.m_from.add4( off );
				 in.m_to.add4( off );
			}
			else
			{
				out = &rayOutputs[i];
			}
			
			//	Display the ray
			{
				hkVector4 hitPoint;	hitPoint.setInterpolate4( in.m_from, in.m_to, out->m_hitFraction );
				HK_DISPLAY_LINE(in.m_from, hitPoint, hkColor::rgbFromChars( 240, 200, 0, 200 ));
			}

			//	Display the result
			if ( out->hasHit() )
			{
				displayRayHit( world, in, *out );
			}
		}
	}
}
hkDemo::Result PlanetGravityDemo::stepDemo()
{
	// Update lighting
	{
		// Update the light source to be at the camera
		float position[3];
		m_cameraPosition.store3( position );
		m_flashLight->setPosition( position );

		// Update the light direction to be pointing toward the character controller rigid body
		hkVector4 directionVector;
		directionVector.setSub4( m_cameraPosition, m_characterRigidBody->getPosition() );
		directionVector.mul4( -1.0f );
		directionVector.normalize3();

		float direction[3];
		directionVector.store3( direction );
		m_flashLight->setDirection( direction );
	}

	// Detach the camera from the character when P is pressed.
	if( m_env->m_window->getKeyboard().wasKeyPressed('P') )
	{
		m_detachedCamera = !m_detachedCamera;
	}

	// Update turrets
	for( int i = 0; i < m_turrets.getSize(); i++ )
	{
		Turret& turret = m_turrets[i];
		turret.cooldown -= m_timestep;
		
		// Make the turret spin
		turret.hinge->setMotorTargetAngle( turret.hinge->getMotorTargetAngle() + ( m_timestep / 5.f ) );

		// Bail out if the turret is "hot"
		if( turret.cooldown > 0.0f )
		{
			continue;
		}

		// Generate a curved raycast and shoot the ray
		// This has to be done every time-step as it's in world-space
		{
			const hkReal radius = 14.8f;
			hkRotation rot;
			hkVector4 offset;
			hkVector4 turretDown;
			
			rot.set( turret.turretRigidBody->getRotation() );
			offset = turret.turretRigidBody->getPosition();
			turretDown.setMul4( -1.0f, rot.getColumn(2) );

			hkpLinearParametricCurve myCurve;
			// Move the ray's source a little up so it's coming from the center of the barrel
			hkTransform localTransform( hkQuaternion::getIdentity(), hkVector4( 0.0f, 0.0f, 0.7f ) );

			// Create a curve of 20 points
			for( int j = 0; j < 20; j++ )
			{
				hkReal angle = HK_REAL_PI * static_cast<hkReal>(j) / 15.0f;

				hkVector4 newPoint( radius * 2.0f * sin( angle ),
									0.0f,
									radius * 2.0f * cos( angle ) );

				newPoint.setTransformedPos( localTransform, newPoint );
				newPoint.setTransformedPos( turret.turretRigidBody->getTransform(), newPoint );
				newPoint.addMul4( radius * 2.0f, turretDown );

				myCurve.addPoint( newPoint );
			}

			// We only need the closest hit (as our lasers can't pass through objects)
			//  so hkpClosestRayHitCollector is used.
			hkpClosestRayHitCollector raycastOutput;
			hkReal t = castCurvedRay( raycastOutput, myCurve, 20 );

			// Apply a large force to the closest rb we hit, along the tangent at the colliding point
			if( raycastOutput.hasHit() )
			{
				hkpRigidBody* hitRb = hkGetRigidBody( raycastOutput.getHit().m_rootCollidable );

				if( hitRb->getMotionType() != hkpMotion::MOTION_FIXED )
				{
					hkVector4 tangent;
					myCurve.getTangent( t, tangent );
					tangent.mul4( 15000.0f );

					applyScaledLinearImpulse( hitRb, tangent );
					turret.cooldown = 3.0f;
				}
			}
		}
	}

	m_world->markForWrite();

	// Update the character context
	m_characterRigidBody->m_up = m_worldUp;
	hkReal posX = 0.0f;
	hkReal posY = 0.0f;
	if( !m_detachedCamera )
	{
		float deltaAngle;
		CharacterUtils::getUserInputForCharacter( m_env, deltaAngle, posX, posY );

		if( ( ( hkMath::fabs( posX ) < HK_REAL_MAX ) && ( hkMath::fabs( posY ) < HK_REAL_MAX ) ) && ( posX || posY ) )
		{
			// find new orientation in local space
			hkVector4 newForward( -posY, 0.0f, -posX );
			hkVector4 absoluteForward( 1.0f, 0.0f, 0.0f );
			hkReal characterAngle = hkMath::acos( absoluteForward.dot3( newForward ) );

			// Calculate cross product to get sign of rotation.
			hkVector4 crossProduct;
			crossProduct.setCross( absoluteForward, newForward );

			if( crossProduct(1) < 0.0f )
			{
				characterAngle *= -1.0f;
			}

			// Rotate the character's rigid body to face in the direction it's moving
			hkRotation newRotation;
			newRotation.setAxisAngle( m_worldUp, characterAngle );
 			m_characterForward.setRotatedDir( newRotation, m_cameraForward );
 			m_characterForward.normalize3();
		}

		// Rotate the camera's forward vector based on world up vector and mouse movement
		if( deltaAngle != 0.0f && m_characterRigidBody->getRigidBody()->getRotation().hasValidAxis() )
		{
			hkRotation newRotation;
			newRotation.setAxisAngle( m_worldUp, deltaAngle );
 			m_cameraForward.setRotatedDir( newRotation, m_cameraForward );
 			m_cameraForward.normalize3();
		}
	}

	HK_TIMER_BEGIN( "set character state", HK_NULL );
	hkpCharacterInput input;
	hkpCharacterOutput output;
	{
		input.m_atLadder = false;
		input.m_inputLR = posX;
		input.m_inputUD = posY;

		if( m_detachedCamera )
		{
			input.m_wantJump = false;
		}
		else
		{
			input.m_wantJump = m_env->m_window->getMouse().wasButtonPressed( HKG_MOUSE_LEFT_BUTTON )
							|| m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_1 );
		}

		// Check that we have a valid rotation. Probably won't for the first couple of frames.
		if( !( m_characterRigidBody->getRigidBody()->getRotation().hasValidAxis() ) )
		{
			input.m_up = hkVector4( 0.0f, 0.0f, 1.0f );
			input.m_forward = m_cameraForward;
		}
		else
		{
			input.m_up = m_worldUp;

			// Recalculate m_forward so it's perpendicular to m_worldUp
			hkVector4 newRot;
			newRot.setCross( m_cameraForward, m_worldUp );
			m_cameraForward.setCross( m_worldUp, newRot );

			// Display character's current heading
			hkRotation characterRotation;
			characterRotation.set( m_characterRigidBody->getRigidBody()->getRotation() );
			HK_DISPLAY_ARROW( m_characterRigidBody->getPosition(), characterRotation.getColumn(0), hkColor::LIMEGREEN );

			input.m_forward = m_cameraForward;
		}

		hkStepInfo stepInfo;
		stepInfo.m_deltaTime = m_timestep;
		stepInfo.m_invDeltaTime = 1.0f / m_timestep;

		input.m_stepInfo = stepInfo;
		input.m_characterGravity.setMul4( -20.0f, m_worldUp );

		input.m_velocity = m_characterRigidBody->getRigidBody()->getLinearVelocity();
		input.m_position = m_characterRigidBody->getRigidBody()->getPosition();
		{
			hkpSurfaceInfo ground;
			m_characterRigidBody->checkSupport( stepInfo, ground );

			// Avoid accidental state changes (Smooth movement on stairs)
			// During transition supported->unsupported continue to return N-frames hkpSurfaceInfo data from previous supported state
			{
				// Number of frames to skip (continue with previous hkpSurfaceInfo data)
				const int skipFramesInAir = 6;

				if( input.m_wantJump )
				{
					m_framesInAir = skipFramesInAir;
				}

				hkpSurfaceInfo* currInfo;
				if( ground.m_supportedState != hkpSurfaceInfo::SUPPORTED )
				{
					if( m_framesInAir < skipFramesInAir )
					{
						input.m_isSupported = true;
						currInfo = m_previousGround;
					}
					else
					{
						input.m_isSupported = false;
						currInfo = &ground;
					}

					m_framesInAir++;
				}
				else
				{
					input.m_isSupported = true;
					currInfo = &ground;

					m_previousGround->set( ground );

					// reset old number of frames
					if( m_framesInAir > skipFramesInAir )
					{
						m_framesInAir = 0;
					}			
				}

				input.m_surfaceNormal = currInfo->m_surfaceNormal;
				input.m_surfaceVelocity = currInfo->m_surfaceVelocity;
				input.m_surfaceMotionType = currInfo->m_surfaceMotionType;
			}
		}

		HK_TIMER_END();
	}

	// Apply the character state machine
	{
		HK_TIMER_BEGIN( "update character state", HK_NULL );

		m_characterContext->update( input, output );

		HK_TIMER_END();
	}

	//Apply the player character controller
	{
		HK_TIMER_BEGIN( "simulate character", HK_NULL );

		// Set output velocity from state machine into character rigid body
		m_characterRigidBody->setLinearVelocity( output.m_velocity, m_timestep );

		HK_TIMER_END();

		m_world->unmarkForWrite();
	}

	// Rotate the character
	{
		hkRotation newOrientation;
		newOrientation.getColumn(0) = m_characterForward;
		newOrientation.getColumn(1) = m_worldUp;
		newOrientation.getColumn(2).setCross( newOrientation.getColumn(0), newOrientation.getColumn(1) );
		newOrientation.renormalize();
		
		reorientCharacter( newOrientation );
	}

	// Step the world
	hkDefaultPhysicsDemo::stepDemo();

	// Display state
	{
		hkpCharacterStateType state = m_characterContext->getState();
		char* stateStr;

		switch( state )
		{
			case HK_CHARACTER_ON_GROUND:
			{
				stateStr = "On Ground";
				break;
			}
			case HK_CHARACTER_JUMPING:
			{
				stateStr = "Jumping";
				break;
			}
			case HK_CHARACTER_IN_AIR:
			{
				stateStr = "In Air";
				break;
			}
			default:
			{
				stateStr = "Other";
				break;
			}
		}

		char buffer[255];
		hkString::snprintf( buffer, 255, "State : %s", stateStr );
		m_env->m_textDisplay->outputText( buffer, 20.f, 270.f, 0xffffffff );
	}

	//
	// Handle crouching (only for capsule)
	//
	if( !m_detachedCamera )
	{
		m_world->markForWrite();
		hkBool wantCrouch = ( m_env->m_window->getMouse().getButtonState() & HKG_MOUSE_RIGHT_BUTTON )
						 || ( m_env->m_gamePad->getButtonState() & HKG_PAD_BUTTON_2 );

		hkBool isCrouching = ( m_characterRigidBody->getRigidBody()->getCollidable()->getShape() == m_crouchShape );


		// We want to stand
		if( isCrouching && !wantCrouch )
		{
			m_characterRigidBody->getRigidBody()->setShape( m_standShape );
		}

		// We want to crouch
		else if( !isCrouching && wantCrouch )
		{
			m_characterRigidBody->getRigidBody()->setShape( m_crouchShape );
		}

		m_world->unmarkForWrite();
	}

	// Transparent camera handling
	if( !m_detachedCamera )
	{
		m_world->markForWrite();
		handleCamera();
		m_world->unmarkForWrite();
	}

	return hkDemo::DEMO_OK;
}
示例#11
0
void ShapeQueryDemo::worldRayCast( hkpWorld* world, hkReal time, hkBool useCollector )
{
	const int N_RAY_CASTS = 10;

	hkpWorldRayCastInput  rayInputs[N_RAY_CASTS];
	hkpWorldRayCastOutput rayOutputs[N_RAY_CASTS];
	hkpClosestRayHitCollector rayCollector[ N_RAY_CASTS ];

	// We may also choose whether or not we wish to use a collector or output structure to
	// gather the results of the query (hkpWorld::castRay has two overloaded methods).

	hkVector4 displacement( 0.0f, -30.0f, 0.0f );

	//	Perform all queries in one go (do not interleave with examining the results,
	//  as this is bad for code and data cache.
	{
		for ( int i = 0; i < N_RAY_CASTS; i++ )
		{
			hkpWorldRayCastInput& in = rayInputs[i];

			// create a new position: all objects move in a circle
			hkReal t = time + (HK_REAL_PI * 2 * i) / N_RAY_CASTS;
			hkVector4 pos( hkMath::sin( t ) * 8.0f, 10.0f, hkMath::cos( t ) * 8.0f );

			//	Set our position in our input structure
			in.m_from = pos;
			in.m_to.setAdd4( pos, displacement );

			//
			// Query for intersecting objects. monitor the timing.
			//
			for (int k = 0; k < NUM_ITER ; k++ )
			{
				HK_TIMER_BEGIN("raycast", HK_NULL);
				if ( useCollector )
				{
					hkpClosestRayHitCollector& collector = rayCollector[i];
					collector.reset();
					world->castRay( in, collector );
				}
				else
				{
					hkpWorldRayCastOutput& out = rayOutputs[i];
					out.reset();
					world->castRay( in, out );
				}
				HK_TIMER_END( );
			}
		}
	}

	// Once we've cast our rays all that remains to do is display them!
	// We can do this by using both the input structure (to find the
	// start position) and the output structure (which in the case
	// of using collectors uses the collector's internal
	// hkpWorldRayCastOutput structure) to find the end point.
	// We plot N_RAY_CAST casts, one for each iteration, in a GREEN colour.
	{
		for ( int i = 0; i < N_RAY_CASTS; i++ )
		{
			hkpWorldRayCastInput& in = rayInputs[i];

			const hkpWorldRayCastOutput* out;
			if ( useCollector )
			{
				 out = &rayCollector[i].getHit();
			}
			else
			{
				out = &rayOutputs[i];
			}

			//	Display the ray
			{
				hkVector4 hitPoint;	hitPoint.setInterpolate4( in.m_from, in.m_to, out->m_hitFraction );
				HK_DISPLAY_LINE(in.m_from, hitPoint, hkColor::GREEN);
			}

			//	Display the result
			if ( out->hasHit() )
			{
				displayRayHit( world, in, *out );
			}
		}
	}
}
示例#12
0
hkDemo::Result LowFrequencyCharactersDemo::stepDemo()
{
	hkVector4 up;
	hkpCharacterInput input[NUM_CHARACTERS];

	{
		m_world->lock();

		//	Get user input data
		int m_upAxisIndex = 1;
		up.setZero4();
		up(m_upAxisIndex) = 1;

		m_tick++;

		hkQuaternion orient;
		hkReal posX = 0.f;
		hkReal posY = 0.f;
		{
			float deltaAngle = 0.f;
			CharacterUtils::getUserInputForCharacter(m_env, deltaAngle, posX, posY);
			m_currentAngle += deltaAngle;
			orient.setAxisAngle(up, m_currentAngle);
		}

		// Fill in the state machine input structure
		hkpCharacterOutput output[NUM_CHARACTERS];
		{
			for (int i=0; i < NUM_CHARACTERS; i++)
			{
				hkInt32 slot = m_characterProxy[i]->getShapePhantom()->getProperty(HK_SCHEDULE_FREQUENCY).getInt();
				if (shouldSimulate(i, m_tick))
				{
					if (i==0)
					{
						input[i].m_inputLR = posX;
						input[i].m_inputUD = posY;
						input[i].m_wantJump = m_env->m_window->getMouse().wasButtonPressed(HKG_MOUSE_LEFT_BUTTON)
							|| m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_1);
						input[i].m_forward.set(1,0,0);
						input[i].m_forward.setRotatedDir( orient, input[i].m_forward );
					}
					else
					{
						hkReal time = hkReal(m_tick) / 60.0f;
						input[i].m_inputLR = hkMath::sin(time + i);
						input[i].m_inputUD = hkMath::cos(time + i);
						input[i].m_wantJump = false;
						input[i].m_forward.set(1,0,0);
					}

					input[i].m_atLadder = false;
					input[i].m_up = up;


					input[i].m_stepInfo.m_deltaTime = m_timestep;
					input[i].m_stepInfo.m_invDeltaTime = 1.0f / (m_timestep * (1 << slot));
					input[i].m_characterGravity.set(0,-40,0);
					input[i].m_velocity = m_characterProxy[i]->getLinearVelocity();
					input[i].m_position = m_characterProxy[i]->getPosition();

					hkVector4 down;	down.setNeg4(up);
					m_characterProxy[i]->checkSupport(down, input[i].m_surfaceInfo);
				}		
			}
		}


		// Apply the character state machine
		{
			HK_TIMER_BEGIN( "update character state", HK_NULL );

			for (int i=0; i < NUM_CHARACTERS; i++)
			{
				if (shouldSimulate(i, m_tick))
				{
					m_characterContext[i]->update(input[i], output[i]);
				}
			}

			HK_TIMER_END();

		}

		//Apply the player character controller
		{
			HK_TIMER_BEGIN( "simulate character", HK_NULL );

			for (int i=0; i < NUM_CHARACTERS; i++)
			{
				if (shouldSimulate(i, m_tick))
				{
					// Since we're simulatating some characters at less than full frequency we need to adjust the
					// timestep we pass to the proxy
					hkInt32 slot = m_characterProxy[i]->getShapePhantom()->getProperty(HK_SCHEDULE_FREQUENCY).getInt();

					hkStepInfo csi;
					csi.m_deltaTime = m_timestep * (1 << slot);
					csi.m_invDeltaTime = 1.0f / csi.m_deltaTime;

					// Feed output from state machine into character proxy
					m_characterProxy[i]->setLinearVelocity(output[i].m_velocity);
					m_characterProxy[i]->integrate( csi, m_world->getGravity() );

					// If the character has fallen off the world we reposition them
					hkVector4 pos = m_characterProxy[i]->getPosition();
					if (pos(1) < -10.0f)
					{
						pos.setZero4();
						pos(1) = 5;
						m_characterProxy[i]->setPosition(pos);
					}
				}
			}

			HK_TIMER_END();
		}

		m_world->unlock();
	}

	// Step the world
	hkDefaultPhysicsDemo::stepDemo();

	{
		m_world->lock();

		// Camera Handling
		{
			const hkReal height = 1.7f;

			hkVector4 from, to;
			to = m_characterProxy[0]->getPosition();
			to.addMul4(height, up);

			hkVector4 dir;
			dir.setMul4( height, up );
			dir.addMul4( -8.f, input[0].m_forward);

			from.setAdd4(to, dir);
			setupDefaultCameras(m_env, from, to, up, 1.0f);
		}

		{
			char buffer[255];
			hkString::snprintf(buffer, 255, "%d capsules at 60Hz, %d boxes at 30Hz, %d spheres at 15Hz", m_numCapsules, m_numBoxes, m_numSpheres);
			m_env->m_textDisplay->outputText(buffer, 20, 410, 0xffffffff);
		}

		m_world->unlock();
	}

	return hkDemo::DEMO_OK;
}
//
// Do some random raycasts into the world
// Both the kd-tree and the (deprecated) hkp3AxisSweep versions are used for comparison
//
void KdTreeVsBroadphaseDemo::doRaycasts()
{
	const int numRays = 100;
	
	hkLocalArray<hkpWorldRayCastInput> inputs( numRays );
	inputs.setSize(numRays);

	// Need fixed-size collector arrays to make sure the constructors get called

	hkpWorldRayCastOutput iterativeCollectors[numRays];
	hkpClosestRayHitCollector worldCollectors[numRays];

	for (int i=0; i < numRays; i++)
	{
		hkVector4 start, end;
		start.set(	hkMath::randRange(-m_worldSizeX, m_worldSizeX),
					hkMath::randRange(-m_worldSizeY, m_worldSizeY),
					hkMath::randRange(-m_worldSizeZ, m_worldSizeZ));

		end.set(	hkMath::randRange(-m_worldSizeX, m_worldSizeX),
					hkMath::randRange(-m_worldSizeY, m_worldSizeY),
					hkMath::randRange(-m_worldSizeZ, m_worldSizeZ));

		// Flatten out the rays in one component - this triggers a special case in the raycasting code
		{
			end(i%3) = start(i%3);
		}

		inputs[i].m_from = start;
		inputs[i].m_to = end;
		inputs[i].m_filterInfo = 0;
	}

	//
	// Raycast using the world's kd-tree
	//
	HK_TIMER_BEGIN("kdTreeRaycast", HK_NULL);

	// Check that the tree isn't dirty
	HK_ASSERT(0x3fe8daf1, m_world->m_kdTreeManager->isUpToDate());
	for (int i=0; i < numRays; i++)
	{
		m_world->castRay(inputs[i], iterativeCollectors[i]);

	}
	HK_TIMER_END();


	HK_TIMER_BEGIN("worldRc", HK_NULL);
	{ 
		//
		// Mark the world's kd-tree as dirty, forcing raycasting to go through the old (slow) hkp3AxisSweep algorithm
		// You should NOT usually be doing this.
		//
		m_world->markKdTreeDirty();
		for (int i=0; i < numRays; i++)
		{
			m_world->castRay(inputs[i], worldCollectors[i]);
		}
	
	}
	HK_TIMER_END();
		
	// Check that the results agree, and draw the results
	{ 
		for (int i=0; i<numRays; i++)
		{

			HK_ASSERT(0x0, iterativeCollectors[i].hasHit() == worldCollectors[i].hasHit());
			HK_ASSERT(0x0, hkMath::equal(iterativeCollectors[i].m_hitFraction, worldCollectors[i].m_earlyOutHitFraction));

			if (iterativeCollectors[i].hasHit())
			{
				hkVector4 hitpoint;
				hitpoint.setInterpolate4(inputs[i].m_from, inputs[i].m_to, iterativeCollectors[i].m_hitFraction);
				HK_DISPLAY_STAR(hitpoint, .1f, hkColor::RED);
				HK_DISPLAY_ARROW(hitpoint, iterativeCollectors[i].m_normal, hkColor::CYAN);
				HK_DISPLAY_LINE(inputs[i].m_from, hitpoint, hkColor::BLUE);
			}
			else
			{
				HK_DISPLAY_LINE(inputs[i].m_from, inputs[i].m_to, hkColor::WHITE);
			}
		}
	}
}
hkDemo::Result DestructibleWallsDemo::stepDemo()
{
	m_world->lock();

	{
		const hkgPad* pad = m_env->m_gamePad;

		// Cannon control + drawing
		// check to see if the user has pressed one of the control keys:
		int x = ((pad->getButtonState() & HKG_PAD_DPAD_LEFT) != 0)? -1:0;
		x = ((pad->getButtonState() & HKG_PAD_DPAD_RIGHT) != 0)? 1:x;
		int y = ((pad->getButtonState() & HKG_PAD_DPAD_DOWN) != 0)? -1:0;
		y = ((pad->getButtonState() & HKG_PAD_DPAD_UP) != 0)?    1:y;

		m_shootingDirX += x * 0.015f;
		m_shootingDirY += y * 0.015f;

		hkVector4 canonStart( m_centerOfScene );
		canonStart(2) += m_options.m_WallsWidth*2.0f;

		hkVector4 canonDir( m_shootingDirX, m_shootingDirY, -1.0f );
		canonDir.normalize3();

		// display the canon direction 
		{
			hkpWorldRayCastInput in;
			in.m_from = canonStart;
			in.m_to.setAddMul4( in.m_from, canonDir, 100.0f );
			in.m_filterInfo = 0;
			hkpWorldRayCastOutput out;
			m_world->castRay( in , out );
			hkVector4 hit; hit.setInterpolate4( in.m_from, in.m_to, out.m_hitFraction );
			HK_DISPLAY_LINE( in.m_from, hit, 0x600000ff );
			if ( out.hasHit() )
			{
				HK_DISPLAY_ARROW( hit, out.m_normal, 0x60ff00ff );
			}
			HK_DISPLAY_ARROW( canonStart, canonDir, hkColor::CYAN );
		}

		// Shooting bullets
		{
			hkBool shooting = false;

			if ( pad->wasButtonPressed(HKG_PAD_BUTTON_1)!= 0 )
			{
				shooting = true;
			}

			if (  pad->isButtonPressed(HKG_PAD_BUTTON_2)!= 0)
			{
				if ( m_gunCounter-- < 0 )
				{
					shooting = true;
					m_gunCounter = 5;
				}
			}  

			if ( shooting )
			{
				hkpMassProperties result;
				hkpInertiaTensorComputer::computeSphereVolumeMassProperties(m_options.m_cannonBallRadius, m_options.m_cannonBallMass, result);

				hkpSphereShape* sphereShape = new hkpSphereShape(m_options.m_cannonBallRadius); 
				hkVector4 spherePos(-20.0f, 0.0f + m_options.m_cannonBallRadius, 200.0f);

				hkpRigidBodyCinfo sphereInfo;
				sphereInfo.m_mass = result.m_mass;
				sphereInfo.m_centerOfMass = result.m_centerOfMass;
				sphereInfo.m_inertiaTensor = result.m_inertiaTensor;
				sphereInfo.m_shape = sphereShape;
				sphereInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA;
				sphereInfo.m_position = canonStart;
				sphereInfo.m_qualityType = HK_COLLIDABLE_QUALITY_BULLET;
				sphereInfo.m_linearVelocity.setMul4( 100.0f, canonDir );

				hkpRigidBody* bullet = new hkpRigidBody( sphereInfo );
				sphereInfo.m_shape->removeReference();

				m_world->addEntity( bullet );
				bullet->removeReference();
			}
		}
	}

	// release the world
	m_world->unlock();

	// step demo
	hkDemo::Result res = hkDefaultPhysicsDemo::stepDemo();


	//HK_TIMER_BEGIN_LIST( "Update Walls", "Update Walls"/*HK_NULL*/);
	HK_TIMER_BEGIN( "Update Walls", "update walls"/*HK_NULL*/);
	if(m_collisionDetectionType == PARALLEL)
	{
		HK_ASSERT2(0x7274e9ec, m_fractureUtility!=HK_NULL ,"The parallel simulation wasn't set!!");
		// and update walls
		m_fractureUtility->Update();
	}
	HK_TIMER_END();

	HK_TIMER_BEGIN("DebugDisplay", HK_NULL);
	// DEBUG DISPLAY
	if(m_fractureUtility->getSimulation() && m_options.m_showDebugDisplay)
	{
		// applied impulses
		for(int i=0; i<m_fractureUtility->getSimulation()->debugImpulses.getSize(); i+=2)
		{
			hkVector4 start( m_fractureUtility->getSimulation()->debugImpulses[i] );
			hkVector4 end( m_fractureUtility->getSimulation()->debugImpulses[i+1] );
			end.mul4( 0.01f );
			HK_DISPLAY_ARROW(start, end , 0x00000000);			
		}
		
		if(m_fractureUtility->getSimulation()->debugImpulses.getSize() > 100 )
			m_fractureUtility->getSimulation()->debugImpulses.clear();

		// bricks positions in parallel simulation
		hkArray<hkVector4> positions;
		m_fractureUtility->getSimulation()->getAllBricksPositions( positions );
		for(int i=0; i<positions.getSize(); ++i)
		{
			drawBrick(positions[i] , m_brickHalfExtents);
		}
		positions.clear();

		// edges of union find
		for(int i=0; i<m_fractureUtility->getSimulation()->debugEdges.getSize(); i+=2)
		{
			HK_DISPLAY_LINE(m_fractureUtility->getSimulation()->debugEdges[i], m_fractureUtility->getSimulation()->debugEdges[i+1] , 0x00000000);
		}
	}
	HK_TIMER_END();

	if(m_collisionDetectionType == PARALLEL)
	{
		hkArray< hkVector4 > planes;
		m_fractureUtility->getSimulation()->getAllDebugfracturePlanes(planes);
		for(int i=0; i< planes.getSize()-2; ++i)
		{
			if(planes[i].length3()!=0)
			{
				hkVector4 offset(.0f, .5f, .0f/*.5f, .5f, .5f*/);
				HK_DISPLAY_PLANE(planes[i], offset, 0.5f, 0xffffffff);
			}
		}
		if(!planes.isEmpty() && planes[planes.getSize()-1].length3()!=0)
		{
			hkVector4 offset(.0f, .5f, .0f/*.5f, .5f, .5f*/);
			HK_DISPLAY_PLANE(planes[planes.getSize()-2], offset, 0.5f, 0x00000000);
			HK_DISPLAY_PLANE(planes[planes.getSize()-1], offset, 0.5f, 0xffff0000);
		}
		hkArray<hkVector4> cpts;
		hkArray<hkVector4> impulses;
		m_fractureUtility->getSimulation()->getAllDebugImpulsesAndContactPoints(impulses, cpts);
		for(int i=0; i< cpts.getSize(); ++i)
		{
			HK_DISPLAY_ARROW(cpts[i], impulses[i] , 0x00000000);	
		}
	}
	return res;
}
示例#15
0
hkDemo::Result RayTraceDemo::stepDemo()
{

	if ( m_env->m_window->getMouse().getButtonState() != 0 )
	{
		m_rotateCounter = 60;
	}
	m_rotateCounter--;


	// rotate the camera viewpoint
	if (m_rotateCounter <= 0)
	{

		hkgWindow* w = m_env->m_window;
		hkgCamera* c = w->getViewport(0)->getCamera();

		hkVector4 from; c->getFrom( &from(0) );
		hkVector4 to; c->getTo(&to(0));
		hkVector4 up; c->getUp(&up(0));
		up.set(0,1,0);


		hkVector4 d; d.setSub4(to, from);
		hkQuaternion q( up, .03f);
		d.setRotatedDir(q, d);
		from.setSub4(to, d);

		setupDefaultCameras(m_env, from, to, up );
	}


	//
	//	Do our raytrace
	//
	{
		//
		//	Get our camera information
		//
		hkVector4 from;
		hkVector4 zOffset;
		hkVector4 upOffset;
		hkVector4 rightOffset;
		{
			from.setZero4();
			zOffset.setZero4();
			upOffset.setZero4();
			rightOffset.setZero4();

			hkgWindow* w = m_env->m_window;
			hkgCamera* c = w->getViewport(0)->getCamera();

			c->getFrom( &from(0) );
			c->getDir( &zOffset(0) );
			c->getUp( &upOffset(0) );

			rightOffset.setCross( upOffset, zOffset );
		}

		//
		// global info
		//
		hkVector4 lightPos; lightPos.setAddMul4( from, upOffset, 10 );
		hkReal lightStrength = 150.0f;

		// reflect the light in the normal graphics too 
		{
			hkVector4 lightDir; 
			hkVector4 lightTo; 
			m_env->m_window->getViewport(0)->getCamera()->getDir( &lightTo(0) );
			lightTo.add4( from ); 
			lightDir.setSub4( lightTo, lightPos);
			setSoleDirectionLight(m_env, &lightDir(0), 0xffffffff);
		}


		//
		//	Prepare the data for iterations
		//
		{
			hkgWindow* w = m_env->m_window;
			hkgCamera* c = w->getViewport(0)->getCamera();
			hkReal fa = c->getFar();
			zOffset.mul4( fa );
			upOffset.mul4( fa * c->getFOV() / 45 * CANVAS_HEIGHT/ CANVAS_WIDTH);
			rightOffset.mul4( fa * c->getFOV() / 45 );
		}

		hkpShapeRayCastInput ray;
		ray.m_from = from;
		ray.m_to.setAdd4( from, zOffset );
		ray.m_to.addMul4( 0.5f, upOffset );
		ray.m_to.addMul4( 0.5f, rightOffset );
		upOffset.mul4( 1.0f / CANVAS_HEIGHT );
		rightOffset.mul4( 1.0f / CANVAS_WIDTH );

		m_numPrimaryRays = 0;
		m_numShadowRays = 0;

		hkpShapeRayCastInput lightRay;
		lightRay.m_from = lightPos;

		//
		//	Do the raytracer
		//
		HK_TIMER_BEGIN("Raytrace Frame", HK_NULL);
		m_stopwatch.start();
		{
			hkpShapeRayCastOutput output;
			hkpShapeRayCastOutput output2;
			int* data = reinterpret_cast<int*>(m_texture->getDataPointer());
			hkVector4 yStart = ray.m_to;

			for (int y = 0; y < CANVAS_HEIGHT; y++)
			{
				ray.m_to = yStart;
				for (int x = 0; x < CANVAS_WIDTH; x++ )
				{
				#if (HK_ENDIAN_BIG==1) 
					data[0] = 0x3f3f7fFF; // background (rgba in that byte order)
				#else
					data[0] = 0xFF7f3f3f; // background
				#endif
				
					output.reset();
					m_numPrimaryRays++;
					m_shape->castRay( ray, output );
					if ( output.hasHit() )
					{
						hkReal brightness = .4f;

						hkVector4 hitPos; hitPos.setInterpolate4( ray.m_from, ray.m_to, output.m_hitFraction );
						hkVector4 lightDir; lightDir.setSub4( lightPos, hitPos );

						// get the direct light info
						{
							hkReal lightDot = output.m_normal.dot3( lightDir );
							if ( lightDot > 0.0f )
							{
								//
								//	Do shadows
								//
								output2.reset();
								lightRay.m_to.setInterpolate4( lightRay.m_from,hitPos, 0.999f);

								m_numShadowRays++;
								if (!m_shape->castRay( lightRay, output2 ))
								{
									hkReal lightDirInvLen = lightDir.lengthInverse3();
									brightness += lightDot * lightDirInvLen * lightStrength;

									// add some glare
									{
										hkVector4 reflectedDir; reflectedDir.setAddMul4( lightDir, output.m_normal, -2.0f * lightDot );
										hkVector4 rayDirection; rayDirection.setSub4( ray.m_to, ray.m_from );
										hkReal dot2 = reflectedDir.dot3( rayDirection );
										if ( dot2 > 0 )
										{
											dot2 *= lightDirInvLen;
											dot2 *= dot2;
											dot2 /= rayDirection.lengthSquared3();
											dot2 *= dot2;
											dot2 *= dot2;
											dot2 *= dot2;
											dot2 *= dot2;
											brightness += dot2 * lightStrength * 2;
										}
									}

								}
							}

						}


						unsigned s = (unsigned)hkMath::hkToIntFast( brightness );
						if ( s > 255 ) s = 255;

						#if (HK_ENDIAN_BIG==1) 
							data[0] = 0x000000ff | (s<<24) | (s<<16) | (s<<8); // rgba in that byte order
						#else
							data[0] = 0xff000000 | (s<<16) | (s<<8) | s;
						#endif
					}
					data++;
					ray.m_to.sub4( rightOffset );
				}
				yStart.sub4( upOffset );
			}
		}
		m_stopwatch.stop();
		HK_TIMER_END();
	}

	//
	// Output statistics
	//
	{
		hkReal timePerRayuSecs = m_stopwatch.getSplitSeconds() * 1e6f / (m_numPrimaryRays + m_numShadowRays);
		m_stopwatch.reset();
		char buf[512];
		hkString::snprintf(buf, 512, "Primary Rays:%d\nShadow Rays:%d\nAverage time per ray:%f microsecs", m_numPrimaryRays, m_numShadowRays, timePerRayuSecs);
		m_env->m_textDisplay->outputText(buf, 20, 350);
	}

	//
	//	Draw the texture (really slow as we don't have a quicker reinit for the textures / direct write yet in the HKG)
	//
	m_env->m_window->getContext()->lock();
	if (m_textureRealized)
	{
		m_texture->free();
	}
	m_texture->realize(true);
	m_env->m_window->getContext()->unlock();

	m_textureRealized = true;
		
	return DEMO_OK;
}
hkDemo::Result MultipleCharacterRbsDemo::stepDemo()
{
	HK_TIMER_BEGIN( "simulate multiply characters", HK_NULL );

	m_world->lock();

	hkVector4 up;
	up.setNeg4( m_world->getGravity() );
	up.normalize3();
	int numCharacters = m_characterRigidBodies.getSize();

	m_tick++;

	hkLocalArray<hkpCharacterInput> input( numCharacters ) ;
	input.setSize(numCharacters);

	// Fill in the state machine input structure
	{
		for (int i=0; i < numCharacters; i++)
		{
			input[i].m_atLadder = false;
			input[i].m_up = up;

			// Steer the characters
			hkReal time = hkReal(m_tick) / 60.0f;
			input[i].m_inputLR = hkMath::sin(time + i);
			input[i].m_inputUD = hkMath::cos(time + i);
			input[i].m_wantJump = false;
			input[i].m_forward.set(1,0,0);

			hkStepInfo stepInfo;
			stepInfo.m_deltaTime = m_timestep;
			stepInfo.m_invDeltaTime = 1.0f/m_timestep;
			
			input[i].m_stepInfo = stepInfo;

			input[i].m_characterGravity = m_world->getGravity();
			input[i].m_velocity = m_characterRigidBodies[i]->getLinearVelocity();
			input[i].m_position = m_characterRigidBodies[i]->getPosition();

			hkpSurfaceInfo ground;
			m_characterRigidBodies[i]->checkSupport(stepInfo, ground);

			input[i].m_isSupported = (ground.m_supportedState == hkpSurfaceInfo::SUPPORTED);
			input[i].m_surfaceNormal = ground.m_surfaceNormal;
			input[i].m_surfaceVelocity = ground.m_surfaceVelocity;	
		}
	}


	hkLocalArray<hkpCharacterOutput> output( numCharacters);
	output.setSize(numCharacters);

	// Apply the character state machine
	{
		HK_TIMER_BEGIN( "update character state", HK_NULL );

		for (int i=0; i < numCharacters; i++)
		{
			m_characterContexts[i]->update(input[i], output[i]);
		}

		HK_TIMER_END();

	}

	//Apply the character controllers
	{
		HK_TIMER_BEGIN( "simulate character", HK_NULL );

		for (int i=0; i < numCharacters; i++)
		{

			// Feed the output velocity from state machine into character rigid body
			m_characterRigidBodies[i]->setLinearVelocity(output[i].m_velocity, m_timestep);
			
			// If the character has fallen off the world we reposition them
			hkVector4 pos = m_characterRigidBodies[i]->getRigidBody()->getPosition();
			if (pos(1) < -10.0f)
			{
				pos.setZero4();
				pos(1) = 5;
				m_characterRigidBodies[i]->getRigidBody()->setPosition(pos);
			}

		}

		HK_TIMER_END();

		m_world->unlock();
	}

	// Step the world
	{
		hkDefaultPhysicsDemo::stepDemo();
	}

	HK_TIMER_END();

	return hkDemo::DEMO_OK;
}
示例#17
0
///[stepGame]
/// This is called every simulation timestep. We need to
/// - Steer the first vehicle based on user input.
/// - Step the simulation.
/// - Sync each vehicle's display wheels.
/// - Update the camera that follows the first vehicle.
/// - Draw skidmarks for the first vehicle if it is skidding.
/// - Update the RPM meter and speedometer.
///
hkDemo::Result VehicleManagerDemo::stepDemo()
{
	const MTVehicleRayCastDemoVariant& variant = g_MTVehicleRayCastDemoVariants[m_variantId];

	// Steer the vehicle from user input.
	{
		m_world->markForWrite();
		steer();
		m_world->unmarkForWrite();
	}

	m_world->markForWrite();
	
	HK_TIMER_BEGIN( "Simulate vehicles", HK_NULL );

	if ( variant.m_demoType == MTVehicleRayCastDemoVariant::MULTITHREADED_RAY_CAST || variant.m_demoType == MTVehicleRayCastDemoVariant::MULTITHREADED_LINEAR_CAST )
	{
		// Multithreaded
		m_vehicleManager->stepVehiclesSynchronously( m_world, m_jobThreadPool, m_jobQueue, NUM_SPUS );
	}
	else
	{
		// Singlethreaded
		m_vehicleManager->stepVehicles( m_world->m_dynamicsStepInfo.m_stepInfo );
	}
	HK_TIMER_END();
	
	m_world->unmarkForWrite();
	
	//
	// Step the world.
	//
	{
		hkDefaultPhysicsDemo::stepDemo();
	}


	{
		m_world->markForWrite();

		for (int vehicleId = 0; vehicleId < m_vehicles.getSize(); vehicleId++ )
		{
			VehicleApiUtils::syncDisplayWheels(m_env, 
				*m_vehicles[vehicleId].m_vehicle,
				m_displayWheelId[vehicleId], m_tag);
		}

		// Update the "follow" camera.
		VehicleDisplayUtils::VehicleDataAndDisplayInfo& playerVehicle = m_vehicles[0];

		if (m_followCarView)
		{
			VehicleApiUtils::updateCamera( m_env, *playerVehicle.m_vehicle->getChassis(), m_timestep, m_camera);
		}

		VehicleDisplayUtils::updateTyremarks( m_timestep, playerVehicle.m_vehicle );

		VehicleDisplayUtils::updateInfo( m_env, m_vehicles[0] );

		m_world->unmarkForWrite();
	}

	return DEMO_OK;
}