276 lines
13 KiB
C++
276 lines
13 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-2025 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 SC_BODYSIM_H
|
|
#define SC_BODYSIM_H
|
|
|
|
#include "foundation/PxUtilities.h"
|
|
#include "foundation/PxIntrinsics.h"
|
|
#include "ScRigidSim.h"
|
|
#include "PxvDynamics.h"
|
|
#include "ScBodyCore.h"
|
|
#include "ScSimStateData.h"
|
|
#include "PxRigidDynamic.h"
|
|
#include "PxsRigidBody.h"
|
|
|
|
namespace physx
|
|
{
|
|
namespace Bp
|
|
{
|
|
class BoundsArray;
|
|
}
|
|
struct PxsExternalAccelerationProvider;
|
|
class PxsTransformCache;
|
|
namespace Sc
|
|
{
|
|
class Scene;
|
|
class ArticulationSim;
|
|
|
|
#if PX_VC
|
|
#pragma warning(push)
|
|
#pragma warning( disable : 4324 ) // Padding was added at the end of a structure because of a __declspec(align) value.
|
|
#endif
|
|
|
|
class BodySim : public RigidSim
|
|
{
|
|
public:
|
|
BodySim(Scene&, BodyCore&, bool);
|
|
virtual ~BodySim();
|
|
|
|
void switchToKinematic();
|
|
void switchToDynamic();
|
|
|
|
PX_FORCE_INLINE const SimStateData* getSimStateData(bool isKinematic) const { return (mSimStateData && (checkSimStateKinematicStatus(isKinematic)) ? mSimStateData : NULL); }
|
|
PX_FORCE_INLINE SimStateData* getSimStateData(bool isKinematic) { return (mSimStateData && (checkSimStateKinematicStatus(isKinematic)) ? mSimStateData : NULL); }
|
|
PX_FORCE_INLINE SimStateData* getSimStateData_Unchecked() const { return mSimStateData; }
|
|
PX_FORCE_INLINE bool checkSimStateKinematicStatus(bool isKinematic) const
|
|
{
|
|
PX_ASSERT(mSimStateData);
|
|
return mSimStateData->isKine() == isKinematic;
|
|
}
|
|
|
|
void setKinematicTarget(const PxTransform& p);
|
|
|
|
void addSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc);
|
|
void setSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc);
|
|
void clearSpatialAcceleration(bool force, bool torque);
|
|
void addSpatialVelocity(const PxVec3* linVelDelta, const PxVec3* angVelDelta);
|
|
void clearSpatialVelocity(bool force, bool torque);
|
|
|
|
void updateCached(PxBitMapPinned* shapeChangedMap);
|
|
void updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray);
|
|
void updateContactDistance(PxReal* contactDistance, PxReal dt, const Bp::BoundsArray& boundsArray);
|
|
|
|
// hooks for actions in body core when it's attached to a sim object. Generally
|
|
// we get called after the attribute changed.
|
|
|
|
virtual void postActorFlagChange(PxU32 oldFlags, PxU32 newFlags) PX_OVERRIDE;
|
|
void postBody2WorldChange();
|
|
void postSetWakeCounter(PxReal t, bool forceWakeUp);
|
|
void postPosePreviewChange(PxU32 posePreviewFlag); // called when PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW changes
|
|
|
|
PX_FORCE_INLINE const PxTransform& getBody2World() const { return getBodyCore().getCore().body2World; }
|
|
PX_FORCE_INLINE const PxTransform& getBody2Actor() const { return getBodyCore().getCore().getBody2Actor(); }
|
|
PX_FORCE_INLINE const PxsRigidBody& getLowLevelBody() const { return mLLBody; }
|
|
PX_FORCE_INLINE PxsRigidBody& getLowLevelBody() { return mLLBody; }
|
|
|
|
void setActive(bool active, bool asPartOfCreation=false);
|
|
void wakeUp(); // note: for user API call purposes only, i.e., use from BodyCore. For simulation internal purposes there is internalWakeUp().
|
|
void putToSleep();
|
|
|
|
void disableCompound();
|
|
|
|
static PxU32 getRigidBodyOffset() { return PxU32(PX_OFFSET_OF_RT(BodySim, mLLBody));}
|
|
|
|
void activate();
|
|
void deactivate();
|
|
|
|
// Kinematics
|
|
PX_FORCE_INLINE bool isKinematic() const { return getBodyCore().getFlags() & PxRigidBodyFlag::eKINEMATIC; }
|
|
PX_FORCE_INLINE bool isArticulationLink() const { return getActorType() == PxActorType::eARTICULATION_LINK; }
|
|
PX_FORCE_INLINE bool hasForcedKinematicNotif() const
|
|
{
|
|
return getBodyCore().getFlags() & (PxRigidBodyFlag::eFORCE_KINE_KINE_NOTIFICATIONS|PxRigidBodyFlag::eFORCE_STATIC_KINE_NOTIFICATIONS);
|
|
}
|
|
void calculateKinematicVelocity(PxReal oneOverDt);
|
|
void updateKinematicPose();
|
|
bool deactivateKinematic();
|
|
// Sleeping
|
|
virtual void internalWakeUp(PxReal wakeCounterValue) PX_OVERRIDE; // PT: TODO: does it need to be virtual?
|
|
void internalWakeUpArticulationLink(PxReal wakeCounterValue); // called by ArticulationSim to wake up this link
|
|
|
|
PxReal updateWakeCounter(PxReal dt, PxReal energyThreshold, const Cm::SpatialVector& motionVelocity);
|
|
|
|
void notifyReadyForSleeping(); // inform the sleep island generation system that the body is ready for sleeping
|
|
void notifyNotReadyForSleeping(); // inform the sleep island generation system that the body is not ready for sleeping
|
|
PX_FORCE_INLINE bool checkSleepReadinessBesidesWakeCounter(); // for API triggered changes to test sleep readiness
|
|
|
|
// PT: TODO: this is only used for the rigid bodies' sleep check, the implementations in derived classes look useless
|
|
virtual void registerCountedInteraction() PX_OVERRIDE { mLLBody.getCore().numCountedInteractions++; PX_ASSERT(mLLBody.getCore().numCountedInteractions); }
|
|
virtual void unregisterCountedInteraction() PX_OVERRIDE { PX_ASSERT(mLLBody.getCore().numCountedInteractions); mLLBody.getCore().numCountedInteractions--; }
|
|
// PT: TODO: this is only used for the rigid bodies' sleep check called from the articulation sim code
|
|
virtual PxU32 getNumCountedInteractions() const PX_OVERRIDE { return mLLBody.getCore().numCountedInteractions; }
|
|
|
|
PX_FORCE_INLINE PxIntBool isFrozen() const { return PxIntBool(mLLBody.mInternalFlags & PxsRigidBody::eFROZEN); }
|
|
|
|
// External velocity changes - returns true if any forces were applied to this body
|
|
bool updateForces(PxReal dt, PxsRigidBody** updatedBodySims, PxU32* updatedBodyNodeIndices, PxU32& index, Cm::SpatialVector* acceleration,
|
|
PxsExternalAccelerationProvider* externalAccelerations = NULL, PxU32 maxNumExternalAccelerations = 0);
|
|
|
|
PX_FORCE_INLINE bool readVelocityModFlag(VelocityModFlags f) { return (mVelModState & f) != 0; }
|
|
|
|
// Miscellaneous
|
|
PX_FORCE_INLINE bool notInScene() const { return mActiveListIndex == SC_NOT_IN_SCENE_INDEX; }
|
|
PX_FORCE_INLINE PxU32 getNbShapes() const { return mShapes.getCount(); }
|
|
PX_FORCE_INLINE PxU32 getFlagsFast() const { return getBodyCore().getFlags(); }
|
|
PX_FORCE_INLINE BodyCore& getBodyCore() const { return static_cast<BodyCore&>(getRigidCore()); }
|
|
|
|
PX_FORCE_INLINE ArticulationSim* getArticulation() const { return mArticulation; }
|
|
void setArticulation(ArticulationSim* a, PxReal wakeCounter, bool asleep, PxU32 bodyIndex);
|
|
|
|
PX_FORCE_INLINE void onConstraintAttach() { raiseInternalFlag(BF_HAS_CONSTRAINTS); registerCountedInteraction(); }
|
|
void onConstraintDetach();
|
|
|
|
PX_FORCE_INLINE void onOriginShift(const PxVec3& shift, const bool isKinematic)
|
|
{
|
|
PX_ASSERT(!mSimStateData || checkSimStateKinematicStatus(isKinematic));
|
|
mLLBody.mLastTransform.p -= shift;
|
|
if (mSimStateData && isKinematic && mSimStateData->getKinematicData()->targetValid)
|
|
mSimStateData->getKinematicData()->targetPose.p -= shift;
|
|
}
|
|
|
|
PX_FORCE_INLINE bool usingSqKinematicTarget() const
|
|
{
|
|
const PxU32 ktFlags(PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES | PxRigidBodyFlag::eKINEMATIC);
|
|
return (getFlagsFast()&ktFlags) == ktFlags;
|
|
}
|
|
|
|
void createSqBounds();
|
|
void destroySqBounds();
|
|
void freezeTransforms(PxBitMapPinned* shapeChangedMap);
|
|
|
|
void addToSpeculativeCCDMap();
|
|
void removeFromSpeculativeCCDMap();
|
|
private:
|
|
// Base body
|
|
PxsRigidBody mLLBody;
|
|
|
|
// External velocity changes
|
|
// VelocityMod data allocated on the fly when the user applies velocity changes
|
|
// which need to be accumulated.
|
|
// VelMod dirty flags stored in BodySim so we can save ourselves the expense of looking at
|
|
// the separate velmod data if no forces have been set.
|
|
//PxU16 mInternalFlags;
|
|
SimStateData* mSimStateData;
|
|
PxU8 mVelModState;
|
|
|
|
// Articulation
|
|
ArticulationSim* mArticulation; // NULL if not in an articulation
|
|
|
|
// Joints & joint groups
|
|
|
|
bool setupSimStateData(bool isKinematic);
|
|
void tearDownSimStateData(bool isKinematic);
|
|
|
|
void raiseVelocityModFlagAndNotify(VelocityModFlags flag);
|
|
PX_FORCE_INLINE void notifyDirtySpatialAcceleration() { raiseVelocityModFlagAndNotify(VMF_ACC_DIRTY); }
|
|
PX_FORCE_INLINE void notifyDirtySpatialVelocity() { raiseVelocityModFlagAndNotify(VMF_VEL_DIRTY); }
|
|
|
|
PX_FORCE_INLINE void initKinematicStateBase(BodyCore&, bool asPartOfCreation);
|
|
|
|
void notifyWakeUp(); // inform the sleep island generation system that the object got woken up
|
|
void notifyPutToSleep(); // inform the sleep island generation system that the object was put to sleep
|
|
void internalWakeUpBase(PxReal wakeCounterValue);
|
|
|
|
PX_FORCE_INLINE void raiseVelocityModFlag(VelocityModFlags f) { mVelModState |= f; }
|
|
PX_FORCE_INLINE void clearVelocityModFlag(VelocityModFlags f) { mVelModState &= ~f; }
|
|
PX_FORCE_INLINE void setForcesToDefaults(bool enableGravity);
|
|
};
|
|
|
|
#if PX_VC
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
} // namespace Sc
|
|
|
|
PX_FORCE_INLINE void Sc::BodySim::setForcesToDefaults(bool enableGravity)
|
|
{
|
|
if (!(mLLBody.mCore->mFlags & PxRigidBodyFlag::eRETAIN_ACCELERATIONS))
|
|
{
|
|
SimStateData* simStateData = getSimStateData(false);
|
|
if(simStateData)
|
|
{
|
|
VelocityMod* velmod = simStateData->getVelocityModData();
|
|
velmod->clear();
|
|
}
|
|
|
|
if (enableGravity)
|
|
mVelModState = VMF_GRAVITY_DIRTY; // We want to keep the gravity flag to make sure the acceleration gets changed to gravity-only
|
|
// in the next step (unless the application adds new forces of course)
|
|
else
|
|
mVelModState = 0;
|
|
}
|
|
else
|
|
{
|
|
SimStateData* simStateData = getSimStateData(false);
|
|
if (simStateData)
|
|
{
|
|
VelocityMod* velmod = simStateData->getVelocityModData();
|
|
velmod->clearPerStep();
|
|
}
|
|
|
|
mVelModState &= (~(VMF_VEL_DIRTY));
|
|
}
|
|
}
|
|
|
|
PX_FORCE_INLINE bool Sc::BodySim::checkSleepReadinessBesidesWakeCounter()
|
|
{
|
|
const BodyCore& bodyCore = getBodyCore();
|
|
const SimStateData* simStateData = getSimStateData(false);
|
|
const VelocityMod* velmod = simStateData ? simStateData->getVelocityModData() : NULL;
|
|
|
|
bool readyForSleep = bodyCore.getLinearVelocity().isZero() && bodyCore.getAngularVelocity().isZero();
|
|
if (readVelocityModFlag(VMF_ACC_DIRTY))
|
|
{
|
|
readyForSleep = readyForSleep && (!velmod || velmod->getLinearVelModPerSec().isZero());
|
|
readyForSleep = readyForSleep && (!velmod || velmod->getAngularVelModPerSec().isZero());
|
|
}
|
|
if (readVelocityModFlag(VMF_VEL_DIRTY))
|
|
{
|
|
readyForSleep = readyForSleep && (!velmod || velmod->getLinearVelModPerStep().isZero());
|
|
readyForSleep = readyForSleep && (!velmod || velmod->getAngularVelModPerStep().isZero());
|
|
}
|
|
|
|
return readyForSleep;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
#endif
|