void PxRigidBodyExt::computeVelocityDeltaFromImpulse(const PxRigidBody& body, const PxVec3& impulsiveForce, const PxVec3& impulsiveTorque, PxVec3& deltaLinearVelocity, PxVec3& deltaAngularVelocity)
{
	{
		const PxF32 recipMass = body.getInvMass();
		deltaLinearVelocity = impulsiveForce*recipMass;
	}

	{
		const PxTransform globalPose = body.getGlobalPose();
		const PxTransform cmLocalPose = body.getCMassLocalPose();
		const PxTransform body2World = globalPose*cmLocalPose;
		PxMat33 M(body2World.q);

		const PxVec3 recipInertiaBodySpace = body.getMassSpaceInvInertiaTensor();

		PxMat33 recipInertiaWorldSpace;
		const float	axx = recipInertiaBodySpace.x*M(0,0), axy = recipInertiaBodySpace.x*M(1,0), axz = recipInertiaBodySpace.x*M(2,0);
		const float	byx = recipInertiaBodySpace.y*M(0,1), byy = recipInertiaBodySpace.y*M(1,1), byz = recipInertiaBodySpace.y*M(2,1);
		const float	czx = recipInertiaBodySpace.z*M(0,2), czy = recipInertiaBodySpace.z*M(1,2), czz = recipInertiaBodySpace.z*M(2,2);
		recipInertiaWorldSpace(0,0) = axx*M(0,0) + byx*M(0,1) + czx*M(0,2);
		recipInertiaWorldSpace(1,1) = axy*M(1,0) + byy*M(1,1) + czy*M(1,2);
		recipInertiaWorldSpace(2,2) = axz*M(2,0) + byz*M(2,1) + czz*M(2,2);
		recipInertiaWorldSpace(0,1) = recipInertiaWorldSpace(1,0) = axx*M(1,0) + byx*M(1,1) + czx*M(1,2);
		recipInertiaWorldSpace(0,2) = recipInertiaWorldSpace(2,0) = axx*M(2,0) + byx*M(2,1) + czx*M(2,2);
		recipInertiaWorldSpace(1,2) = recipInertiaWorldSpace(2,1) = axy*M(2,0) + byy*M(2,1) + czy*M(2,2);

		deltaAngularVelocity = recipInertiaWorldSpace*(impulsiveTorque);
	}
}
Example #2
0
PX_INLINE PxVec3 getVelocityAtPosInternal(const PxRigidBody& body, const PxVec3& point)
{
	PxVec3 velocity = body.getLinearVelocity();
	velocity       += body.getAngularVelocity().cross(point);
	
	return velocity;
}
Example #3
0
vec3f PhysActor_PhysX::GetAngularVelocity()
{
	if (!impl->physActor)
	{
		LOG("Cannot get angular velocity from actor because actor ptr is null!");
		return vec3f(0.0f, 0.0f, 0.0f);
	}

	PxRigidBody* actor = nullptr;

	if (impl->physActor->isRigidDynamic() || impl->physActor->isRigidBody())
		actor = (PxRigidBody*)impl->physActor;
	else
	{
		LOG("Cannot get angular velocity from actor because actor is not a Rigid Dynamic or Rigid Body actor.");
		return vec3f(0.0f, 0.0f, 0.0f);
	}

	if (!actor)
		return vec3f(0.0f, 0.0f, 0.0f);

	PxVec3 velocity = actor->getAngularVelocity();
	vec3f vConv(velocity.x, velocity.y, velocity.z);

	return vConv;
}
void AddRadialImpulseToPxRigidBody_AssumesLocked(PxRigidBody& PRigidBody, const FVector& Origin, float Radius, float Strength, uint8 Falloff, bool bVelChange)
{
#if WITH_PHYSX
	if (!(PRigidBody.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC))
	{
		float Mass = PRigidBody.getMass();
		PxTransform PCOMTransform = PRigidBody.getGlobalPose().transform(PRigidBody.getCMassLocalPose());
		PxVec3 PCOMPos = PCOMTransform.p; // center of mass in world space
		PxVec3 POrigin = U2PVector(Origin); // origin of radial impulse, in world space
		PxVec3 PDelta = PCOMPos - POrigin; // vector from origin to COM

		float Mag = PDelta.magnitude(); // Distance from COM to origin, in Unreal scale : @todo: do we still need conversion scale?

		// If COM is outside radius, do nothing.
		if (Mag > Radius)
		{
			return;
		}

		PDelta.normalize();

		// Scale by U2PScale here, because units are velocity * mass. 
		float ImpulseMag = Strength;
		if (Falloff == RIF_Linear)
		{
			ImpulseMag *= (1.0f - (Mag / Radius));
		}

		PxVec3 PImpulse = PDelta * ImpulseMag;

		PxForceMode::Enum Mode = bVelChange ? PxForceMode::eVELOCITY_CHANGE : PxForceMode::eIMPULSE;
		PRigidBody.addForce(PImpulse, Mode);
	}
#endif // WITH_PHYSX
}
//=================================================================================
// Single closest hit compound sweep
bool PxRigidBodyExt::linearSweepSingle(
	PxRigidBody& body, PxScene& scene, const PxVec3& unitDir, const PxReal distance,
	PxHitFlags outputFlags, PxSweepHit& closestHit, PxU32& shapeIndex,
	const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall,
	const PxQueryCache* cache, const PxReal inflation)
{
	shapeIndex = 0xFFFFffff;
	PxReal closestDist = distance;
	PxU32 nbShapes = body.getNbShapes();
	for(PxU32 i=0; i < nbShapes; i++)
	{
		PxShape* shape = NULL;
		body.getShapes(&shape, 1, i);
		PX_ASSERT(shape != NULL);
		PxTransform pose = PxShapeExt::getGlobalPose(*shape, body);
		PxQueryFilterData fd;
		fd.flags = filterData.flags;
		PxU32 or4 = (filterData.data.word0 | filterData.data.word1 | filterData.data.word2 | filterData.data.word3);
		fd.data = or4 ? filterData.data : shape->getSimulationFilterData();
		PxGeometryHolder anyGeom = shape->getGeometry();

		PxSweepBuffer subHit; // touching hits are not allowed to be returned from the filters
		scene.sweep(anyGeom.any(), pose, unitDir, distance, subHit, outputFlags, fd, filterCall, cache, inflation);
		if (subHit.hasBlock && subHit.block.distance < closestDist)
		{
			closestDist = subHit.block.distance;
			closestHit = subHit.block;
			shapeIndex = i;
		}
	}

	return (shapeIndex != 0xFFFFffff);
}
void AddRadialForceToPxRigidBody_AssumesLocked(PxRigidBody& PRigidBody, const FVector& Origin, float Radius, float Strength, uint8 Falloff, bool bAccelChange)
{
#if WITH_PHYSX
	if (!(PRigidBody.getRigidBodyFlags() & PxRigidBodyFlag::eKINEMATIC))
	{
		float Mass = PRigidBody.getMass();
		PxTransform PCOMTransform = PRigidBody.getGlobalPose().transform(PRigidBody.getCMassLocalPose());
		PxVec3 PCOMPos = PCOMTransform.p; // center of mass in world space
		PxVec3 POrigin = U2PVector(Origin); // origin of radial impulse, in world space
		PxVec3 PDelta = PCOMPos - POrigin; // vector from

		float Mag = PDelta.magnitude(); // Distance from COM to origin, in Unreal scale : @todo: do we still need conversion scale?

		// If COM is outside radius, do nothing.
		if (Mag > Radius)
		{
			return;
		}

		PDelta.normalize();

		// If using linear falloff, scale with distance.
		float ForceMag = Strength;
		if (Falloff == RIF_Linear)
		{
			ForceMag *= (1.0f - (Mag / Radius));
		}

		// Apply force
		PxVec3 PImpulse = PDelta * ForceMag;
		PRigidBody.addForce(PImpulse, bAccelChange ? PxForceMode::eACCELERATION : PxForceMode::eFORCE);
	}
#endif // WITH_PHYSX
}
Example #7
0
PxVec3 PxRigidBodyExt::getLocalVelocityAtLocalPos(const PxRigidBody& body, const PxVec3& point)
{
	const PxTransform globalPose = body.getGlobalPose();
	const PxVec3 centerOfMass    = globalPose.transform(body.getCMassLocalPose().p);
	const PxVec3 rpoint          = globalPose.transform(point) - centerOfMass;

	return getVelocityAtPosInternal(body, rpoint);
}
Example #8
0
PxVec3 PxRigidBodyExt::getVelocityAtOffset(const PxRigidBody& body, const PxVec3& point)
{
	const PxTransform globalPose = body.getGlobalPose();
	const PxVec3 centerOfMass    = globalPose.rotate(body.getCMassLocalPose().p);
	const PxVec3 rpoint          = point - centerOfMass;

	return getVelocityAtPosInternal(body, rpoint);
}
void PxRigidBodyExt::computeVelocityDeltaFromImpulse(const PxRigidBody& body, const PxTransform& globalPose, const PxVec3& point, const PxVec3& impulse, const PxReal invMassScale, 
														const PxReal invInertiaScale, PxVec3& linearVelocityChange, PxVec3& angularVelocityChange)
{
	const PxVec3 centerOfMass = globalPose.transform(body.getCMassLocalPose().p);
	const PxReal invMass = body.getInvMass() * invMassScale;
	const PxVec3 invInertiaMS = body.getMassSpaceInvInertiaTensor() * invInertiaScale;

	PxMat33 invInertia;
	transformInertiaTensor(invInertiaMS, PxMat33(globalPose.q), invInertia);
	linearVelocityChange = impulse * invMass;
	const PxVec3 rXI = (point - centerOfMass).cross(impulse);
	angularVelocityChange = invInertia * rXI;
}
/** Applies torques - Assumes caller has obtained writer lock */
void FPhysSubstepTask::ApplyTorques_AssumesLocked(const FPhysTarget& PhysTarget, FBodyInstance* BodyInstance)
{
#if WITH_PHYSX
	/** Apply Torques */
	PxRigidBody* PRigidBody = BodyInstance->GetPxRigidBody_AssumesLocked();

	for (int32 i = 0; i < PhysTarget.Torques.Num(); ++i)
	{
		const FTorqueTarget& TorqueTarget = PhysTarget.Torques[i];
		PRigidBody->addTorque(U2PVector(TorqueTarget.Torque), TorqueTarget.bAccelChange ? PxForceMode::eACCELERATION : PxForceMode::eFORCE, true);
	}
#endif
}
Example #11
0
void PhysActor_PhysX::AddTorque(vec3f torque, PhysForceMode::Enum mode)
{
	if (!impl->physActor)
	{
		LOG("Cannot add torque to actor because physActor is null!");
		return;
	}

	PxRigidBody* actor = nullptr;

	PxVec3 pushDir;
	pushDir.x = torque.x;
	pushDir.y = torque.y;
	pushDir.z = torque.z;

	PxForceMode::Enum physXMode;

	switch (mode)
	{
	case PhysForceMode::Acceleration:
		physXMode = PxForceMode::eACCELERATION;
		break;

	case PhysForceMode::Force:
		physXMode = PxForceMode::eFORCE;
		break;

	case PhysForceMode::VelocityChange:
		physXMode = PxForceMode::eVELOCITY_CHANGE;
		break;

	case PhysForceMode::Impulse:
	default:
		physXMode = PxForceMode::eIMPULSE;
		break;
	}

	if (impl->physActor->isRigidDynamic() || impl->physActor->isRigidBody())
	{
		actor = (PxRigidBody*)impl->physActor;
	}
	else
	{
		LOG("Cannot add force to actor because actor is not a Rigid Dynamic or Rigid Body actor.");
		return;
	}

	if (actor)
		actor->addTorque(pushDir, physXMode);
}
void FPhysSubstepTask::SubstepInterpolation(float InAlpha, float DeltaTime)
{
#if WITH_PHYSX
#if WITH_APEX
	SCOPED_APEX_SCENE_WRITE_LOCK(PAScene);
	PxScene * PScene = PAScene->getPhysXScene();
#else
	PxScene * PScene = PAScene;
	SCOPED_SCENE_WRITE_LOCK(PScene);
#endif
	
	/** Note: We lock the entire scene before iterating. The assumption is that removing an FBodyInstance from the map will also be wrapped by this lock */
	
	
	PhysTargetMap& Targets = PhysTargetBuffers[!External];

	for (PhysTargetMap::TIterator Itr = Targets.CreateIterator(); Itr; ++Itr)
	{
		FPhysTarget & PhysTarget = Itr.Value();
		FBodyInstance * BodyInstance = Itr.Key();
		PxRigidBody* PRigidBody = BodyInstance->GetPxRigidBody_AssumesLocked();

		if (PRigidBody == NULL)
		{
			continue;
		}

		//We should only be iterating over actors that belong to this scene
		check(PRigidBody->getScene() == PScene);

		if (!IsKinematicHelper(PRigidBody))
		{
			ApplyCustomPhysics(PhysTarget, BodyInstance, DeltaTime);
			ApplyForces_AssumesLocked(PhysTarget, BodyInstance);
			ApplyTorques_AssumesLocked(PhysTarget, BodyInstance);
			ApplyRadialForces_AssumesLocked(PhysTarget, BodyInstance);
		}else
		{
			InterpolateKinematicActor_AssumesLocked(PhysTarget, BodyInstance, InAlpha);
		}
	}

	/** Final substep */
	if (InAlpha >= 1.f)
	{
		Targets.Empty(Targets.Num());
	}
#endif
}
static bool setMassAndUpdateInertia(bool multipleMassOrDensity, PxRigidBody& body, const PxReal* masses, PxU32 massCount, const PxVec3* massLocalPose, bool includeNonSimShapes)
{
	bool success;

	// default values in case there were no shapes
	PxReal massOut = 1.0f;
	PxVec3 diagTensor(1.0f,1.0f,1.0f);
	PxQuat orient = PxQuat(PxIdentity);
	bool lockCom = massLocalPose != NULL;
	PxVec3 com = lockCom ? *massLocalPose : PxVec3(0);
	const char* errorStr = "PxRigidBodyExt::setMassAndUpdateInertia";

	if(masses && massCount)
	{
		Ext::InertiaTensorComputer inertiaComp(true);
		if(computeMassAndInertia(multipleMassOrDensity, body, NULL, masses, massCount, includeNonSimShapes, inertiaComp))
		{
			success = true;

			if (inertiaComp.getMass()!=0 && !computeMassAndDiagInertia(inertiaComp, diagTensor, orient, massOut, com, lockCom, body, errorStr))
				success = false;  // computeMassAndDiagInertia() failed (mass zero?)

			if (massCount == 1)
				massOut = masses[0]; // to cover special case where body has no simulation shape
		}
		else
		{
			Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
				"%s: Mass and inertia computation failed, setting mass to 1 and inertia to (1,1,1)", errorStr);

			success = false;
		}
	}
	else
	{
		Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
			"%s: No mass specified, setting mass to 1 and inertia to (1,1,1)", errorStr);
		success = false;
	}

	PX_ASSERT(orient.isFinite());
	PX_ASSERT(diagTensor.isFinite());

	body.setMass(massOut);
	body.setMassSpaceInertiaTensor(diagTensor);
	body.setCMassLocalPose(PxTransform(com, orient));

	return success;
}
Example #14
0
Vec3 PhysXPhysics::VGetVelocity(ActorId actorId)
{
	PxRigidBody* pBody = FindRigidBody(actorId);
	BE_ASSERT(pBody);
	if (!pBody)
	{
		return Vec3::g_InvalidVec3;
	}
	PxVec3 pxVec = pBody->getLinearVelocity();

	Vec3 velocity;
	PxVecToVec3(pxVec, &velocity);

	return velocity;
}
static bool updateMassAndInertia(bool multipleMassOrDensity, PxRigidBody& body, const PxReal* densities, PxU32 densityCount, const PxVec3* massLocalPose, bool includeNonSimShapes)
{
	bool success;

	// default values in case there were no shapes
	PxReal massOut = 1.0f;
	PxVec3 diagTensor(1.f,1.f,1.f);
	PxQuat orient = PxQuat(PxIdentity);
	bool lockCom = massLocalPose != NULL;
	PxVec3 com = lockCom ? *massLocalPose : PxVec3(0);
	const char* errorStr = "PxRigidBodyExt::updateMassAndInertia";

	if (densities && densityCount)
	{
		Ext::InertiaTensorComputer inertiaComp(true);
		if(computeMassAndInertia(multipleMassOrDensity, body, densities, NULL, densityCount, includeNonSimShapes, inertiaComp))
		{
			if(inertiaComp.getMass()!=0 && computeMassAndDiagInertia(inertiaComp, diagTensor, orient, massOut, com, lockCom, body, errorStr))
				success = true;
			else
				success = false;  // body with no shapes provided or computeMassAndDiagInertia() failed
		}
		else
		{
			Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
				"%s: Mass and inertia computation failed, setting mass to 1 and inertia to (1,1,1)", errorStr);

			success = false;
		}
	}
	else
	{
		Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
			"%s: No density specified, setting mass to 1 and inertia to (1,1,1)", errorStr);

		success = false;
	}

	PX_ASSERT(orient.isFinite());
	PX_ASSERT(diagTensor.isFinite());
	PX_ASSERT(PxIsFinite(massOut));

	body.setMass(massOut);
	body.setMassSpaceInertiaTensor(diagTensor);
	body.setCMassLocalPose(PxTransform(com, orient));

	return success;
}
Example #16
0
void PxRigidBodyExt::addForceAtLocalPos(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup)
{
	//transform pos to world space
	const PxVec3 globalForcePos = body.getGlobalPose().transform(pos);

	addForceAtPosInternal(body, force, globalForcePos, mode, wakeup);
}
Example #17
0
PX_INLINE void addForceAtPosInternal(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup)
{
	if(mode == PxForceMode::eACCELERATION || mode == PxForceMode::eVELOCITY_CHANGE)
	{
		Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
			"PxRigidBodyExt::addForce methods do not support eACCELERATION or eVELOCITY_CHANGE modes");
		return;
	}

	const PxTransform globalPose = body.getGlobalPose();
	const PxVec3 centerOfMass = globalPose.transform(body.getCMassLocalPose().p);

	const PxVec3 torque = (pos - centerOfMass).cross(force);
	body.addForce(force, mode, wakeup);
	body.addTorque(torque, mode, wakeup);
}
void PxRigidBodyExt::computeLinearAngularImpulse(const PxRigidBody& body, const PxTransform& globalPose, const PxVec3& point, const PxVec3& impulse, const PxReal invMassScale, 
														const PxReal invInertiaScale, PxVec3& linearImpulse, PxVec3& angularImpulse)
{
	const PxVec3 centerOfMass = globalPose.transform(body.getCMassLocalPose().p);
	linearImpulse = impulse * invMassScale;
	angularImpulse = (point - centerOfMass).cross(impulse) * invInertiaScale;
}
Example #19
0
void PxRigidBodyExt::addLocalForceAtLocalPos(PxRigidBody& body, const PxVec3& force, const PxVec3& pos, PxForceMode::Enum mode, bool wakeup)
{
	const PxTransform globalPose = body.getGlobalPose();
	const PxVec3 globalForcePos = globalPose.transform(pos);
	const PxVec3 globalForce = globalPose.rotate(force);

	addForceAtPosInternal(body, globalForce, globalForcePos, mode, wakeup);
}
static bool computeMassAndDiagInertia(Ext::InertiaTensorComputer& inertiaComp, 
		PxVec3& diagTensor, PxQuat& orient, PxReal& massOut, PxVec3& coM, bool lockCOM, const PxRigidBody& body, const char* errorStr)
{
	// The inertia tensor and center of mass is relative to the actor at this point. Transform to the
	// body frame directly if CoM is specified, else use computed center of mass
	if (lockCOM)
	{
		inertiaComp.translate(-coM);  // base the tensor on user's desired center of mass.
	}
	else
	{
		//get center of mass - has to be done BEFORE centering.
		coM = inertiaComp.getCenterOfMass();

		//the computed result now needs to be centered around the computed center of mass:
		inertiaComp.center();
	}
	// The inertia matrix is now based on the body's center of mass desc.massLocalPose.p
	
	massOut = inertiaComp.getMass();
	diagTensor = PxDiagonalize(inertiaComp.getInertia(), orient);

	if ((diagTensor.x > 0.0f) && (diagTensor.y > 0.0f) && (diagTensor.z > 0.0f))
		return true;
	else
	{
		Ps::getFoundation().error(PxErrorCode::eDEBUG_WARNING, __FILE__, __LINE__, 
								"%s: inertia tensor has negative components (ill-conditioned input expected). Approximation for inertia tensor will be used instead.", errorStr);

		// keep center of mass but use the AABB as a crude approximation for the inertia tensor
		PxBounds3 bounds = body.getWorldBounds();
		PxTransform pose = body.getGlobalPose();
		bounds = PxBounds3::transformFast(pose.getInverse(), bounds);
		Ext::InertiaTensorComputer it(false);
		it.setBox(bounds.getExtents());
		it.scaleDensity(massOut / it.getMass());
		PxMat33 inertia = it.getInertia();
		diagTensor = PxVec3(inertia.column0.x, inertia.column1.y, inertia.column2.z);
		orient = PxQuat(PxIdentity);

		return true;
	}
}
void SceneQueryManager::validateSimUpdates()
{
	if (mPrunerExt[1].type() != PxPruningStructureType::eDYNAMIC_AABB_TREE)
		return;

	
	Sc::BodyCore*const* activeBodies = mScene.getActiveBodiesArray();
	const PxU32 nbActiveBodies = mScene.getNumActiveBodies();

	for (PxU32 i = 0; i < nbActiveBodies; ++i)
	{
		const Sc::BodyCore* bCore = activeBodies[i];

		if (bCore->isFrozen())
			continue;

		PxRigidBody* pxBody = static_cast<PxRigidBody*>(bCore->getPxActor());

		PX_ASSERT(pxBody->getConcreteType() == PxConcreteType::eRIGID_DYNAMIC || pxBody->getConcreteType() == PxConcreteType::eARTICULATION_LINK);

		NpShapeManager& shapeManager = *NpActor::getShapeManager(*pxBody);
		const PxU32 nbShapes = shapeManager.getNbShapes();
		NpShape* const* shape = shapeManager.getShapes();
		

		for (PxU32 j = 0; j<nbShapes; j++)
		{
			PrunerData prunerData = shapeManager.getPrunerData(j);
			if (prunerData != INVALID_PRUNERHANDLE)
			{
				const PrunerHandle handle = getPrunerHandle(prunerData);
				const PxBounds3 worldAABB = computeWorldAABB(shape[j]->getScbShape(), *bCore);
				PxBounds3 prunerAABB = static_cast<AABBPruner*>(mPrunerExt[1].pruner())->getAABB(handle);
				PX_ASSERT((worldAABB.minimum - prunerAABB.minimum).magnitudeSquared() < 0.005f*mScene.getPxScene()->getPhysics().getTolerancesScale().length);
				PX_ASSERT((worldAABB.maximum - prunerAABB.maximum).magnitudeSquared() < 0.005f*mScene.getPxScene()->getPhysics().getTolerancesScale().length);
				PX_UNUSED(worldAABB);
				PX_UNUSED(prunerAABB);
			}
		}
	}
}
/** Applies forces - Assumes caller has obtained writer lock */
void FPhysSubstepTask::ApplyForces_AssumesLocked(const FPhysTarget& PhysTarget, FBodyInstance* BodyInstance)
{
#if WITH_PHYSX
	/** Apply Forces */
	PxRigidBody* PRigidBody = BodyInstance->GetPxRigidBody_AssumesLocked();

	for (int32 i = 0; i < PhysTarget.Forces.Num(); ++i)
	{
		const FForceTarget& ForceTarget = PhysTarget.Forces[i];

		if (ForceTarget.bPosition)
		{
			PxRigidBodyExt::addForceAtPos(*PRigidBody, U2PVector(ForceTarget.Force), U2PVector(ForceTarget.Position), PxForceMode::eFORCE, true);
		}
		else
		{
			PRigidBody->addForce(U2PVector(ForceTarget.Force), ForceTarget.bAccelChange ? PxForceMode::eACCELERATION : PxForceMode::eFORCE, true);
		}
	}
#endif
}
Example #23
0
void PhysActor_PhysX::SetAngularVelocity(vec3f velocity)
{
	if (!impl->physActor)
	{
		LOG("Cannot set angular velocity from actor because actor ptr is null!");
		return;
	}

	PxRigidBody* actor = nullptr;

	if (impl->physActor->isRigidDynamic() || impl->physActor->isRigidBody())
		actor = (PxRigidBody*)impl->physActor;
	else
	{
		LOG("Cannot set angular velocity from actor because actor is not a Rigid Dynamic or Rigid Body actor.");
		return;
	}

	if (!actor)
		return;

	actor->setAngularVelocity(PxVec3(velocity.x, velocity.y, velocity.z));
}
void SimulationEventCallback::destroyWallBlock(const PxRigidBody& _krRigidBody, const PxShape& _krShape)
{
	Entity* wallBlock = static_cast<Entity*>(_krRigidBody.userData);
	if (find(m_destroyedWallBlocks.begin(), m_destroyedWallBlocks.end(), wallBlock) != m_destroyedWallBlocks.end())
	{
		return;
	}

	PxBoxGeometry geometry;
	_krShape.getBoxGeometry(geometry);

	PxTransform transform = _krRigidBody.getGlobalPose();
	Matrix44 transformation = PhysXMatrix::toMatrix44(transform);

	PxVec3 angularVelocity = _krRigidBody.getAngularVelocity();
	PxVec3 linearVelocity = _krRigidBody.getLinearVelocity();

	m_destroyedWallBlocks.push_back(wallBlock);
	GazEngine::removeEntity(*wallBlock);

	float halfSize = geometry.halfExtents.x / 2.0f;

	Matrix44 fragment0Transformation = transformation;
	getTranslation3(fragment0Transformation) += Vector3(-halfSize, halfSize, 0.0f);
	Entity* pFragment0 = CreateWallBlock(fragment0Transformation, halfSize, *m_pParentNode);
	PxRigidBody* pFragment0RigidBody = pFragment0->getSingleComponent<PhysXBody>()->getActor()->isRigidBody();
	pFragment0RigidBody->setAngularVelocity(angularVelocity);
	pFragment0RigidBody->setLinearVelocity(linearVelocity);
	// The body only got a position in the constructor... lets give it a rotation too.
	PxTransform fragment0Transform = transform;
	fragment0Transform.p += PxVec3(-halfSize, halfSize, 0.0f);
	pFragment0RigidBody->setGlobalPose(fragment0Transform);

	Matrix44 fragment1Transformation = transformation;
	getTranslation3(fragment1Transformation) += Vector3(halfSize, halfSize, 0.0f);
	Entity* pFragment1 = CreateWallBlock(fragment1Transformation, halfSize, *m_pParentNode);
	PxRigidBody* pFragment1RigidBody = pFragment1->getSingleComponent<PhysXBody>()->getActor()->isRigidBody();
	pFragment1RigidBody->setAngularVelocity(angularVelocity);
	pFragment1RigidBody->setLinearVelocity(linearVelocity);
	// The body only got a position in the constructor... lets give it a rotation too.
	PxTransform fragment1Transform = transform;
	fragment1Transform.p += PxVec3(halfSize, halfSize, 0.0f);
	pFragment1RigidBody->setGlobalPose(fragment1Transform);

	Matrix44 fragment2Transformation = transformation;
	getTranslation3(fragment2Transformation) += Vector3(halfSize, -halfSize, 0.0f);
	Entity* pFragment2 = CreateWallBlock(fragment2Transformation, halfSize, *m_pParentNode);
	PxRigidBody* pFragment2RigidBody = pFragment2->getSingleComponent<PhysXBody>()->getActor()->isRigidBody();
	pFragment2RigidBody->setAngularVelocity(angularVelocity);
	pFragment2RigidBody->setLinearVelocity(linearVelocity);
	// The body only got a position in the constructor... lets give it a rotation too.
	PxTransform fragment2Transform = transform;
	fragment2Transform.p += PxVec3(halfSize, -halfSize, 0.0f);
	pFragment2RigidBody->setGlobalPose(fragment2Transform);

	Matrix44 fragment3Transformation = transformation;
	getTranslation3(fragment3Transformation) += Vector3(-halfSize, -halfSize, 0.0f);
	Entity* pFragment3 = CreateWallBlock(fragment3Transformation, halfSize, *m_pParentNode);
	PxRigidBody* pFragment3RigidBody = pFragment3->getSingleComponent<PhysXBody>()->getActor()->isRigidBody();
	pFragment3RigidBody->setAngularVelocity(angularVelocity);
	pFragment3RigidBody->setLinearVelocity(linearVelocity);
	// The body only got a position in the constructor... lets give it a rotation too.
	PxTransform fragment3Transform = transform;
	fragment3Transform.p += PxVec3(-halfSize, -halfSize, 0.0f);
	pFragment3RigidBody->setGlobalPose(fragment3Transform);
}
Example #25
0
static void sweepRigidBody(PxRigidBody& body, PxBatchQuery& batchQuery, bool closestObject, const PxVec3& unitDir, const PxReal distance, PxSceneQueryFilterFlags filterFlags, 
		bool useShapeFilterData, PxFilterData* filterDataList, PxU32 filterDataCount, void* userData, const PxSweepCache* sweepCache)
{
	if (body.getNbShapes() == 0)
		return;

	const char* outOfMemMsg = "PxRigidBodyExt: LinearSweep: Out of memory, call failed.";
	bool succeeded = true;

	PX_ALLOCA(shapes, PxShape*, body.getNbShapes());
	if (!shapes)
	{
		Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, outOfMemMsg);
		succeeded = false;
	}
	PxU32 nbShapes = body.getShapes(shapes, body.getNbShapes());
	
	PX_ALLOCA(geoms, const PxGeometry*, nbShapes);
	if (!geoms)
	{
		Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, outOfMemMsg);
		succeeded = false;
	}

	PX_ALLOCA(poses, PxTransform, nbShapes);
	if (!poses)
	{
		Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, outOfMemMsg);
		succeeded = false;
	}

	PxFilterData* filterData = NULL;
	PX_ALLOCA(filterDataBuffer, PxFilterData, nbShapes);
	if (useShapeFilterData)
	{
		filterData = filterDataBuffer;

		if (!filterDataBuffer)
		{
			Ps::getFoundation().error(PxErrorCode::eOUT_OF_MEMORY, __FILE__, __LINE__, outOfMemMsg);
			succeeded = false;
		}
	}
	else if (filterDataList)
	{
		if (filterDataCount == nbShapes)
		{
			filterData = filterDataList;
		}
		else
		{
			Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "PxRigidBodyExt: LinearSweep: Number of filter data entries does not match number of shapes, call failed.");
			succeeded = false;
		}
	}

	if (succeeded)
	{
		PxU32 geomByteSize = 0;

		for(PxU32 i=0; i < nbShapes; i++)
		{
			poses[i] = PxShapeExt::getGlobalPose(*shapes[i]);

			if (useShapeFilterData)
				filterData[i] = shapes[i]->getSimulationFilterData();

			// Copy the non-supported geometry types too, to make sure the closest geometry index maps to the shapes
			switch(shapes[i]->getGeometryType())
			{
				case PxGeometryType::eSPHERE : 
				{
					geomByteSize += sizeof(PxSphereGeometry);
				}
				break;

				case PxGeometryType::eBOX : 
				{
					geomByteSize += sizeof(PxBoxGeometry);
				}
				break;

				case PxGeometryType::eCAPSULE : 
				{
					geomByteSize += sizeof(PxCapsuleGeometry);
				}
				break;

				case PxGeometryType::eCONVEXMESH : 
				{
					geomByteSize += sizeof(PxConvexMeshGeometry);
				}
				break;

				case PxGeometryType::ePLANE : 
				{
					geomByteSize += sizeof(PxPlaneGeometry);
				}
				break;

				case PxGeometryType::eTRIANGLEMESH : 
				{
					geomByteSize += sizeof(PxTriangleMeshGeometry);
				}
				break;

				case PxGeometryType::eHEIGHTFIELD : 
				{
					geomByteSize += sizeof(PxHeightFieldGeometry);
				}
				break;
				default:
				break;
			}
		}

		PX_ALLOCA(geomBuffer, PxU8, geomByteSize);

		if (geomBuffer)
		{
			PxU8* currBufferPos = geomBuffer;

			for(PxU32 i=0; i < nbShapes; i++)
			{
				// Copy the non-supported geometry types too, to make sure the closest geometry index maps to the shapes
				switch(shapes[i]->getGeometryType())
				{
					case PxGeometryType::eSPHERE : 
					{
						PxSphereGeometry* g = reinterpret_cast<PxSphereGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getSphereGeometry(*g);
						currBufferPos += sizeof(PxSphereGeometry);
					}
					break;

					case PxGeometryType::eBOX : 
					{
						PxBoxGeometry* g = reinterpret_cast<PxBoxGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getBoxGeometry(*g);
						currBufferPos += sizeof(PxBoxGeometry);
					}
					break;

					case PxGeometryType::eCAPSULE : 
					{
						PxCapsuleGeometry* g = reinterpret_cast<PxCapsuleGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getCapsuleGeometry(*g);
						currBufferPos += sizeof(PxCapsuleGeometry);
					}
					break;

					case PxGeometryType::eCONVEXMESH : 
					{
						PxConvexMeshGeometry* g = reinterpret_cast<PxConvexMeshGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getConvexMeshGeometry(*g);
						currBufferPos += sizeof(PxConvexMeshGeometry);
					}
					break;

					case PxGeometryType::ePLANE : 
					{
						PxPlaneGeometry* g = reinterpret_cast<PxPlaneGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getPlaneGeometry(*g);
						currBufferPos += sizeof(PxPlaneGeometry);
					}
					break;

					case PxGeometryType::eTRIANGLEMESH : 
					{
						PxTriangleMeshGeometry* g = reinterpret_cast<PxTriangleMeshGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getTriangleMeshGeometry(*g);
						currBufferPos += sizeof(PxTriangleMeshGeometry);
					}
					break;

					case PxGeometryType::eHEIGHTFIELD : 
					{
						PxHeightFieldGeometry* g = reinterpret_cast<PxHeightFieldGeometry*>(currBufferPos);
						geoms[i] = g;
						shapes[i]->getHeightFieldGeometry(*g);
						currBufferPos += sizeof(PxHeightFieldGeometry);
					}
					break;
					default:
					break;
				}
			}

			if (closestObject)
				batchQuery.linearCompoundGeometrySweepSingle(geoms, poses, filterData, nbShapes, unitDir, distance, filterFlags, PxSceneQueryFlag::eIMPACT|PxSceneQueryFlag::eNORMAL|PxSceneQueryFlag::eDISTANCE|PxSceneQueryFlag::eUV, userData, sweepCache);
			else
				batchQuery.linearCompoundGeometrySweepMultiple(geoms, poses, filterData, nbShapes, unitDir, distance, filterFlags, PxSceneQueryFlag::eIMPACT|PxSceneQueryFlag::eNORMAL|PxSceneQueryFlag::eDISTANCE|PxSceneQueryFlag::eUV, userData, sweepCache);
		}
	}
}
void SceneQueryManager::processSimUpdates()
{
	PX_PROFILE_ZONE("Sim.updatePruningTrees", mScene.getContextId());

	{
		PX_PROFILE_ZONE("SceneQuery.processActiveShapes", mScene.getContextId());

		// update all active objects
		BodyCore*const* activeBodies = mScene.getScScene().getActiveBodiesArray();
		PxU32 nbActiveBodies = mScene.getScScene().getNumActiveBodies();

#define NB_BATCHED_OBJECTS	128
		PrunerHandle batchedHandles[NB_BATCHED_OBJECTS];
		PxU32 nbBatchedObjects = 0;
		Pruner* pruner = mPrunerExt[PruningIndex::eDYNAMIC].pruner();

		while(nbActiveBodies--)
		{
			// PT: TODO: don't put frozen objects in "active bodies" array? After all they
			// are also not included in the 'active transforms' or 'active actors' arrays.
			BodyCore* currentBody = *activeBodies++;
			if(currentBody->isFrozen())
				continue;

			PxActorType::Enum type;
			PxRigidBody* pxBody = static_cast<PxRigidBody*>(getPxActorFromBodyCore(currentBody, type));
			PX_ASSERT(pxBody->getConcreteType()==PxConcreteType::eRIGID_DYNAMIC || pxBody->getConcreteType()==PxConcreteType::eARTICULATION_LINK);

			NpShapeManager* shapeManager;
			if(type==PxActorType::eRIGID_DYNAMIC)
			{
				NpRigidDynamic* rigidDynamic = static_cast<NpRigidDynamic*>(pxBody);
				shapeManager = &rigidDynamic->getShapeManager();
			}
			else
			{
				NpArticulationLink* articulationLink = static_cast<NpArticulationLink*>(pxBody);
				shapeManager = &articulationLink->getShapeManager();
			}

			const PxU32 nbShapes = shapeManager->getNbShapes();
			for(PxU32 i=0; i<nbShapes; i++)
			{
				const PrunerData data = shapeManager->getPrunerData(i);
				if(data!=SQ_INVALID_PRUNER_DATA)
				{
					// PT: index can't be zero here!
					PX_ASSERT(getPrunerIndex(data)==PruningIndex::eDYNAMIC);

					const PrunerHandle handle = getPrunerHandle(data);

					if(!mPrunerExt[PruningIndex::eDYNAMIC].isDirty(handle))	// PT: if dirty, will be updated in "flushShapes"
					{
						batchedHandles[nbBatchedObjects] = handle;

						PxBounds3* bounds;
						const PrunerPayload& pp = pruner->getPayload(handle, bounds);
						computeDynamicWorldAABB(*bounds, *(reinterpret_cast<Scb::Shape*>(pp.data[0])), *(reinterpret_cast<Scb::Actor*>(pp.data[1])));
						nbBatchedObjects++;

						if(nbBatchedObjects==NB_BATCHED_OBJECTS)
						{
							mPrunerExt[PruningIndex::eDYNAMIC].invalidateTimestamp();
							pruner->updateObjects(batchedHandles, NULL, nbBatchedObjects);
							nbBatchedObjects = 0;
						}
					}
				}
			}
		}
		if(nbBatchedObjects)
		{
			mPrunerExt[PruningIndex::eDYNAMIC].invalidateTimestamp();
			pruner->updateObjects(batchedHandles, NULL, nbBatchedObjects);
		}
	}

	// flush user modified objects
	flushShapes();

	for(PxU32 i=0;i<PruningIndex::eCOUNT;i++)
	{
		if(mPrunerExt[i].pruner() && mPrunerExt[i].type() == PxPruningStructureType::eDYNAMIC_AABB_TREE)
			static_cast<AABBPruner*>(mPrunerExt[i].pruner())->buildStep();

		mPrunerExt[i].pruner()->commit();
	}
}
Example #27
0
// Called every frame for vehicle
void Vehicle::update()
{
    resetIfNeeded();

    float handBrake = 0;
    float forwardSpeed = physicsVehicle->computeForwardSpeed();
    (input.handBrake) ? handBrake = 1.0f: handBrake = 0.0f;

    // Force gear change if speed is 0 (works, not sure why)
    if (forwardSpeed == 0)
    {
        if (input.forward > 0)
        {
            physicsVehicle->mDriveDynData.forceGearChange(PxVehicleGearsData::eFIRST);
        }
        else if (input.backward > 0)
        {
            physicsVehicle->mDriveDynData.forceGearChange(PxVehicleGearsData::eREVERSE);
        }
    }
    // If speed is close to 0 set new target gear
    else if (forwardSpeed < 5 && input.backward > 0)
    {
        physicsVehicle->mDriveDynData.setTargetGear(PxVehicleGearsData::eREVERSE);
    }
    else if (forwardSpeed > -5 && input.forward > 0)
    {
        physicsVehicle->mDriveDynData.setTargetGear(PxVehicleGearsData::eFIRST);
    }

    // Determine how to apply controller input depending on current gear
    if (physicsVehicle->mDriveDynData.getCurrentGear() == PxVehicleGearsData::eREVERSE)
    {
        vehicleInput.setAnalogAccel(input.backward);
        vehicleInput.setAnalogBrake(input.forward);
    }
    else
    {
        vehicleInput.setAnalogAccel(input.forward);
        vehicleInput.setAnalogBrake(input.backward);
        if(input.forward > 0)
            gasSignal(this);
    }
    if (input.forward == 0 && input.backward == 0)
        idleSignal(this);
    if (isSlipping && (forwardSpeed > 5 || forwardSpeed < -5))
        brakeSignal(this);

    // Steer and handbrake
    vehicleInput.setAnalogSteer(input.steer);
    vehicleInput.setAnalogHandbrake(handBrake);

    PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(smoothingData, steerVsSpeedTable, vehicleInput, stepSizeS, isInAir, *physicsVehicle);

    if (input.shootPizza)
    {
        if (pizzaCount > 0)
        {
            shootPizzaSignal(this);
            pizzaCount--;
        }
        else
        {
            dryFireSignal(this);
        }
        input.shootPizza = false;
    }

    if (input.jump && (!isInAir || spaceMode))
    {
        PxRigidBody* rigid = (PxRigidBody*)actor;
        rigid->addForce(PxVec3(0, 375, 0), PxForceMode::eACCELERATION);
        input.jump = false;
    }
}
//=================================================================================
// Multiple hits compound sweep
// AP: we might be able to improve the return results API but no time for it in 3.3
PxU32 PxRigidBodyExt::linearSweepMultiple(
	PxRigidBody& body, PxScene& scene, const PxVec3& unitDir, const PxReal distance, PxHitFlags outputFlags,
	PxSweepHit* hitBuffer, PxU32* hitShapeIndices, PxU32 hitBufferSize, PxSweepHit& block, PxI32& blockingHitShapeIndex,
	bool& overflow, const PxQueryFilterData& filterData, PxQueryFilterCallback* filterCall,
	const PxQueryCache* cache, const PxReal inflation)
{
	overflow = false;
	blockingHitShapeIndex = -1;

	for (PxU32 i = 0; i < hitBufferSize; i++)
		hitShapeIndices[i] = 0xFFFFffff;

	PxI32 sumNbResults = 0;

	PxU32 nbShapes = body.getNbShapes();
	PxF32 shrunkMaxDistance = distance;
	for(PxU32 i=0; i < nbShapes; i++)
	{
		PxShape* shape = NULL;
		body.getShapes(&shape, 1, i);
		PX_ASSERT(shape != NULL);
		PxTransform pose = PxShapeExt::getGlobalPose(*shape, body);
		PxQueryFilterData fd;
		fd.flags = filterData.flags;
		PxU32 or4 = (filterData.data.word0 | filterData.data.word1 | filterData.data.word2 | filterData.data.word3);
		fd.data = or4 ? filterData.data : shape->getSimulationFilterData();
		PxGeometryHolder anyGeom = shape->getGeometry();

		PxU32 bufSizeLeft = hitBufferSize-sumNbResults;
		PxSweepHit extraHit;
		PxSweepBuffer buffer(bufSizeLeft == 0 ? &extraHit : hitBuffer+sumNbResults, bufSizeLeft == 0 ? 1 : hitBufferSize-sumNbResults);
		scene.sweep(anyGeom.any(), pose, unitDir, shrunkMaxDistance, buffer, outputFlags, fd, filterCall, cache, inflation);

		// Check and abort on overflow. Assume overflow if result count is bufSize.
		PxU32 nbNewResults = buffer.getNbTouches();
		overflow |= (nbNewResults >= bufSizeLeft);
		if (bufSizeLeft == 0) // this is for when we used the extraHit buffer
			nbNewResults = 0;

		// set hitShapeIndices for each new non-blocking hit
		for (PxU32 j = 0; j < nbNewResults; j++)
			if (sumNbResults + PxU32(j) < hitBufferSize)
				hitShapeIndices[sumNbResults+j] = i;

		if (buffer.hasBlock) // there's a blocking hit in the most recent sweepMultiple results
		{
			// overwrite the return result blocking hit with the new blocking hit if under
			if (blockingHitShapeIndex == -1 || buffer.block.distance < block.distance)
			{
				blockingHitShapeIndex = (PxI32)i;
				block = buffer.block;
			}

			// Remove all the old touching hits below the new maxDist
			// sumNbResults is not updated yet at this point
			//   and represents the count accumulated so far excluding the very last query
			PxI32 nbNewResultsSigned = PxI32(nbNewResults); // need a signed version, see nbNewResultsSigned-- below
			for (PxI32 j = sumNbResults-1; j >= 0; j--) // iterate over "old" hits (up to shapeIndex-1)
				if (buffer.block.distance < hitBuffer[j].distance)
				{
					// overwrite with last "new" hit
					PxI32 sourceIndex = PxI32(sumNbResults)+nbNewResultsSigned-1; PX_ASSERT(sourceIndex >= j);
					hitBuffer[j] = hitBuffer[sourceIndex];
					hitShapeIndices[j] = hitShapeIndices[sourceIndex];
					nbNewResultsSigned--; // can get negative, that means we are shifting the last results array
				}

			sumNbResults += nbNewResultsSigned;
		} else // if there was no new blocking hit we don't need to do anything special, simply append all results to touch array
			sumNbResults += nbNewResults;

		PX_ASSERT(sumNbResults >= 0 && sumNbResults <= PxI32(hitBufferSize));
	}

	return (PxU32)sumNbResults;
}
Example #29
0
static bool computeMassAndInertia(bool multipleMassOrDensity, PxRigidBody& body, const PxReal* densities, const PxReal* masses, PxU32 densityOrMassCount, Ext::InertiaTensorComputer& computer)
{
	PX_ASSERT(!densities || !masses);
	PX_ASSERT((densities || masses) && (densityOrMassCount > 0));

	Ext::InertiaTensorComputer inertiaComp(true);

	Ps::InlineArray<PxShape*, 16> shapes("PxShape*"); shapes.resize(body.getNbShapes());

	body.getShapes(shapes.begin(), shapes.size());

	PxU32 validShapeIndex = 0;
	PxReal currentMassOrDensity;
	const PxReal* massOrDensityArray;
	if (densities)
	{
		massOrDensityArray = densities;
		currentMassOrDensity = densities[0];
	}
	else
	{
		massOrDensityArray = masses;
		currentMassOrDensity = masses[0];
	}
	if (!PxIsFinite(currentMassOrDensity))
	{
		Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
			"computeMassAndInertia: Provided mass or density has no valid value");
		return false;
	}

	for(PxU32 i=0; i < shapes.size(); i++)
	{
		if (!(shapes[i]->getFlags() & PxShapeFlag::eSIMULATION_SHAPE))
			continue; 

		if (multipleMassOrDensity)
		{
			if (validShapeIndex < densityOrMassCount)
			{
				currentMassOrDensity = massOrDensityArray[validShapeIndex];

				if (!PxIsFinite(currentMassOrDensity))
				{
					Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
						"computeMassAndInertia: Provided mass or density has no valid value");
					return false;
				}
			}
			else
			{
				Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
					"computeMassAndInertia: Not enough mass/density values provided for all simulation shapes");
				return false;
			}
		}

		Ext::InertiaTensorComputer it(false);

		switch(shapes[i]->getGeometryType())
		{
		case PxGeometryType::eSPHERE : 
			{
				PxSphereGeometry g;
				bool ok = shapes[i]->getSphereGeometry(g);
				PX_ASSERT(ok);
				PX_UNUSED(ok);
				PxTransform temp(shapes[i]->getLocalPose());

				it.setSphere(g.radius, &temp);
			}
			break;

		case PxGeometryType::eBOX : 
			{
				PxBoxGeometry g;
				bool ok = shapes[i]->getBoxGeometry(g);
				PX_ASSERT(ok);
				PX_UNUSED(ok);
				PxTransform temp(shapes[i]->getLocalPose());

				it.setBox(g.halfExtents, &temp);
			}
			break;

		case PxGeometryType::eCAPSULE : 
			{
				PxCapsuleGeometry g;
				bool ok = shapes[i]->getCapsuleGeometry(g);
				PX_ASSERT(ok);
				PX_UNUSED(ok);
				PxTransform temp(shapes[i]->getLocalPose());

				it.setCapsule(0, g.radius, g.halfHeight, &temp);
			}
			break;

		case PxGeometryType::eCONVEXMESH : 
			{
				PxConvexMeshGeometry g;
				bool ok = shapes[i]->getConvexMeshGeometry(g);
				PX_ASSERT(ok);
				PX_UNUSED(ok);
				PxConvexMesh& convMesh = *g.convexMesh;

				PxReal convMass;
				PxMat33 convInertia;
				PxVec3 convCoM;
				convMesh.getMassInformation(convMass, reinterpret_cast<PxMat33&>(convInertia), convCoM);

				//scale the mass:
				convMass *= (g.scale.scale.x * g.scale.scale.y * g.scale.scale.z);
				convCoM = g.scale.rotation.rotateInv(g.scale.scale.multiply(g.scale.rotation.rotate(convCoM)));
				convInertia = Ext::MassProps::scaleInertia(convInertia, g.scale.rotation, g.scale.scale);

				it = Ext::InertiaTensorComputer(convInertia, convCoM, convMass);
				it.transform(shapes[i]->getLocalPose());
			}
			break;

		default :
			{

				Ps::getFoundation().error(PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, 
					"computeMassAndInertia: Dynamic actor with illegal collision shapes");
				return false;
			}
		}

		if (densities)
			it.scaleDensity(currentMassOrDensity);
		else if (multipleMassOrDensity)  // mass per shape -> need to scale density per shape
			it.scaleDensity(currentMassOrDensity / it.getMass());

		inertiaComp.add(it);

		validShapeIndex++;
	}

	if (validShapeIndex && masses && (!multipleMassOrDensity))  // at least one simulation shape and single mass for all shapes -> scale density at the end
	{
		inertiaComp.scaleDensity(currentMassOrDensity / inertiaComp.getMass());
	}

	computer = inertiaComp;
	return true;
}