Projekt_Grafika/dependencies/physx-4.1/source/physx/src/NpRigidBodyTemplate.h

645 lines
21 KiB
C++

//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2019 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef PX_PHYSICS_NP_RIGIDBODY_TEMPLATE
#define PX_PHYSICS_NP_RIGIDBODY_TEMPLATE
#include "NpRigidActorTemplate.h"
#include "ScbBody.h"
#include "NpPhysics.h"
#include "NpShape.h"
#include "NpScene.h"
namespace physx
{
PX_INLINE PxVec3 invertDiagInertia(const PxVec3& m)
{
return PxVec3( m.x == 0.0f ? 0.0f : 1.0f/m.x,
m.y == 0.0f ? 0.0f : 1.0f/m.y,
m.z == 0.0f ? 0.0f : 1.0f/m.z);
}
#if PX_ENABLE_DEBUG_VISUALIZATION
/*
given the diagonal of the body space inertia tensor, and the total mass
this returns the body space AABB width, height and depth of an equivalent box
*/
PX_INLINE PxVec3 getDimsFromBodyInertia(const PxVec3& inertiaMoments, PxReal mass)
{
const PxVec3 inertia = inertiaMoments * (6.0f/mass);
return PxVec3( PxSqrt(PxAbs(- inertia.x + inertia.y + inertia.z)),
PxSqrt(PxAbs(+ inertia.x - inertia.y + inertia.z)),
PxSqrt(PxAbs(+ inertia.x + inertia.y - inertia.z)));
}
#endif
template<class APIClass>
class NpRigidBodyTemplate : public NpRigidActorTemplate<APIClass>
{
private:
typedef NpRigidActorTemplate<APIClass> RigidActorTemplateClass;
public:
// PX_SERIALIZATION
NpRigidBodyTemplate(PxBaseFlags baseFlags) : RigidActorTemplateClass(baseFlags), mBody(PxEmpty) {}
//~PX_SERIALIZATION
virtual ~NpRigidBodyTemplate();
//---------------------------------------------------------------------------------
// PxRigidActor implementation
//---------------------------------------------------------------------------------
// The rule is: If an API method is used somewhere in here, it has to be redeclared, else GCC whines
virtual PxTransform getGlobalPose() const = 0;
//---------------------------------------------------------------------------------
// PxRigidBody implementation
//---------------------------------------------------------------------------------
// Center of mass pose
virtual PxTransform getCMassLocalPose() const;
// Mass
virtual void setMass(PxReal mass);
virtual PxReal getMass() const;
virtual PxReal getInvMass() const;
virtual void setMassSpaceInertiaTensor(const PxVec3& m);
virtual PxVec3 getMassSpaceInertiaTensor() const;
virtual PxVec3 getMassSpaceInvInertiaTensor() const;
// Velocity
virtual PxVec3 getLinearVelocity() const;
virtual PxVec3 getAngularVelocity() const;
virtual bool attachShape(PxShape& shape);
//---------------------------------------------------------------------------------
// Miscellaneous
//---------------------------------------------------------------------------------
NpRigidBodyTemplate(PxType concreteType, PxBaseFlags baseFlags, const PxActorType::Enum type, const PxTransform& bodyPose);
PX_FORCE_INLINE const Scb::Body& getScbBodyFast() const { return mBody; } // PT: important: keep returning an address here (else update prefetch in SceneQueryManager::addShapes)
PX_FORCE_INLINE Scb::Body& getScbBodyFast() { return mBody; } // PT: important: keep returning an address here (else update prefetch in SceneQueryManager::addShapes)
PX_FORCE_INLINE Scb::Actor& getScbActorFast() { return mBody; }
PX_FORCE_INLINE const Scb::Actor& getScbActorFast() const { return mBody; }
// Flags
virtual void setRigidBodyFlag(PxRigidBodyFlag::Enum, bool value);
virtual void setRigidBodyFlags(PxRigidBodyFlags inFlags);
PX_FORCE_INLINE PxRigidBodyFlags getRigidBodyFlagsFast() const
{
return getScbBodyFast().getFlags();
}
virtual PxRigidBodyFlags getRigidBodyFlags() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return getRigidBodyFlagsFast();
}
virtual void setMinCCDAdvanceCoefficient(PxReal advanceCoefficient);
virtual PxReal getMinCCDAdvanceCoefficient() const;
virtual void setMaxDepenetrationVelocity(PxReal maxDepenVel);
virtual PxReal getMaxDepenetrationVelocity() const;
virtual void setMaxContactImpulse(PxReal maxDepenVel);
virtual PxReal getMaxContactImpulse() const;
virtual PxU32 getInternalIslandNodeIndex() const;
protected:
void setCMassLocalPoseInternal(const PxTransform&);
void addSpatialForce(const PxVec3* force, const PxVec3* torque, PxForceMode::Enum mode);
void clearSpatialForce(PxForceMode::Enum mode, bool force, bool torque);
void setSpatialForce(const PxVec3* force, const PxVec3* torque, PxForceMode::Enum mode);
PX_INLINE void updateBody2Actor(const PxTransform& newBody2Actor);
PX_FORCE_INLINE void setRigidBodyFlagsInternal(const PxRigidBodyFlags& currentFlags, const PxRigidBodyFlags& newFlags);
#if PX_ENABLE_DEBUG_VISUALIZATION
public:
void visualize(Cm::RenderOutput& out, NpScene* scene);
#endif
PX_FORCE_INLINE bool isKinematic() const
{
return (APIClass::getConcreteType() == PxConcreteType::eRIGID_DYNAMIC) && (getScbBodyFast().getFlags() & PxRigidBodyFlag::eKINEMATIC);
}
protected:
Scb::Body mBody;
};
template<class APIClass>
NpRigidBodyTemplate<APIClass>::NpRigidBodyTemplate(PxType concreteType, PxBaseFlags baseFlags, PxActorType::Enum type, const PxTransform& bodyPose)
: RigidActorTemplateClass(concreteType, baseFlags)
, mBody(type, bodyPose)
{
}
template<class APIClass>
NpRigidBodyTemplate<APIClass>::~NpRigidBodyTemplate()
{
}
namespace
{
PX_FORCE_INLINE static bool isSimGeom(PxGeometryType::Enum t)
{
return t != PxGeometryType::eTRIANGLEMESH && t != PxGeometryType::ePLANE && t != PxGeometryType::eHEIGHTFIELD;
}
}
template<class APIClass>
bool NpRigidBodyTemplate<APIClass>::attachShape(PxShape& shape)
{
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
PX_CHECK_AND_RETURN_VAL(!(shape.getFlags() & PxShapeFlag::eSIMULATION_SHAPE)
|| isSimGeom(shape.getGeometryType())
|| isKinematic(),
"attachShape: Triangle mesh, heightfield or plane geometry shapes configured as eSIMULATION_SHAPE are not supported for non-kinematic PxRigidDynamic instances.", false);
return RigidActorTemplateClass::attachShape(shape);
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setCMassLocalPoseInternal(const PxTransform& body2Actor)
{
//the point here is to change the mass distribution w/o changing the actors' pose in the world
PxTransform newBody2World = getGlobalPose() * body2Actor;
mBody.setBody2World(newBody2World, true);
mBody.setBody2Actor(body2Actor);
RigidActorTemplateClass::updateShaderComs();
}
template<class APIClass>
PxTransform NpRigidBodyTemplate<APIClass>::getCMassLocalPose() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return getScbBodyFast().getBody2Actor();
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setMass(PxReal mass)
{
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
PX_CHECK_AND_RETURN(PxIsFinite(mass), "PxRigidDynamic::setMass: invalid float");
PX_CHECK_AND_RETURN(mass>=0, "PxRigidDynamic::setMass: mass must be non-negative!");
PX_CHECK_AND_RETURN(this->getType() != PxActorType::eARTICULATION_LINK || mass > 0.0f, "PxRigidDynamic::setMassSpaceInertiaTensor: components must be > 0 for articualtions");
getScbBodyFast().setInverseMass(mass > 0.0f ? 1.0f/mass : 0.0f);
}
template<class APIClass>
PxReal NpRigidBodyTemplate<APIClass>::getMass() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
const PxReal invMass = mBody.getInverseMass();
return invMass > 0.0f ? 1.0f/invMass : 0.0f;
}
template<class APIClass>
PxReal NpRigidBodyTemplate<APIClass>::getInvMass() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getInverseMass();
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setMassSpaceInertiaTensor(const PxVec3& m)
{
PX_CHECK_AND_RETURN(m.isFinite(), "PxRigidDynamic::setMassSpaceInertiaTensor: invalid inertia");
PX_CHECK_AND_RETURN(m.x>=0.0f && m.y>=0.0f && m.z>=0.0f, "PxRigidDynamic::setMassSpaceInertiaTensor: components must be non-negative");
PX_CHECK_AND_RETURN(this->getType() != PxActorType::eARTICULATION_LINK || (m.x > 0.0f && m.y > 0.0f && m.z > 0.0f), "PxRigidDynamic::setMassSpaceInertiaTensor: components must be > 0 for articualtions");
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
mBody.setInverseInertia(invertDiagInertia(m));
}
template<class APIClass>
PxVec3 NpRigidBodyTemplate<APIClass>::getMassSpaceInertiaTensor() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return invertDiagInertia(mBody.getInverseInertia());
}
template<class APIClass>
PxVec3 NpRigidBodyTemplate<APIClass>::getMassSpaceInvInertiaTensor() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getInverseInertia();
}
template<class APIClass>
PxVec3 NpRigidBodyTemplate<APIClass>::getLinearVelocity() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getLinearVelocity();
}
template<class APIClass>
PxVec3 NpRigidBodyTemplate<APIClass>::getAngularVelocity() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getAngularVelocity();
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::addSpatialForce(const PxVec3* force, const PxVec3* torque, PxForceMode::Enum mode)
{
PX_ASSERT(!(mBody.getFlags() & PxRigidBodyFlag::eKINEMATIC));
switch (mode)
{
case PxForceMode::eFORCE:
{
PxVec3 linAcc, angAcc;
if (force)
{
linAcc = (*force) * mBody.getInverseMass();
force = &linAcc;
}
if (torque)
{
angAcc = mBody.getGlobalInertiaTensorInverse() * (*torque);
torque = &angAcc;
}
mBody.addSpatialAcceleration(force, torque);
}
break;
case PxForceMode::eACCELERATION:
mBody.addSpatialAcceleration(force, torque);
break;
case PxForceMode::eIMPULSE:
{
PxVec3 linVelDelta, angVelDelta;
if (force)
{
linVelDelta = ((*force) * mBody.getInverseMass());
force = &linVelDelta;
}
if (torque)
{
angVelDelta = (mBody.getGlobalInertiaTensorInverse() * (*torque));
torque = &angVelDelta;
}
mBody.addSpatialVelocity(force, torque);
}
break;
case PxForceMode::eVELOCITY_CHANGE:
mBody.addSpatialVelocity(force, torque);
break;
}
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setSpatialForce(const PxVec3* force, const PxVec3* torque, PxForceMode::Enum mode)
{
PX_ASSERT(!(mBody.getFlags() & PxRigidBodyFlag::eKINEMATIC));
switch (mode)
{
case PxForceMode::eFORCE:
{
PxVec3 linAcc, angAcc;
if (force)
{
linAcc = (*force) * mBody.getInverseMass();
force = &linAcc;
}
if (torque)
{
angAcc = mBody.getGlobalInertiaTensorInverse() * (*torque);
torque = &angAcc;
}
mBody.setSpatialAcceleration(force, torque);
}
break;
case PxForceMode::eACCELERATION:
mBody.setSpatialAcceleration(force, torque);
break;
case PxForceMode::eIMPULSE:
{
PxVec3 linVelDelta, angVelDelta;
if (force)
{
linVelDelta = ((*force) * mBody.getInverseMass());
force = &linVelDelta;
}
if (torque)
{
angVelDelta = (mBody.getGlobalInertiaTensorInverse() * (*torque));
torque = &angVelDelta;
}
mBody.addSpatialVelocity(force, torque);
}
break;
case PxForceMode::eVELOCITY_CHANGE:
mBody.addSpatialVelocity(force, torque);
break;
}
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::clearSpatialForce(PxForceMode::Enum mode, bool force, bool torque)
{
PX_ASSERT(!(mBody.getFlags() & PxRigidBodyFlag::eKINEMATIC));
switch (mode)
{
case PxForceMode::eFORCE:
case PxForceMode::eACCELERATION:
mBody.clearSpatialAcceleration(force, torque);
break;
case PxForceMode::eIMPULSE:
case PxForceMode::eVELOCITY_CHANGE:
mBody.clearSpatialVelocity(force, torque);
break;
}
}
#if PX_ENABLE_DEBUG_VISUALIZATION
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::visualize(Cm::RenderOutput& out, NpScene* scene)
{
RigidActorTemplateClass::visualize(out, scene);
if (mBody.getActorFlags() & PxActorFlag::eVISUALIZATION)
{
Scb::Scene& scbScene = scene->getScene();
const PxReal scale = scbScene.getVisualizationParameter(PxVisualizationParameter::eSCALE);
//visualize actor frames
const PxReal actorAxes = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eACTOR_AXES);
if (actorAxes != 0.0f)
out << getGlobalPose() << Cm::DebugBasis(PxVec3(actorAxes));
const PxReal bodyAxes = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eBODY_AXES);
if (bodyAxes != 0.0f)
out << mBody.getBody2World() << Cm::DebugBasis(PxVec3(bodyAxes));
const PxReal linVelocity = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eBODY_LIN_VELOCITY);
if (linVelocity != 0.0f)
{
out << 0xffffff << PxMat44(PxIdentity) << Cm::DebugArrow(mBody.getBody2World().p,
mBody.getLinearVelocity() * linVelocity, 0.2f * linVelocity);
}
const PxReal angVelocity = scale * scbScene.getVisualizationParameter(PxVisualizationParameter::eBODY_ANG_VELOCITY);
if (angVelocity != 0.0f)
{
out << 0x000000 << PxMat44(PxIdentity) << Cm::DebugArrow(mBody.getBody2World().p,
mBody.getAngularVelocity() * angVelocity, 0.2f * angVelocity);
}
}
}
#endif
PX_FORCE_INLINE void updateDynamicSceneQueryShapes(NpShapeManager& shapeManager, Sq::SceneQueryManager& sqManager, const PxRigidActor& actor)
{
shapeManager.markAllSceneQueryForUpdate(sqManager, actor);
sqManager.get(Sq::PruningIndex::eDYNAMIC).invalidateTimestamp();
}
template<class APIClass>
PX_FORCE_INLINE void NpRigidBodyTemplate<APIClass>::setRigidBodyFlagsInternal(const PxRigidBodyFlags& currentFlags, const PxRigidBodyFlags& newFlags)
{
PxRigidBodyFlags filteredNewFlags = newFlags;
//Test to ensure we are not enabling both CCD and kinematic state on a body. This is unsupported
if((filteredNewFlags & PxRigidBodyFlag::eENABLE_CCD) && (filteredNewFlags & PxRigidBodyFlag::eKINEMATIC))
{
physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
"RigidBody::setRigidBodyFlag: kinematic bodies with CCD enabled are not supported! CCD will be ignored.");
filteredNewFlags &= PxRigidBodyFlags(~PxRigidBodyFlag::eENABLE_CCD);
}
if ((filteredNewFlags & PxRigidBodyFlag::eENABLE_CCD) && (filteredNewFlags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD))
{
physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__,
"RigidBody::setRigidBodyFlag: eENABLE_CCD can't be raised as the same time as eENABLE_SPECULATIVE_CCD! eENABLE_SPECULATIVE_CCD will be ignored.");
filteredNewFlags &= PxRigidBodyFlags(~PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD);
}
Scb::Body& body = getScbBodyFast();
NpScene* scene = NpActor::getAPIScene(*this);
Sc::Scene* scScene = scene ? &scene->getScene().getScScene() : NULL;
const bool isKinematic = currentFlags & PxRigidBodyFlag::eKINEMATIC;
const bool willBeKinematic = filteredNewFlags & PxRigidBodyFlag::eKINEMATIC;
const bool kinematicSwitchingToDynamic = isKinematic && (!willBeKinematic);
const bool dynamicSwitchingToKinematic = (!isKinematic) && willBeKinematic;
if(kinematicSwitchingToDynamic)
{
NpShapeManager& shapeManager = this->getShapeManager();
PxU32 nbShapes = shapeManager.getNbShapes();
NpShape*const* shapes = shapeManager.getShapes();
bool hasTriangleMesh = false;
for(PxU32 i=0;i<nbShapes;i++)
{
if((shapes[i]->getFlags() & PxShapeFlag::eSIMULATION_SHAPE) && (shapes[i]->getGeometryTypeFast()==PxGeometryType::eTRIANGLEMESH || shapes[i]->getGeometryTypeFast()==PxGeometryType::ePLANE || shapes[i]->getGeometryTypeFast()==PxGeometryType::eHEIGHTFIELD))
{
hasTriangleMesh = true;
break;
}
}
if(hasTriangleMesh)
{
physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "RigidBody::setRigidBodyFlag: dynamic meshes/planes/heightfields are not supported!");
return;
}
PxTransform bodyTarget;
if ((currentFlags & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES) && body.getKinematicTarget(bodyTarget) && scene)
{
updateDynamicSceneQueryShapes(shapeManager, scene->getSceneQueryManagerFast(), *this);
}
if(scScene)
{
scScene->decreaseNumKinematicsCounter();
scScene->increaseNumDynamicsCounter();
}
body.clearSimStateDataForPendingInsert();
}
else if (dynamicSwitchingToKinematic)
{
if (this->getType() != PxActorType::eARTICULATION_LINK)
{
body.transitionSimStateDataForPendingInsert();
}
else
{
//We're an articulation, raise an issue
physx::shdfnd::getFoundation().error(physx::PxErrorCode::eINVALID_PARAMETER, __FILE__, __LINE__, "RigidBody::setRigidBodyFlag: kinematic articulation links are not supported!");
return;
}
if(scScene)
{
scScene->decreaseNumDynamicsCounter();
scScene->increaseNumKinematicsCounter();
}
}
const bool kinematicSwitchingUseTargetForSceneQuery = isKinematic && willBeKinematic &&
((currentFlags & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES) != (filteredNewFlags & PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES));
if (kinematicSwitchingUseTargetForSceneQuery)
{
PxTransform bodyTarget;
if (body.getKinematicTarget(bodyTarget) && scene)
{
updateDynamicSceneQueryShapes(this->getShapeManager(), scene->getSceneQueryManagerFast(), *this);
}
}
body.setFlags(filteredNewFlags);
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setRigidBodyFlag(PxRigidBodyFlag::Enum flag, bool value)
{
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
Scb::Body& body = getScbBodyFast();
const PxRigidBodyFlags currentFlags = body.getFlags();
const PxRigidBodyFlags newFlags = value ? currentFlags | flag : currentFlags & (~PxRigidBodyFlags(flag));
setRigidBodyFlagsInternal(currentFlags, newFlags);
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setRigidBodyFlags(PxRigidBodyFlags inFlags)
{
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
Scb::Body& body = getScbBodyFast();
const PxRigidBodyFlags currentFlags = body.getFlags();
setRigidBodyFlagsInternal(currentFlags, inFlags);
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setMinCCDAdvanceCoefficient(PxReal minCCDAdvanceCoefficient)
{
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
mBody.setMinCCDAdvanceCoefficient(minCCDAdvanceCoefficient);
}
template<class APIClass>
PxReal NpRigidBodyTemplate<APIClass>::getMinCCDAdvanceCoefficient() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getMinCCDAdvanceCoefficient();
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setMaxDepenetrationVelocity(PxReal maxDepenVel)
{
PX_CHECK_AND_RETURN(maxDepenVel > 0.0f, "PxRigidDynamic::setMaxDepenetrationVelocity: maxDepenVel must be greater than zero.");
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
mBody.setMaxPenetrationBias(-maxDepenVel);
}
template<class APIClass>
PxReal NpRigidBodyTemplate<APIClass>::getMaxDepenetrationVelocity() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return -mBody.getMaxPenetrationBias();
}
template<class APIClass>
void NpRigidBodyTemplate<APIClass>::setMaxContactImpulse(const PxReal maxImpulse)
{
PX_CHECK_AND_RETURN(maxImpulse >= 0.f, "NpRigidBody::setMaxImpulse: impulse limit must be greater than or equal to zero.");
NP_WRITE_CHECK(NpActor::getOwnerScene(*this));
mBody.setMaxContactImpulse(maxImpulse);
}
template<class APIClass>
PxReal NpRigidBodyTemplate<APIClass>::getMaxContactImpulse() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getMaxContactImpulse();
}
template<class APIClass>
PxU32 NpRigidBodyTemplate<APIClass>::getInternalIslandNodeIndex() const
{
NP_READ_CHECK(NpActor::getOwnerScene(*this));
return mBody.getInternalIslandNodeIndex();
}
}
#endif