feat(physics): wire physx sdk into build

This commit is contained in:
2026-04-15 12:22:15 +08:00
parent 5bf258df6d
commit 31f40e2cbb
2044 changed files with 752623 additions and 1 deletions

View File

@@ -0,0 +1,137 @@
// 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_ACTOR_CORE_H
#define SC_ACTOR_CORE_H
#include "foundation/PxBitAndData.h"
#include "PxActor.h"
#define SC_FILTERING_ID_SHIFT_BIT 24
#define SC_FILTERING_ID_MAX (1<<SC_FILTERING_ID_SHIFT_BIT)
#define SC_FILTERING_ID_MASK 0x00ffffff
namespace physx
{
namespace Sc
{
class ActorSim;
class ActorCore
{
public:
// PX_SERIALIZATION
ActorCore(const PxEMPTY) : mSim(NULL), mActorFlags(PxEmpty)
{
}
//~PX_SERIALIZATION
ActorCore(PxActorType::Enum actorType, PxU8 actorFlags, PxClientID owner, PxDominanceGroup dominanceGroup);
~ActorCore();
PX_FORCE_INLINE ActorSim* getSim() const { return mSim; }
PX_FORCE_INLINE void setSim(ActorSim* sim)
{
PX_ASSERT((sim==NULL) ^ (mSim==NULL));
mSim = sim;
}
PX_FORCE_INLINE PxActorFlags getActorFlags() const { return mActorFlags; }
void setActorFlags(PxActorFlags af);
PX_FORCE_INLINE PxDominanceGroup getDominanceGroup() const
{
return PxDominanceGroup(mDominanceGroup);
}
void setDominanceGroup(PxDominanceGroup g);
PX_FORCE_INLINE void setOwnerClient(PxClientID inId)
{
const PxU32 id = mPackedIDs & SC_FILTERING_ID_MASK;
mPackedIDs = (PxU32(inId)<<SC_FILTERING_ID_SHIFT_BIT) | id;
}
PX_FORCE_INLINE PxClientID getOwnerClient() const
{
return mPackedIDs>>SC_FILTERING_ID_SHIFT_BIT;
}
PX_FORCE_INLINE PxActorType::Enum getActorCoreType() const { return PxActorType::Enum(mActorType); }
void reinsertShapes();
void setAggregateID(PxU32 id);
PX_FORCE_INLINE PxU8 hasAggregateID() const { return mDominanceGroup.isBitSet(); }
PX_FORCE_INLINE PxU32 getAggregateID() const
{
if(!hasAggregateID())
return PX_INVALID_U32;
return mPackedIDs & SC_FILTERING_ID_MASK;
}
void setEnvID(PxU32 id);
PX_FORCE_INLINE PxU32 getEnvID() const
{
if(hasAggregateID())
return PX_INVALID_U32;
const PxU32 id = mPackedIDs & SC_FILTERING_ID_MASK;
return id == SC_FILTERING_ID_MASK ? PX_INVALID_U32 : id;
}
private:
ActorSim* mSim;
PxU32 mPackedIDs; // PxClientID (8bit) | aggregate / env ID (24bit)
// PT: TODO: the remaining members could be packed into just a 16bit mask
PxActorFlags mActorFlags; // PxActor's flags (PxU8) => only 4 bits used
PxU8 mActorType; // Actor type (8 bits, but 3 would be enough)
PxBitAndByte mDominanceGroup; // Aggregate bit | dominance group (7 bits, but 5 would be enough because "must be < 32")
PX_FORCE_INLINE void setID(PxU32 id)
{
const PxU32 ownerClient = mPackedIDs & (~SC_FILTERING_ID_MASK);
mPackedIDs = (id & SC_FILTERING_ID_MASK) | ownerClient;
}
PX_FORCE_INLINE void resetID()
{
mPackedIDs |= SC_FILTERING_ID_MASK;
}
};
#if PX_P64_FAMILY
PX_COMPILE_TIME_ASSERT(sizeof(Sc::ActorCore)==16);
#else
PX_COMPILE_TIME_ASSERT(sizeof(Sc::ActorCore)==12);
#endif
} // namespace Sc
}
//////////////////////////////////////////////////////////////////////////
#endif

View File

@@ -0,0 +1,67 @@
// 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_ATTACHMENT_CORE_H
#define SC_ATTACHMENT_CORE_H
#include "foundation/PxVec3.h"
namespace physx
{
namespace Sc
{
class ArticulationAttachmentCore
{
public:
// PX_SERIALIZATION
ArticulationAttachmentCore(const PxEMPTY) : mTendonSim(NULL) {}
void preExportDataReset() { }
//~PX_SERIALIZATION
ArticulationAttachmentCore() : mLowLimit(PX_MAX_F32), mHighLimit(-PX_MAX_F32), mRestLength(0.f)
{
}
PxVec3 mRelativeOffset; //relative offset to the link(in link space)
ArticulationAttachmentCore* mParent;
PxReal mLowLimit;
PxReal mHighLimit;
PxReal mRestLength;
PxReal mCoefficient;
PxU32 mLLLinkIndex;
PxU32 mAttachmentIndex;
Sc::ArticulationSpatialTendonSim* mTendonSim;
};
}//namespace Sc
}//namespace physx
#endif

View File

@@ -0,0 +1,162 @@
// 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_ARTICULATION_CORE_H
#define SC_ARTICULATION_CORE_H
#include "ScActorCore.h"
#include "DyFeatherstoneArticulation.h"
namespace physx
{
class PxNodeIndex;
namespace Sc
{
class ArticulationSim;
class ArticulationCore
{
//---------------------------------------------------------------------------------
// Construction, destruction & initialization
//---------------------------------------------------------------------------------
// PX_SERIALIZATION
public:
ArticulationCore(const PxEMPTY) : mSim(NULL), mCore(PxEmpty) {}
//~PX_SERIALIZATION
ArticulationCore();
~ArticulationCore();
//---------------------------------------------------------------------------------
// External API
//---------------------------------------------------------------------------------
PX_FORCE_INLINE PxReal getSleepThreshold() const { return mCore.sleepThreshold; }
PX_FORCE_INLINE void setSleepThreshold(const PxReal v) { mCore.sleepThreshold = v; }
PX_FORCE_INLINE PxReal getFreezeThreshold() const { return mCore.freezeThreshold; }
PX_FORCE_INLINE void setFreezeThreshold(const PxReal v) { mCore.freezeThreshold = v; }
PX_FORCE_INLINE PxU16 getSolverIterationCounts() const { return mCore.solverIterationCounts; }
PX_FORCE_INLINE void setSolverIterationCounts(PxU16 c) { mCore.solverIterationCounts = c; }
PX_FORCE_INLINE PxReal getWakeCounter() const { return mCore.wakeCounter; }
PX_FORCE_INLINE void setWakeCounterInternal(const PxReal v) { mCore.wakeCounter = v; }
void setWakeCounter(const PxReal v);
bool isSleeping() const;
void wakeUp(PxReal wakeCounter);
void putToSleep();
//---------------------------------------------------------------------------------
// external reduced coordinate API
//---------------------------------------------------------------------------------
void setArticulationFlags(PxArticulationFlags flags);
PxArticulationFlags getArticulationFlags() const { return mCore.flags; }
PxU32 getDofs() const;
PxArticulationCache* createCache() const;
PxU32 getCacheDataSize() const;
void zeroCache(PxArticulationCache& cache) const;
bool applyCache(PxArticulationCache& cache, const PxArticulationCacheFlags flag)const;
void copyInternalStateToCache
(PxArticulationCache& cache, const PxArticulationCacheFlags flag, const bool isGpuSimEnabled) const;
void packJointData(const PxReal* maximum, PxReal* reduced) const;
void unpackJointData(const PxReal* reduced, PxReal* maximum) const;
void commonInit() const;
void computeGeneralizedGravityForce(PxArticulationCache& cache, const bool rootMotion) const;
void computeCoriolisAndCentrifugalForce(PxArticulationCache& cache, const bool rootMotion) const;
void computeGeneralizedExternalForce(PxArticulationCache& cache) const;
void computeJointAcceleration(PxArticulationCache& cache) const;
void computeJointForce(PxArticulationCache& cache) const;
void computeDenseJacobian(PxArticulationCache& cache, PxU32& nRows, PxU32& nCols) const;
void computeCoefficientMatrix(PxArticulationCache& cache) const;
bool computeLambda(PxArticulationCache& cache, PxArticulationCache& rollBackCache, const PxReal* const jointTorque, const PxVec3 gravity, const PxU32 maxIter) const;
void computeGeneralizedMassMatrix(PxArticulationCache& cache, const bool rootMotion) const;
PxVec3 computeArticulationCOM(const bool rootFrame) const;
void computeCentroidalMomentumMatrix(PxArticulationCache& cache) const;
PxU32 getCoefficientMatrixSize() const;
PxSpatialVelocity getLinkAcceleration(const PxU32 linkId, const bool isGpuSimEnabled) const;
PxU32 getGpuArticulationIndex() const;
void updateKinematic(PxArticulationKinematicFlags flags);
//---------------------------------------------------------------------------------
// Internal API
//---------------------------------------------------------------------------------
public:
PX_FORCE_INLINE void setSim(ArticulationSim* sim)
{
PX_ASSERT((sim==0) ^ (mSim == 0));
mSim = sim;
}
PX_FORCE_INLINE ArticulationSim* getSim() const { return mSim; }
PX_FORCE_INLINE Dy::ArticulationCore& getCore() { return mCore; }
static PX_FORCE_INLINE ArticulationCore& getArticulationCore(ArticulationCore& core)
{
const size_t offset = PX_OFFSET_OF(ArticulationCore, mCore);
return *reinterpret_cast<ArticulationCore*>(reinterpret_cast<PxU8*>(&core) - offset);
}
PxNodeIndex getIslandNodeIndex() const;
void setGlobalPose();
private:
ArticulationSim* mSim;
Dy::ArticulationCore mCore;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,147 @@
// 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_ARTICULATION_JOINT_CORE_H
#define SC_ARTICULATION_JOINT_CORE_H
#include "foundation/PxTransform.h"
#include "DyVArticulation.h"
namespace physx
{
namespace Sc
{
class BodyCore;
class ArticulationJointSim;
class ArticulationCore;
class ArticulationJointDesc
{
public:
BodyCore* parent;
BodyCore* child;
PxTransform parentPose;
PxTransform childPose;
};
class ArticulationJointCore
{
public:
// PX_SERIALIZATION
ArticulationJointCore(const PxEMPTY) : mCore(PxEmpty), mSim(NULL) {}
void preExportDataReset() { mCore.jCalcUpdateFrames = true; }
//~PX_SERIALIZATION
ArticulationJointCore(const PxTransform& parentFrame, const PxTransform& childFrame);
~ArticulationJointCore();
//Those methods are not allowed while the articulation are in the scene
PX_FORCE_INLINE const PxTransform& getParentPose() const { return mCore.parentPose; }
void setParentPose(const PxTransform&);
PX_FORCE_INLINE const PxTransform& getChildPose() const { return mCore.childPose; }
void setChildPose(const PxTransform&);
//Those functions doesn't change the articulation configuration so the application is allowed to change those value in run-time
PX_FORCE_INLINE PxArticulationLimit getLimit(PxArticulationAxis::Enum axis) const { return mCore.limits[axis]; }
void setLimit(PxArticulationAxis::Enum axis, const PxArticulationLimit& limit);
PX_FORCE_INLINE PxArticulationDrive getDrive(PxArticulationAxis::Enum axis) const { return mCore.drives[axis]; }
void setDrive(PxArticulationAxis::Enum axis, const PxArticulationDrive& drive);
void setTargetP(PxArticulationAxis::Enum axis, PxReal targetP);
PX_FORCE_INLINE PxReal getTargetP(PxArticulationAxis::Enum axis) const { return mCore.targetP[axis]; }
void setTargetV(PxArticulationAxis::Enum axis, PxReal targetV);
PX_FORCE_INLINE PxReal getTargetV(PxArticulationAxis::Enum axis) const { return mCore.targetV[axis]; }
void setArmature(PxArticulationAxis::Enum axis, PxReal armature);
PX_FORCE_INLINE PxReal getArmature(PxArticulationAxis::Enum axis) const { return mCore.armature[axis]; }
void setJointPosition(PxArticulationAxis::Enum axis, const PxReal jointPos);
PxReal getJointPosition(PxArticulationAxis::Enum axis) const;
void setJointVelocity(PxArticulationAxis::Enum axis, const PxReal jointVel);
PxReal getJointVelocity(PxArticulationAxis::Enum axis) const;
void setMaxJointVelocity(PxReal maxJointV);
PX_FORCE_INLINE PxReal getMaxJointVelocity() const { return mCore.maxJointVelocity[0]; }
void setMaxJointVelocity(PxArticulationAxis::Enum axis, PxReal maxJointV);
PX_FORCE_INLINE PxReal getMaxJointVelocity(PxArticulationAxis::Enum axis) const { return mCore.maxJointVelocity[axis]; }
PX_FORCE_INLINE void setMotion(PxArticulationAxis::Enum axis, PxArticulationMotion::Enum motion) { mCore.motion[axis] = PxU8(motion); }
PX_FORCE_INLINE PxArticulationMotion::Enum getMotion(PxArticulationAxis::Enum axis) const { return PxArticulationMotion::Enum(mCore.motion[axis]); }
PX_FORCE_INLINE void setJointType(PxArticulationJointType::Enum type) { mCore.setJointType(type); }
PX_FORCE_INLINE PxArticulationJointType::Enum getJointType() const { return PxArticulationJointType::Enum(mCore.jointType); }
void setFrictionCoefficient(const PxReal coefficient);
PX_FORCE_INLINE PxReal getFrictionCoefficient() const { return mCore.frictionCoefficient; }
void setFrictionParams(PxArticulationAxis::Enum axis, const PxJointFrictionParams& jointFrictionParams);
PX_FORCE_INLINE PxJointFrictionParams getFrictionParams(PxArticulationAxis::Enum axis) const { return mCore.frictionParams[axis]; }
PX_FORCE_INLINE ArticulationJointSim* getSim() const { return mSim; }
PX_FORCE_INLINE void setSim(ArticulationJointSim* sim)
{
PX_ASSERT((sim==0) ^ (mSim == 0));
mSim = sim;
}
PX_FORCE_INLINE Dy::ArticulationJointCore& getCore() { return mCore; }
PX_FORCE_INLINE void setArticulation(ArticulationCore* articulation) { mArticulation = articulation; }
PX_FORCE_INLINE const ArticulationCore* getArticulation() const { return mArticulation; }
PX_FORCE_INLINE void setRoot(PxArticulationJointReducedCoordinate* base) { mRootType = base; }
PX_FORCE_INLINE PxArticulationJointReducedCoordinate* getRoot() const { return mRootType; }
PX_FORCE_INLINE void setLLIndex(const PxU32 llLinkIndex) { mLLLinkIndex = llLinkIndex; }
private:
void setSimDirty();
PX_FORCE_INLINE void setDirty()
{
mCore.jCalcUpdateFrames = true;
setSimDirty();
}
Dy::ArticulationJointCore mCore;
ArticulationJointSim* mSim;
ArticulationCore* mArticulation;
PxArticulationJointReducedCoordinate* mRootType;
PxU32 mLLLinkIndex;
#if PX_P64_FAMILY
PxU32 pad;
#endif
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,74 @@
// 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_ARTICULATION_MIMIC_JOINT_CORE
#define SC_ARTICULATION_MIMIC_JOINT_CORE
#include "foundation/PxVec3.h"
#include "foundation/PxTransform.h"
namespace physx
{
namespace Sc
{
class ArticulationCore;
class ArticulationMimicJointSim;
class ArticulationMimicJointCore
{
public:
// PX_SERIALIZATION
ArticulationMimicJointCore(const PxEMPTY) :mSim(NULL) {}
//~PX_SERIALIZATION
ArticulationMimicJointCore() : mSim(NULL) {}
PX_FORCE_INLINE void setSim(ArticulationMimicJointSim* sim)
{
PX_ASSERT((sim == 0) ^ (mSim == 0));
mSim = sim;
}
PX_FORCE_INLINE ArticulationMimicJointSim* getSim() const { return mSim; }
ArticulationMimicJointSim* mSim;
PxU32 mAxisA;
PxU32 mAxisB;
PxReal mGearRatio;
PxReal mOffset;
PxReal mNaturalFrequency;
PxReal mDampingRatio;
};
}//namespace Sc
}//namespace physx
#endif //SC_ARTICULATION_MIMIC_JOINT_CORE

View File

@@ -0,0 +1,147 @@
// 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 PX_PHYSICS_SCP_ARTICULATION_TENDON_CORE
#define PX_PHYSICS_SCP_ARTICULATION_TENDON_CORE
#include "DyArticulationTendon.h"
namespace physx
{
namespace Sc
{
class ArticulationSpatialTendonSim;
class ArticulationFixedTendonSim;
class ArticulationTendonCore
{
public:
// PX_SERIALIZATION
ArticulationTendonCore(const PxEMPTY) {}
void preExportDataReset() { }
//~PX_SERIALIZATION
ArticulationTendonCore() : mStiffness(0.f), mDamping(0.f), mOffset(0.f), mLimitStiffness(0.f)
{
}
PxReal mStiffness;
PxReal mDamping;
PxReal mOffset;
PxReal mLimitStiffness;
};
class ArticulationSpatialTendonCore : public ArticulationTendonCore
{
public:
// PX_SERIALIZATION
ArticulationSpatialTendonCore(const PxEMPTY) : ArticulationTendonCore(PxEmpty), mSim(NULL) {}
void preExportDataReset() { }
//~PX_SERIALIZATION
ArticulationSpatialTendonCore() : ArticulationTendonCore() { mSim = NULL; }
~ArticulationSpatialTendonCore() {}
void setStiffness(const PxReal stiffness);
PxReal getStiffness() const;
void setDamping(const PxReal damping);
PxReal getDamping() const;
void setLimitStiffness(const PxReal stiffness);
PxReal getLimitStiffness() const;
void setOffset(const PxReal offset);
PxReal getOffset() const;
PX_FORCE_INLINE void setSim(ArticulationSpatialTendonSim* sim)
{
PX_ASSERT((sim == 0) ^ (mSim == 0));
mSim = sim;
}
PX_FORCE_INLINE ArticulationSpatialTendonSim* getSim() const { return mSim; }
ArticulationSpatialTendonSim* mSim;
};
class ArticulationFixedTendonCore : public ArticulationTendonCore
{
public:
// PX_SERIALIZATION
ArticulationFixedTendonCore(const PxEMPTY) : ArticulationTendonCore(PxEmpty), mSim(NULL) {}
void preExportDataReset() {}
//~PX_SERIALIZATION
ArticulationFixedTendonCore() : ArticulationTendonCore(), mLowLimit(PX_MAX_F32), mHighLimit(-PX_MAX_F32), mRestLength(0.f)
{ mSim = NULL; }
~ArticulationFixedTendonCore() {}
void setStiffness(const PxReal stiffness);
PxReal getStiffness() const;
void setDamping(const PxReal damping);
PxReal getDamping() const;
void setLimitStiffness(const PxReal stiffness);
PxReal getLimitStiffness() const;
void setOffset(const PxReal offset);
PxReal getOffset() const;
void setSpringRestLength(const PxReal restLength);
PxReal getSpringRestLength() const;
void setLimitRange(const PxReal lowLimit, const PxReal highLimit);
void getLimitRange(PxReal& lowLimit, PxReal& highLimit) const;
PX_FORCE_INLINE void setSim(ArticulationFixedTendonSim* sim)
{
PX_ASSERT((sim == 0) ^ (mSim == 0));
mSim = sim;
}
PX_FORCE_INLINE ArticulationFixedTendonSim* getSim() const { return mSim; }
PxReal mLowLimit;
PxReal mHighLimit;
PxReal mRestLength;
ArticulationFixedTendonSim* mSim;
};
}//namespace Sc
} //namespace physx
#endif

View File

@@ -0,0 +1,83 @@
// 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_TENDON_JOINT_CORE_H
#define SC_TENDON_JOINT_CORE_H
#include "foundation/PxVec3.h"
#include "solver/PxSolverDefs.h"
namespace physx
{
namespace Sc
{
class ArticulationFixedTendonSim;
class ArticulationTendonJointCore
{
public:
// PX_SERIALIZATION
ArticulationTendonJointCore(const PxEMPTY) : mTendonSim(NULL) {}
void preExportDataReset() { }
//~PX_SERIALIZATION
ArticulationTendonJointCore()
{
coefficient = PX_MAX_F32;
recipCoefficient = PX_MAX_F32;
}
PX_FORCE_INLINE PxArticulationAxis::Enum getAxis()
{
return axis;
}
PX_FORCE_INLINE void getCoefficient(PxArticulationAxis::Enum& axis_, PxReal& coefficient_, PxReal& recipCoefficient_) const
{
axis_ = axis;
coefficient_ = coefficient;
recipCoefficient_ = recipCoefficient;
}
void setCoefficient(PxArticulationAxis::Enum axis_, const PxReal coefficient_, const PxReal recipCoefficient_);
PxArticulationAxis::Enum axis;
PxReal coefficient;
PxReal recipCoefficient;
PxU32 mLLLinkIndex;
ArticulationTendonJointCore* mParent;
PxU32 mLLTendonJointIndex;
Sc::ArticulationFixedTendonSim* mTendonSim;
};
}//namespace Sc
}//namespace physx
#endif

View File

@@ -0,0 +1,188 @@
// 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_BODY_CORE_H
#define SC_BODY_CORE_H
#include "foundation/PxTransform.h"
#include "ScRigidCore.h"
#include "PxRigidDynamic.h"
#include "PxvDynamics.h"
#include "PxvConfig.h"
namespace physx
{
namespace Sc
{
class BodySim;
class BodyCore : public RigidCore
{
public:
// PX_SERIALIZATION
BodyCore(const PxEMPTY) : RigidCore(PxEmpty), mCore(PxEmpty) {}
void restoreDynamicData();
//~PX_SERIALIZATION
BodyCore(PxActorType::Enum type, const PxTransform& bodyPose);
~BodyCore();
//---------------------------------------------------------------------------------
// External API
//---------------------------------------------------------------------------------
PX_FORCE_INLINE const PxTransform& getBody2World() const { return mCore.body2World; }
void setBody2World(const PxTransform& p);
void setCMassLocalPose(const PxTransform& body2Actor);
PX_FORCE_INLINE const PxVec3& getLinearVelocity() const { return mCore.linearVelocity; }
void setLinearVelocity(const PxVec3& v, bool skipBodySimUpdate=false);
PX_FORCE_INLINE const PxVec3& getAngularVelocity() const { return mCore.angularVelocity; }
void setAngularVelocity(const PxVec3& v, bool skipBodySimUpdate=false);
PX_FORCE_INLINE PxReal getCfmScale() const { return mCore.cfmScale; }
void setCfmScale(PxReal d);
PX_FORCE_INLINE void updateVelocities(const PxVec3& linearVelModPerStep, const PxVec3& angularVelModPerStep)
{
mCore.linearVelocity += linearVelModPerStep;
mCore.angularVelocity += angularVelModPerStep;
}
PX_FORCE_INLINE const PxTransform& getBody2Actor() const { return mCore.getBody2Actor(); }
void setBody2Actor(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);
PX_FORCE_INLINE PxReal getMaxPenetrationBias() const { return mCore.maxPenBias; }
PX_FORCE_INLINE void setMaxPenetrationBias(PxReal p) { mCore.maxPenBias = p; }
PxReal getInverseMass() const;
void setInverseMass(PxReal m);
const PxVec3& getInverseInertia() const;
void setInverseInertia(const PxVec3& i);
PxReal getLinearDamping() const;
void setLinearDamping(PxReal d);
PxReal getAngularDamping() const;
void setAngularDamping(PxReal d);
PX_FORCE_INLINE PxRigidBodyFlags getFlags() const { return mCore.mFlags; }
void setFlags(PxRigidBodyFlags f);
PX_FORCE_INLINE PxRigidDynamicLockFlags getRigidDynamicLockFlags() const { return mCore.lockFlags; }
PX_FORCE_INLINE void setRigidDynamicLockFlags(PxRigidDynamicLockFlags flags) { mCore.lockFlags = flags; }
PX_FORCE_INLINE PxReal getSleepThreshold() const { return mCore.sleepThreshold; }
void setSleepThreshold(PxReal t);
PX_FORCE_INLINE PxReal getFreezeThreshold() const { return mCore.freezeThreshold; }
void setFreezeThreshold(PxReal t);
PX_FORCE_INLINE PxReal getMaxContactImpulse() const { return mCore.maxContactImpulse; }
void setMaxContactImpulse(PxReal m);
PX_FORCE_INLINE PxReal getOffsetSlop() const { return mCore.offsetSlop; }
void setOffsetSlop(PxReal slop);
PxNodeIndex getInternalIslandNodeIndex() const;
PX_FORCE_INLINE PxReal getWakeCounter() const { return mCore.wakeCounter; }
void setWakeCounter(PxReal wakeCounter, bool forceWakeUp=false);
bool isSleeping() const;
PX_FORCE_INLINE void wakeUp(PxReal wakeCounter) { setWakeCounter(wakeCounter, true); }
void putToSleep();
PxReal getMaxAngVelSq() const;
void setMaxAngVelSq(PxReal v);
PxReal getMaxLinVelSq() const;
void setMaxLinVelSq(PxReal v);
PX_FORCE_INLINE PxU16 getSolverIterationCounts() const { return mCore.solverIterationCounts; }
void setSolverIterationCounts(PxU16 c);
bool getKinematicTarget(PxTransform& p) const;
bool getHasValidKinematicTarget() const;
void setKinematicTarget(const PxTransform& p, PxReal wakeCounter);
void invalidateKinematicTarget();
PX_FORCE_INLINE PxReal getContactReportThreshold() const { return mCore.contactReportThreshold; }
void setContactReportThreshold(PxReal t) { mCore.contactReportThreshold = t; }
void onOriginShift(const PxVec3& shift);
//---------------------------------------------------------------------------------
// Internal API
//---------------------------------------------------------------------------------
PX_FORCE_INLINE void setLinearVelocityInternal(const PxVec3& v) { mCore.linearVelocity = v; }
PX_FORCE_INLINE void setAngularVelocityInternal(const PxVec3& v) { mCore.angularVelocity = v; }
PX_FORCE_INLINE void setWakeCounterFromSim(PxReal c) { mCore.wakeCounter = c; }
BodySim* getSim() const;
PX_FORCE_INLINE PxsBodyCore& getCore() { return mCore; }
PX_FORCE_INLINE const PxsBodyCore& getCore() const { return mCore; }
static PX_FORCE_INLINE size_t getCoreOffset() { return PX_OFFSET_OF_RT(BodyCore, mCore); }
PX_FORCE_INLINE PxReal getCCDAdvanceCoefficient() const { return mCore.ccdAdvanceCoefficient; }
PX_FORCE_INLINE void setCCDAdvanceCoefficient(PxReal c) { mCore.ccdAdvanceCoefficient = c; }
void onRemoveKinematicFromScene();
PxIntBool isFrozen() const;
static PX_FORCE_INLINE BodyCore& getCore(PxsBodyCore& core)
{
return *reinterpret_cast<BodyCore*>(reinterpret_cast<PxU8*>(&core) - getCoreOffset());
}
static PX_FORCE_INLINE BodyCore& getCore(const PxsBodyCore& core)
{
return *reinterpret_cast<BodyCore*>(reinterpret_cast<PxU8*>(&const_cast<PxsBodyCore&>(core)) - getCoreOffset());
}
void setFixedBaseLink(bool value);
private:
PX_ALIGN_PREFIX(16) PxsBodyCore mCore PX_ALIGN_SUFFIX(16);
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,71 @@
// 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_BROADPHASE_H
#define SC_BROADPHASE_H
#include "PxvConfig.h"
#include "foundation/PxArray.h"
// PT: this class captures parts of the Sc::Scene that deals with broadphase matters.
namespace physx
{
class PxBroadPhaseCallback;
namespace Bp
{
class AABBManagerBase;
}
namespace Sc
{
class ObjectIDTracker;
class BroadphaseManager
{
public:
BroadphaseManager();
~BroadphaseManager();
PX_FORCE_INLINE void setBroadPhaseCallback(PxBroadPhaseCallback* callback) { mBroadPhaseCallback = callback; }
PX_FORCE_INLINE PxBroadPhaseCallback* getBroadPhaseCallback() const { return mBroadPhaseCallback; }
void prepareOutOfBoundsCallbacks(Bp::AABBManagerBase* aabbManager);
bool fireOutOfBoundsCallbacks(Bp::AABBManagerBase* aabbManager, const ObjectIDTracker& tracker, PxU64 contextID);
void flush(Bp::AABBManagerBase* aabbManager);
PxBroadPhaseCallback* mBroadPhaseCallback;
PxArray<PxU32> mOutOfBoundsIDs;
};
}
}
#endif

View File

@@ -0,0 +1,122 @@
// 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_CONSTRAINT_CORE_H
#define SC_CONSTRAINT_CORE_H
#include "PxConstraint.h"
namespace physx
{
namespace Sc
{
class ConstraintSim;
class RigidCore;
class ConstraintCore
{
public:
// PX_SERIALIZATION
ConstraintCore(const PxEMPTY) : mFlags(PxEmpty), mConnector(NULL), mSim(NULL), mResidual() {}
PX_FORCE_INLINE void setConstraintFunctions(PxConstraintConnector& n, const PxConstraintShaderTable& shaders)
{
mConnector = &n;
mSolverPrep = shaders.solverPrep;
mVisualize = shaders.visualize;
}
//~PX_SERIALIZATION
ConstraintCore(PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize);
~ConstraintCore() {}
void setBodies(RigidCore* r0v, RigidCore* r1v);
PxConstraint* getPxConstraint();
const PxConstraint* getPxConstraint() const;
PX_FORCE_INLINE PxConstraintConnector* getPxConnector() const { return mConnector; }
PX_FORCE_INLINE PxConstraintFlags getFlags() const { return mFlags; }
void setFlags(PxConstraintFlags flags);
void getForce(PxVec3& force, PxVec3& torque) const;
void setBreakForce(PxReal linear, PxReal angular);
PX_FORCE_INLINE void getBreakForce(PxReal& linear, PxReal& angular) const
{
linear = mLinearBreakForce;
angular = mAngularBreakForce;
}
void setMinResponseThreshold(PxReal threshold);
PX_FORCE_INLINE PxReal getMinResponseThreshold() const { return mMinResponseThreshold; }
void breakApart();
PX_FORCE_INLINE PxConstraintVisualize getVisualize() const { return mVisualize; }
PX_FORCE_INLINE PxConstraintSolverPrep getSolverPrep() const { return mSolverPrep; }
PX_FORCE_INLINE PxU32 getConstantBlockSize() const { return mDataSize; }
PX_FORCE_INLINE void setSim(ConstraintSim* sim)
{
PX_ASSERT((sim==0) ^ (mSim == 0));
mSim = sim;
}
PX_FORCE_INLINE ConstraintSim* getSim() const { return mSim; }
PX_FORCE_INLINE bool isDirty() const { return mIsDirty ? true : false; }
PX_FORCE_INLINE void setDirty() { mIsDirty = 1; }
PX_FORCE_INLINE void clearDirty() { mIsDirty = 0; }
PX_FORCE_INLINE PxConstraintResidual getSolverResidual() const { return mResidual; }
PX_FORCE_INLINE void setSolverResidual(const PxConstraintResidual& residual) { mResidual = residual; }
private:
PxConstraintFlags mFlags;
//In order to support O(1) insert/remove mIsDirty really wants to be an index into NpScene's dirty joint array
PxU8 mIsDirty;
PxU8 mPadding;
PxVec3 mAppliedForce;
PxVec3 mAppliedTorque;
PxConstraintConnector* mConnector;
PxConstraintSolverPrep mSolverPrep;
PxConstraintVisualize mVisualize;
PxU32 mDataSize;
PxReal mLinearBreakForce;
PxReal mAngularBreakForce;
PxReal mMinResponseThreshold;
ConstraintSim* mSim;
PxConstraintResidual mResidual;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,160 @@
// 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_DEFORMABLE_SURFACE_CORE
#define SC_DEFORMABLE_SURFACE_CORE
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "PxDeformableSurface.h"
#include "../../lowleveldynamics/include/DyDeformableSurfaceCore.h"
#include "foundation/PxAssert.h"
#include "ScActorCore.h"
#include "ScShapeCore.h"
#include "PxFiltering.h"
#include "ScRigidCore.h" //KS - required for ShapeChangeNotifyFlags. Ideally, we should move that to a separate shared file
#include "PxConeLimitedConstraint.h"
namespace physx
{
namespace Sc
{
class DeformableSurfaceSim;
class DeformableSurfaceCore : public ActorCore
{
public:
// PX_SERIALIZATION
DeformableSurfaceCore(const PxEMPTY) : ActorCore(PxEmpty) {}
//~PX_SERIALIZATION
DeformableSurfaceCore();
~DeformableSurfaceCore();
//---------------------------------------------------------------------------------
// PxActor API
//---------------------------------------------------------------------------------
void setActorFlags(PxActorFlags flags);
PxActorFlags getActorFlags() const { return mCore.actorFlags; }
//---------------------------------------------------------------------------------
// PxDeformableBody API
//---------------------------------------------------------------------------------
void setBodyFlags(PxDeformableBodyFlags flags);
PxDeformableBodyFlags getBodyFlags() const { return mCore.bodyFlags; }
void setLinearDamping(const PxReal linearDamping);
PxReal getLinearDamping() const { return mCore.linearDamping; }
void setMaxLinearVelocity(const PxReal maxLinearVelocity);
PxReal getMaxLinearVelocity() const { return mCore.maxLinearVelocity; }
void setMaxPenetrationBias(const PxReal maxPenetrationBias);
PxReal getMaxPenetrationBias() const { return mCore.maxPenetrationBias; }
void setSolverIterationCounts(PxU16 c);
PxU16 getSolverIterationCounts() const { return mCore.solverIterationCounts; }
void setSleepThreshold(const PxReal sleepThreshold);
PxReal getSleepThreshold() const { return mCore.sleepThreshold; }
void setSettlingThreshold(const PxReal settlingThreshold);
PxReal getSettlingThreshold() const { return mCore.settlingThreshold; }
void setSettlingDamping(const PxReal linearDamping);
PxReal getSettlingDamping() const { return mCore.settlingDamping; }
void setSelfCollisionFilterDistance(const PxReal selfCollisionFilterDistance);
PxReal getSelfCollisionFilterDistance() const { return mCore.selfCollisionFilterDistance; }
//deprecated
void setSelfCollisionStressTolerance(const PxReal selfCollisionStressTolerance);
PxReal getSelfCollisionStressTolerance() const { return mCore.selfCollisionStressTolerance; }
void setWakeCounter(const PxReal v);
void setWakeCounterInternal(const PxReal v);
PxReal getWakeCounter() const { return mCore.wakeCounter; }
//---------------------------------------------------------------------------------
// PxDeformableBody API
//---------------------------------------------------------------------------------
void setSurfaceFlags(PxDeformableSurfaceFlags flags);
PxDeformableSurfaceFlags getSurfaceFlags() const { return mCore.surfaceFlags; }
void setNbCollisionPairUpdatesPerTimestep(const PxU32 frequency);
PxU32 getNbCollisionPairUpdatesPerTimestep() const { return mCore.nbCollisionPairUpdatesPerTimestep; }
void setNbCollisionSubsteps(const PxU32 frequency);
PxU32 getNbCollisionSubsteps() const { return mCore.nbCollisionSubsteps; }
//---------------------------------------------------------------------------------
// Internal API
//---------------------------------------------------------------------------------
PxU32 addRigidAttachment(Sc::BodyCore* core, PxU32 vertId, const PxVec3& actorSpacePose, PxConeLimitedConstraint* constraint);
void removeRigidAttachment(Sc::BodyCore* core, PxU32 handle);
void addTriRigidFilter(Sc::BodyCore* core, PxU32 triIdx);
void removeTriRigidFilter(Sc::BodyCore* core, PxU32 triIdx);
PxU32 addTriRigidAttachment(Sc::BodyCore* core, PxU32 triIdx, const PxVec4& barycentric,
const PxVec3& actorSpacePose, PxConeLimitedConstraint* constraint);
void removeTriRigidAttachment(Sc::BodyCore* core, PxU32 handle);
void addClothFilter(Sc::DeformableSurfaceCore* otherCore, PxU32 otherTriIdx, PxU32 triIdx);
void removeClothFilter(Sc::DeformableSurfaceCore* otherCore, PxU32 otherTriIdx0, PxU32 triIdx);
PxU32 addClothAttachment(Sc::DeformableSurfaceCore* otherCore, PxU32 otherTriIdx, const PxVec4& otherTriBarycentric, PxU32 triIdx,
const PxVec4& triBarycentric);
void removeClothAttachment(Sc::DeformableSurfaceCore* otherCore, PxU32 handle);
void addMaterial(const PxU16 handle);
void clearMaterials();
PxActor* getPxActor() const;
void attachShapeCore(ShapeCore* shapeCore);
void onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags);
PX_FORCE_INLINE PxU64& getGpuMemStat() { return mGpuMemStat; }
DeformableSurfaceSim* getSim() const;
PX_FORCE_INLINE const Dy::DeformableSurfaceCore& getCore() const { return mCore; }
PX_FORCE_INLINE Dy::DeformableSurfaceCore& getCore() { return mCore; }
private:
Dy::DeformableSurfaceCore mCore;
PxU64 mGpuMemStat;
};
} // namespace Sc
} // namespace physx
#endif // PX_SUPPORT_GPU_PHYSX
#endif // SC_DEFORMABLE_SURFACE_CORE

View File

@@ -0,0 +1,176 @@
// 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_DEFORMABLE_VOLUME_CORE_H
#define SC_DEFORMABLE_VOLUME_CORE_H
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "PxDeformableVolume.h"
#include "DyDeformableVolumeCore.h"
#include "foundation/PxAssert.h"
#include "ScActorCore.h"
#include "ScShapeCore.h"
#include "PxFiltering.h"
#include "ScRigidCore.h" //KS - needed for ShapeChangeNotifyFlags. Move to a shared header
namespace physx
{
namespace Sc
{
class DeformableVolumeSim;
class BodyCore;
class DeformableSurfaceCore;
class ParticleSystemCore;
class DeformableVolumeCore : public ActorCore
{
public:
// PX_SERIALIZATION
DeformableVolumeCore(const PxEMPTY) : ActorCore(PxEmpty){}
//~PX_SERIALIZATION
DeformableVolumeCore();
~DeformableVolumeCore();
//---------------------------------------------------------------------------------
// PxActor API
//---------------------------------------------------------------------------------
void setActorFlags(PxActorFlags flags);
PxActorFlags getActorFlags() const { return mCore.actorFlags; }
//---------------------------------------------------------------------------------
// PxDeformableBody API
//---------------------------------------------------------------------------------
void setBodyFlags(PxDeformableBodyFlags flags);
PxDeformableBodyFlags getBodyFlags() const { return mCore.bodyFlags; }
void setLinearDamping(const PxReal linearDamping);
PxReal getLinearDamping() const { return mCore.linearDamping; }
void setMaxLinearVelocity(const PxReal maxLinearVelocity);
PxReal getMaxLinearVelocity() const { return mCore.maxLinearVelocity; }
void setMaxPenetrationBias(const PxReal maxPenetrationBias);
PxReal getMaxPenetrationBias() const { return mCore.maxPenetrationBias; }
void setSolverIterationCounts(PxU16 c);
PxU16 getSolverIterationCounts() const { return mCore.solverIterationCounts; }
void setSleepThreshold(const PxReal sleepThreshold);
PxReal getSleepThreshold() const { return mCore.sleepThreshold; }
void setSettlingThreshold(const PxReal settlingThreshold);
PxReal getSettlingThreshold() const { return mCore.settlingThreshold; }
void setSettlingDamping(const PxReal linearDamping);
PxReal getSettlingDamping() const { return mCore.settlingDamping; }
void setSelfCollisionFilterDistance(const PxReal selfCollisionFilterDistance);
PxReal getSelfCollisionFilterDistance() const { return mCore.selfCollisionFilterDistance; }
void setWakeCounter(const PxReal v);
void setWakeCounterInternal(const PxReal v);
PxReal getWakeCounter() const { return mCore.wakeCounter; }
//---------------------------------------------------------------------------------
// PxDeformableBody API
//---------------------------------------------------------------------------------
void setVolumeFlags(PxDeformableVolumeFlags flags);
PxDeformableVolumeFlags getVolumeFlags() const { return mCore.volumeFlags; }
void setSelfCollisionStressTolerance(const PxReal selfCollisionStressTolerance);
PxReal getSelfCollisionStressTolerance() const { return mCore.selfCollisionStressTolerance; }
void setKinematicTargets(const PxVec4* positions);
PxU32 getGpuIndex() const;
void addParticleFilter(Sc::ParticleSystemCore* core, PxU32 particleId, PxU32 userBufferId, PxU32 tetId);
void removeParticleFilter(Sc::ParticleSystemCore* core, PxU32 particleId, PxU32 userBufferId, PxU32 tetId);
PxU32 addParticleAttachment(Sc::ParticleSystemCore* core, PxU32 particleId, PxU32 userBufferId, PxU32 tetId, const PxVec4& barycentric);
void removeParticleAttachment(Sc::ParticleSystemCore* core, PxU32 handle);
void addRigidFilter(Sc::BodyCore* core, PxU32 vertId);
void removeRigidFilter(Sc::BodyCore* core, PxU32 vertId);
PxU32 addRigidAttachment(Sc::BodyCore* core, PxU32 vertId, const PxVec3& actorSpacePose, PxConeLimitedConstraint* constraint, bool doConversion);
void removeRigidAttachment(Sc::BodyCore* core, PxU32 handle);
void addTetRigidFilter(Sc::BodyCore* core, PxU32 tetIdx);
void removeTetRigidFilter(Sc::BodyCore* core, PxU32 tetIdx);
PxU32 addTetRigidAttachment(Sc::BodyCore* core, PxU32 tetIdx, const PxVec4& barycentric, const PxVec3& actorSpacePose,
PxConeLimitedConstraint* constraint, bool doConversion);
void addSoftBodyFilter(Sc::DeformableVolumeCore& core, PxU32 tetIdx0, PxU32 tetIdx1);
void removeSoftBodyFilter(Sc::DeformableVolumeCore& core, PxU32 tetIdx0, PxU32 tetIdx1);
void addSoftBodyFilters(Sc::DeformableVolumeCore& core, PxU32* tetIndices0, PxU32* tetIndices1, PxU32 tetIndicesSize);
void removeSoftBodyFilters(Sc::DeformableVolumeCore& core, PxU32* tetIndices0, PxU32* tetIndices1, PxU32 tetIndicesSize);
PxU32 addSoftBodyAttachment(Sc::DeformableVolumeCore& core, PxU32 tetIdx0, const PxVec4& triBarycentric0, PxU32 tetIdx1, const PxVec4& tetBarycentric1,
PxConeLimitedConstraint* constraint, PxReal constraintOffset, bool doConversion);
void removeSoftBodyAttachment(Sc::DeformableVolumeCore& core, PxU32 handle);
void addClothFilter(Sc::DeformableSurfaceCore& core, PxU32 triIdx, PxU32 tetIdx);
void removeClothFilter(Sc::DeformableSurfaceCore& core, PxU32 triIdx, PxU32 tetIdx);
PxU32 addClothAttachment(Sc::DeformableSurfaceCore& core, PxU32 triIdx, const PxVec4& triBarycentric, PxU32 tetIdx, const PxVec4& tetBarycentric,
PxConeLimitedConstraint* constraint, PxReal constraintOffset, bool doConversion);
void removeClothAttachment(Sc::DeformableSurfaceCore& core, PxU32 handle);
//---------------------------------------------------------------------------------
// Internal API
//---------------------------------------------------------------------------------
void addMaterial(const PxU16 handle);
void clearMaterials();
PxActor* getPxActor() const;
void attachShapeCore(ShapeCore* shapeCore);
void attachSimulationMesh(PxTetrahedronMesh* simulationMesh, PxDeformableVolumeAuxData* simulationState);
void onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags);
PX_FORCE_INLINE PxU64& getGpuMemStat() { return mGpuMemStat; }
DeformableVolumeSim* getSim() const;
PX_FORCE_INLINE const Dy::DeformableVolumeCore& getCore() const { return mCore; }
PX_FORCE_INLINE Dy::DeformableVolumeCore& getCore() { return mCore; }
private:
Dy::DeformableVolumeCore mCore;
PxU64 mGpuMemStat;
};
} // namespace Sc
} // namespace physx
#endif // PX_SUPPORT_GPU_PHYSX
#endif // SC_DEFORMABLE_VOLUME_CORE_H

View File

@@ -0,0 +1,123 @@
// 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_ITERATORS_H
#define SC_ITERATORS_H
#include "foundation/PxVec3.h"
#include "PxContact.h"
namespace physx
{
class PxShape;
class PxsContactManagerOutputIterator;
namespace Sc
{
class ShapeSimBase;
class ElementSimInteraction;
class ActorSim;
struct Contact
{
Contact()
: normal(0.0f)
, point(0.0f)
, separation(0.0f)
, normalForce(0.0f)
{}
PxVec3 normal;
PxVec3 point;
PxShape* shape0;
PxShape* shape1;
PxReal separation;
PxReal normalForce;
PxU32 faceIndex0; // these are the external indices
PxU32 faceIndex1;
bool normalForceAvailable;
};
struct FrictionAnchor
{
PxVec3 normal;
PxVec3 point;
PxVec3 impulse;
};
class ContactIterator
{
public:
class Pair
{
public:
Pair() : mIter(NULL, NULL, NULL, 0, 0), mAnchorIter(NULL, NULL, 0) {}
Pair(const void*& contactPatches, const void*& contactPoints, const void*& frictionPatches, const PxU32 /*contactDataSize*/, const PxReal*& forces, PxU32 numContacts, PxU32 numPatches, ShapeSimBase& shape0, ShapeSimBase& shape1, ActorSim* actor0, ActorSim* actor1);
Contact* getNextContact();
FrictionAnchor* getNextFrictionAnchor();
PxActor* getActor0() { return mActor0; }
PxActor* getActor1() { return mActor1; }
private:
PxU32 mIndex;
PxU32 mNumContacts;
PxContactStreamIterator mIter;
PxFrictionAnchorStreamIterator mAnchorIter;
const PxReal* mForces;
Contact mCurrentContact;
FrictionAnchor mCurrentAnchor;
PxActor* mActor0;
PxActor* mActor1;
};
ContactIterator() {}
explicit ContactIterator(ElementSimInteraction** first, ElementSimInteraction** last, PxsContactManagerOutputIterator& outputs): mCurrent(first), mLast(last), mOffset(0), mOutputs(&outputs)
{
if ((!first) || (!last) || (first == last))
{
mCurrent = NULL;
mLast = NULL;
}
}
Pair* getNextPair();
private:
ElementSimInteraction** mCurrent;
ElementSimInteraction** mLast;
Pair mCurrentPair;
PxU32 mOffset;
PxsContactManagerOutputIterator* mOutputs;
private:
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,154 @@
// 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_PARTICLESYSTEM_CORE_H
#define SC_PARTICLESYSTEM_CORE_H
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "PxParticleSystem.h"
#include "foundation/PxAssert.h"
#include "ScActorCore.h"
#include "ScShapeCore.h"
#include "PxFiltering.h"
#include "DyParticleSystem.h"
#include "ScParticleSystemShapeCore.h"
namespace physx
{
namespace Sc
{
class ParticleSystemSim;
class BodyCore;
class ParticleSystemCore : public ActorCore
{
// PX_SERIALIZATION
public:
ParticleSystemCore(const PxEMPTY) : ActorCore(PxEmpty) {}
//~PX_SERIALIZATION
ParticleSystemCore(PxActorType::Enum actorType);
~ParticleSystemCore();
//---------------------------------------------------------------------------------
// External API
//---------------------------------------------------------------------------------
PxReal getSleepThreshold() const;
void setSleepThreshold(const PxReal v);
PxReal getRestOffset() const;
void setRestOffset(const PxReal v);
PxReal getContactOffset() const;
void setContactOffset(const PxReal v);
PxReal getParticleContactOffset() const;
void setParticleContactOffset(const PxReal v);
PxReal getSolidRestOffset() const;
void setSolidRestOffset(const PxReal v);
PxReal getFluidRestOffset() const;
void setFluidRestOffset(const PxReal v);
PxReal getMaxDepenetrationVelocity() const;
void setMaxDepenetrationVelocity(const PxReal v);
PxReal getMaxVelocity() const;
void setMaxVelocity(const PxReal v);
PxParticleSystemCallback* getParticleSystemCallback() const;
void setParticleSystemCallback(PxParticleSystemCallback* callback);
PxReal getFluidBoundaryDensityScale() const;
void setFluidBoundaryDensityScale(const PxReal v);
PxU32 getGridSizeX() const;
void setGridSizeX(const PxU32 v);
PxU32 getGridSizeY() const;
void setGridSizeY(const PxU32 v);
PxU32 getGridSizeZ() const;
void setGridSizeZ(const PxU32 v);
PxU16 getSolverIterationCounts() const { return mShapeCore.getLLCore().solverIterationCounts; }
void setSolverIterationCounts(PxU16 c);
PxReal getWakeCounter() const;
void setWakeCounter(const PxReal v);
void setWakeCounterInternal(const PxReal v);
bool isSleeping() const;
void wakeUp(PxReal wakeCounter);
void putToSleep();
PxActor* getPxActor() const;
PxParticleFlags getFlags() const { return mShapeCore.getLLCore().mFlags; }
void setFlags(PxParticleFlags flags);
PxParticleLockFlags getLockFlags() const { return mShapeCore.getLLCore().mLockFlags; }
void setLockFlags(PxParticleLockFlags lockFlags) { mShapeCore.getLLCore().mLockFlags = lockFlags; }
void setWind(const PxVec3& wind) {mShapeCore.getLLCore().mWind = wind;}
PxVec3 getWind() const { return mShapeCore.getLLCore().mWind; }
PxSparseGridParams getSparseGridParams() const { return mShapeCore.getLLCore().sparseGridParams; }
void setSparseGridParams(const PxSparseGridParams& params) { mShapeCore.getLLCore().sparseGridParams = params; }
void addRigidAttachment(Sc::BodyCore* core);
void removeRigidAttachment(Sc::BodyCore* core);
//---------------------------------------------------------------------------------
// Internal API
//---------------------------------------------------------------------------------
public:
ParticleSystemSim* getSim() const;
PX_FORCE_INLINE const ParticleSystemShapeCore& getShapeCore() const { return mShapeCore; }
PX_FORCE_INLINE ParticleSystemShapeCore& getShapeCore() { return mShapeCore; }
void setDirty(const bool dirty);
private:
//ParticleSystemSim* mSim;
ParticleSystemShapeCore mShapeCore;
};
} // namespace Sc
}
#endif
#endif

View File

@@ -0,0 +1,127 @@
// 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_PHYSICS_H
#define SC_PHYSICS_H
#include "PxPhysics.h"
#include "PxScene.h"
#include "foundation/PxUserAllocated.h"
#include "foundation/PxBasicTemplates.h"
#include "PxActor.h"
namespace physx
{
class PxMaterial;
class PxTolerancesScale;
struct PxvOffsetTable;
#if PX_SUPPORT_GPU_PHYSX
class PxPhysXGpu;
#endif
namespace Sc
{
class Scene;
class StaticCore;
class RigidCore;
class BodyCore;
class ArticulationCore;
class ArticulationJointCore;
class ConstraintCore;
class ShapeCore;
struct OffsetTable
{
PX_FORCE_INLINE OffsetTable() {}
PX_FORCE_INLINE PxShape* convertScShape2Px(ShapeCore* sc) const { return PxPointerOffset<PxShape*>(sc, scShape2Px); }
PX_FORCE_INLINE const PxShape* convertScShape2Px(const ShapeCore* sc) const { return PxPointerOffset<const PxShape*>(sc, scShape2Px); }
PX_FORCE_INLINE PxConstraint* convertScConstraint2Px(ConstraintCore* sc) const { return PxPointerOffset<PxConstraint*>(sc, scConstraint2Px); }
PX_FORCE_INLINE const PxConstraint* convertScConstraint2Px(const ConstraintCore* sc) const { return PxPointerOffset<const PxConstraint*>(sc, scConstraint2Px); }
PX_FORCE_INLINE PxArticulationReducedCoordinate* convertScArticulation2Px(ArticulationCore* sc) const
{
return PxPointerOffset<PxArticulationReducedCoordinate*>(sc, scArticulationRC2Px);
}
PX_FORCE_INLINE const PxArticulationReducedCoordinate* convertScArticulation2Px(const ArticulationCore* sc) const
{
return PxPointerOffset<const PxArticulationReducedCoordinate*>(sc, scArticulationRC2Px);
}
PX_FORCE_INLINE PxArticulationJointReducedCoordinate* convertScArticulationJoint2Px(ArticulationJointCore* sc) const
{
return PxPointerOffset<PxArticulationJointReducedCoordinate*>(sc, scArticulationJointRC2Px);
}
PX_FORCE_INLINE const PxArticulationJointReducedCoordinate* convertScArticulationJoint2Px(const ArticulationJointCore* sc) const
{
return PxPointerOffset<const PxArticulationJointReducedCoordinate*>(sc, scArticulationJointRC2Px);
}
ptrdiff_t scRigidStatic2PxActor;
ptrdiff_t scRigidDynamic2PxActor;
ptrdiff_t scArticulationLink2PxActor;
ptrdiff_t scDeformableSurface2PxActor;
ptrdiff_t scDeformableVolume2PxActor;
ptrdiff_t scPBDParticleSystem2PxActor;
ptrdiff_t scShape2Px;
ptrdiff_t scArticulationRC2Px;
ptrdiff_t scArticulationJointRC2Px;
ptrdiff_t scConstraint2Px;
ptrdiff_t scCore2PxActor[PxActorType::eACTOR_COUNT];
};
extern OffsetTable gOffsetTable;
class Physics : public PxUserAllocated
{
public:
PX_FORCE_INLINE static Physics& getInstance() { return *mInstance; }
Physics(const PxTolerancesScale&, const PxvOffsetTable& pxvOffsetTable);
~Physics();
PX_FORCE_INLINE const PxTolerancesScale& getTolerancesScale() const { return mScale; }
private:
PxTolerancesScale mScale;
static Physics* mInstance;
public:
static const PxReal sWakeCounterOnCreation;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,88 @@
// 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_RIGID_CORE_H
#define SC_RIGID_CORE_H
#include "ScActorCore.h"
#include "ScPhysics.h"
#include "PxvDynamics.h"
#include "PxShape.h"
namespace physx
{
namespace Sc
{
class RigidSim;
class ShapeCore;
struct ShapeChangeNotifyFlag
{
enum Enum
{
eGEOMETRY = 1<<0,
eSHAPE2BODY = 1<<1,
eFILTERDATA = 1<<2,
eCONTACTOFFSET = 1<<3,
eRESTOFFSET = 1<<4,
eRESET_FILTERING = 1<<5
};
};
typedef PxFlags<ShapeChangeNotifyFlag::Enum, PxU32> ShapeChangeNotifyFlags;
PX_FLAGS_OPERATORS(ShapeChangeNotifyFlag::Enum,PxU32)
class RigidCore : public ActorCore
{
public:
PX_FORCE_INLINE PxActor* getPxActor() const
{
return PxPointerOffset<PxActor*>(const_cast<RigidCore*>(this), gOffsetTable.scCore2PxActor[getActorCoreType()]);
}
void addShapeToScene(ShapeCore& shape);
void removeShapeFromScene(ShapeCore& shape, bool wakeOnLostTouch);
void onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags);
void onShapeFlagsChange(ShapeCore& shape, PxShapeFlags oldShapeFlags);
void unregisterShapeFromNphase(ShapeCore& shapeCore);
void registerShapeInNphase(ShapeCore& shapeCore);
RigidSim* getSim() const;
PxU32 getRigidID() const;
protected:
RigidCore(const PxEMPTY) : ActorCore(PxEmpty) {}
RigidCore(PxActorType::Enum type);
~RigidCore();
};
} // namespace Sc
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,132 @@
// 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_SHAPE_CORE_H
#define SC_SHAPE_CORE_H
#include "foundation/PxUtilities.h"
#include "PxvGeometry.h"
#include "PxFiltering.h"
#include "PxShape.h"
namespace physx
{
class PxShape; // PT: TODO: fw decl of higher-level class isn't great
namespace Sc
{
class ShapeSim;
class ShapeCore
{
public:
// PX_SERIALIZATION
ShapeCore(const PxEMPTY);
void exportExtraData(PxSerializationContext& stream);
void importExtraData(PxDeserializationContext& context);
void resolveReferences(PxDeserializationContext& context);
void resolveMaterialReference(PxU32 materialTableIndex, PxU16 materialIndex);
//~PX_SERIALIZATION
ShapeCore( const PxGeometry& geometry, PxShapeFlags shapeFlags,
const PxU16* materialIndices, PxU16 materialCount, bool isExclusive,
PxShapeCoreFlag::Enum coreFlags = PxShapeCoreFlag::Enum(0));
~ShapeCore();
PX_FORCE_INLINE PxGeometryType::Enum getGeometryType() const { return mCore.mGeometry.getType(); }
PxShape* getPxShape();
const PxShape* getPxShape() const;
PX_FORCE_INLINE const GeometryUnion& getGeometryUnion() const { return mCore.mGeometry; }
PX_FORCE_INLINE const PxGeometry& getGeometry() const { return mCore.mGeometry.getGeometry(); }
void setGeometry(const PxGeometry& geom);
PxU16 getNbMaterialIndices() const;
const PxU16* getMaterialIndices() const;
void setMaterialIndices(const PxU16* materialIndices, PxU16 materialIndexCount);
PX_FORCE_INLINE const PxTransform& getShape2Actor() const { return mCore.getTransform(); }
PX_FORCE_INLINE void setShape2Actor(const PxTransform& s2b) { mCore.setTransform(s2b); }
PX_FORCE_INLINE const PxFilterData& getSimulationFilterData() const { return mSimulationFilterData; }
PX_FORCE_INLINE void setSimulationFilterData(const PxFilterData& data) { mSimulationFilterData = data; }
PX_FORCE_INLINE PxReal getContactOffset() const { return mCore.mContactOffset; }
void setContactOffset(PxReal offset);
PX_FORCE_INLINE PxReal getRestOffset() const { return mCore.mRestOffset; }
PX_FORCE_INLINE void setRestOffset(PxReal offset) { mCore.mRestOffset = offset; }
PX_FORCE_INLINE PxReal getDensityForFluid() const { return mCore.getDensityForFluid(); }
PX_FORCE_INLINE void setDensityForFluid(PxReal densityForFluid) { mCore.setDensityForFluid(densityForFluid); }
PX_FORCE_INLINE PxReal getTorsionalPatchRadius() const { return mCore.mTorsionalRadius; }
PX_FORCE_INLINE void setTorsionalPatchRadius(PxReal tpr) { mCore.mTorsionalRadius = tpr; }
PX_FORCE_INLINE PxReal getMinTorsionalPatchRadius() const {return mCore.mMinTorsionalPatchRadius; }
PX_FORCE_INLINE void setMinTorsionalPatchRadius(PxReal radius) { mCore.mMinTorsionalPatchRadius = radius; }
PX_FORCE_INLINE PxShapeFlags getFlags() const { return PxShapeFlags(mCore.mShapeFlags); }
PX_FORCE_INLINE void setFlags(PxShapeFlags f) { mCore.mShapeFlags = f; }
PX_FORCE_INLINE const PxsShapeCore& getCore() const { return mCore; }
static PX_FORCE_INLINE size_t getCoreOffset() { return PX_OFFSET_OF(ShapeCore, mCore); }
static PX_FORCE_INLINE ShapeCore& getCore(PxsShapeCore& core)
{
return *reinterpret_cast<ShapeCore*>(reinterpret_cast<PxU8*>(&core) - getCoreOffset());
}
PX_FORCE_INLINE ShapeSim* getExclusiveSim() const
{
return mExclusiveSim;
}
PX_FORCE_INLINE void setExclusiveSim(ShapeSim* sim)
{
if(!sim || mCore.mShapeCoreFlags.isSet(PxShapeCoreFlag::eIS_EXCLUSIVE))
mExclusiveSim = sim;
}
#if PX_WINDOWS_FAMILY // PT: to avoid "error: offset of on non-standard-layout type" on Linux
protected:
#endif
PxFilterData mSimulationFilterData; // Simulation filter data
PxsShapeCore PX_ALIGN(16, mCore);
ShapeSim* mExclusiveSim; //only set if shape is exclusive
#if PX_WINDOWS_FAMILY // PT: to avoid "error: offset of on non-standard-layout type" on Linux
public:
#endif
const char* mName; // PT: moved here from NpShape to fill padding bytes
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,65 @@
// 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_SQ_BOUNDS_SYNC_H
#define SC_SQ_BOUNDS_SYNC_H
#include "foundation/PxSimpleTypes.h"
#include "foundation/PxBitMap.h"
#include "PxSceneQuerySystem.h"
namespace physx
{
class PxBounds3;
class PxRigidBody;
class PxShape;
typedef PxSQPrunerHandle ScPrunerHandle;
namespace Sc
{
// PT: TODO: revisit the need for a virtual interface
struct SqRefFinder
{
virtual ScPrunerHandle find(const PxRigidBody* body, const PxShape* shape, PxU32& prunerIndex) = 0;
virtual ~SqRefFinder() {}
};
// PT: TODO: revisit the need for a virtual interface
struct SqBoundsSync
{
virtual void sync(PxU32 prunerIndex, const ScPrunerHandle* handles, const PxU32* boundsIndices, const PxBounds3* bounds, const PxTransform32* transforms, PxU32 count, const PxBitMap& ignoredIndices) = 0;
virtual ~SqBoundsSync() {}
};
}
}
#endif

View File

@@ -0,0 +1,70 @@
// 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_STATIC_CORE_H
#define SC_STATIC_CORE_H
#include "ScRigidCore.h"
#include "PxvDynamics.h"
namespace physx
{
namespace Sc
{
class StaticSim;
class StaticCore : public RigidCore
{
public:
StaticCore(const PxTransform& actor2World): RigidCore(PxActorType::eRIGID_STATIC)
{
mCore.body2World = actor2World;
mCore.mFlags = PxRigidBodyFlags();
}
PX_FORCE_INLINE const PxTransform& getActor2World() const { return mCore.body2World; }
void setActor2World(const PxTransform& actor2World);
PX_FORCE_INLINE PxsRigidCore& getCore() { return mCore; }
static PX_FORCE_INLINE size_t getCoreOffset() { return PX_OFFSET_OF_RT(StaticCore, mCore);}
StaticCore(const PxEMPTY) : RigidCore(PxEmpty), mCore(PxEmpty) {}
StaticSim* getSim() const;
PX_FORCE_INLINE void onOriginShift(const PxVec3& shift) { mCore.body2World.p -= shift; }
private:
PxsRigidCore mCore;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,161 @@
// 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.
#include "ScActorCore.h"
#include "ScActorSim.h"
#include "ScShapeCore.h"
#include "ScShapeSim.h"
#include "ScBodySim.h"
using namespace physx;
Sc::ActorCore::ActorCore(PxActorType::Enum actorType, PxU8 actorFlags, PxClientID owner, PxDominanceGroup dominanceGroup) :
mSim (NULL),
mPackedIDs ((PxU32(owner)<<SC_FILTERING_ID_SHIFT_BIT)|SC_FILTERING_ID_MASK),
mActorFlags (actorFlags),
mActorType (PxU8(actorType)),
mDominanceGroup (dominanceGroup)
{
PX_ASSERT((actorType & 0xff) == actorType);
PX_ASSERT(!hasAggregateID());
}
Sc::ActorCore::~ActorCore()
{
}
void Sc::ActorCore::setActorFlags(PxActorFlags af)
{
const PxActorFlags old = mActorFlags;
if(af!=old)
{
mActorFlags = af;
if(mSim)
mSim->postActorFlagChange(old, af);
}
}
void Sc::ActorCore::setDominanceGroup(PxDominanceGroup g)
{
PX_ASSERT(g<32);
const bool b = mDominanceGroup.isBitSet()!=0;
mDominanceGroup = PxBitAndByte(PxU8(g) & 31, b);
if(mSim)
{
//force all related interactions to refresh, so they fetch new dominance values.
mSim->setActorsInteractionsDirty(InteractionDirtyFlag::eDOMINANCE, NULL, InteractionFlag::eRB_ELEMENT);
}
}
void Sc::ActorCore::setAggregateID(PxU32 id)
{
if(id==0xffffffff)
{
if(hasAggregateID())
{
// PT: this was an aggregate ID and we want to disable it.
mDominanceGroup.clearBit();
resetID();
}
else
{
// PT: this was not an aggregate ID. Make sure it wasn't an env ID either.
PX_ASSERT((mPackedIDs & SC_FILTERING_ID_MASK) == SC_FILTERING_ID_MASK);
}
}
else
{
PX_ASSERT(id<SC_FILTERING_ID_MAX);
// PT: we want to setup an aggregate ID.
if(hasAggregateID())
{
// PT: this was already an aggregate ID and we want to update it.
}
else
{
// PT: this was not an aggregate ID. Make sure it wasn't an env ID either.
PX_ASSERT((mPackedIDs & SC_FILTERING_ID_MASK) == SC_FILTERING_ID_MASK);
mDominanceGroup.setBit();
}
setID(id);
}
}
void Sc::ActorCore::setEnvID(PxU32 id)
{
if(id==0xffffffff)
{
// PT: we want to disable the env ID
if(hasAggregateID())
{
// PT: this is an aggregate ID => env ID is already disabled.
}
else
{
// PT: this is not an aggregate ID => disable env ID.
resetID();
}
}
else
{
PX_ASSERT(id<SC_FILTERING_ID_MAX);
// PT: we want to setup an env ID.
if(hasAggregateID())
{
// PT: this is already an aggregate ID, invalid case
PX_ASSERT(!"Invalid case, aggregated actors cannot have their own env ID. Setup the env ID on the owner aggregate.");
}
else
{
setID(id);
}
}
}
void Sc::ActorCore::reinsertShapes()
{
PX_ASSERT(mSim);
if(!mSim)
return;
PxU32 nbElems = mSim->getNbElements();
ElementSim** elems = mSim->getElements();
while (nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
current->reinsertBroadPhase();
}
}

View File

@@ -0,0 +1,252 @@
// 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_ACTOR_PAIR_H
#define SC_ACTOR_PAIR_H
#include "ScRigidSim.h"
#include "ScContactStream.h"
#include "ScNPhaseCore.h"
#include "foundation/PxErrors.h"
#include "foundation/PxFoundation.h"
#include "foundation/PxPreprocessor.h"
#include "foundation/PxSimpleTypes.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScDeformableSurfaceSim.h"
#include "ScDeformableVolumeSim.h"
#endif
namespace physx
{
namespace Sc
{
class ActorPairContactReportData
{
public:
ActorPairContactReportData() :
mStrmResetStamp (0xffffffff),
mActorAID (0xffffffff),
mActorBID (0xffffffff),
mPxActorA (NULL),
mPxActorB (NULL)
{}
ContactStreamManager mContactStreamManager;
PxU32 mStrmResetStamp;
PxU32 mActorAID;
PxU32 mActorBID;
PxActor* mPxActorA;
PxActor* mPxActorB;
};
/**
\brief Class shared by all shape interactions for a pair of actors.
This base class is used if no shape pair of an actor pair has contact reports requested.
*/
class ActorPair
{
public:
enum ActorPairFlags
{
eIS_REPORT_PAIR = (1<<0),
eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET = (1<<1), // PT: whether the pair is already stored in the 'ContactReportActorPairSet' or not
eMAX = (1<<2)
};
PX_FORCE_INLINE ActorPair() : mRefCount(0), mTouchCount_internalFlags(0) {}
PX_FORCE_INLINE ~ActorPair() {}
PX_FORCE_INLINE PxIntBool isReportPair() const { return (getFlags() & eIS_REPORT_PAIR); }
PX_FORCE_INLINE void incTouchCount() { setTouchCount(getTouchCount() + 1); PX_ASSERT(getTouchCount()); }
PX_FORCE_INLINE void decTouchCount() { PX_ASSERT(getTouchCount()); setTouchCount(getTouchCount() -1); }
PX_FORCE_INLINE PxU32 getTouchCount() const { return mTouchCount_internalFlags >> sTouchCountShift; }
PX_FORCE_INLINE void incRefCount() { ++mRefCount; PX_ASSERT(mRefCount>0); }
PX_FORCE_INLINE PxU32 decRefCount() { PX_ASSERT(mRefCount>0); return --mRefCount; }
PX_FORCE_INLINE PxU32 getRefCount() const { return mRefCount; }
private:
ActorPair& operator=(const ActorPair&);
protected:
PxU32 mRefCount;
PxU32 mTouchCount_internalFlags;
PX_FORCE_INLINE PxU32 getFlags() const { return mTouchCount_internalFlags & sFlagMask; }
PX_FORCE_INLINE void raiseFlags(PxU32 flags) { PX_ASSERT(flags < ActorPairFlags::eMAX); mTouchCount_internalFlags |= flags; }
PX_FORCE_INLINE void clearFlags(PxU32 flags);
PX_FORCE_INLINE void setTouchCount(PxU32 count);
public:
static const PxU32 sFlagMask = (ActorPairFlags::eMAX - 1);
static const PxU32 sTouchCountShift = 2; // shift necessary to extract the touch count
PX_COMPILE_TIME_ASSERT(ActorPairFlags::eMAX == (1 << sTouchCountShift)); // if this breaks please adjust the sTouchCountShift above.
};
/**
\brief Class shared by all shape interactions for a pair of actors if contact reports are requested.
This class is used if at least one shape pair of an actor pair has contact reports requested.
\note If a pair of actors had contact reports requested for some of the shape interactions but all of them switch to not wanting contact reports
any longer, then the ActorPairReport instance is kept being used and won't get replaced by a simpler ActorPair instance.
*/
class ActorPairReport : public ActorPair
{
PX_NOCOPY(ActorPairReport)
public:
PX_FORCE_INLINE ActorPairReport(ActorSim&, ActorSim&);
PX_FORCE_INLINE ~ActorPairReport();
PX_INLINE ContactStreamManager& createContactStreamManager(NPhaseCore&);
PX_FORCE_INLINE ContactStreamManager& getContactStreamManager() const { PX_ASSERT(mReportData); return mReportData->mContactStreamManager; }
PX_FORCE_INLINE ActorSim& getActorA() const { return mActorA; }
PX_FORCE_INLINE ActorSim& getActorB() const { return mActorB; }
PX_INLINE PxU32 getActorAID() const { PX_ASSERT(mReportData); return mReportData->mActorAID; }
PX_INLINE PxU32 getActorBID() const { PX_ASSERT(mReportData); return mReportData->mActorBID; }
PX_INLINE PxActor* getPxActorA() const { PX_ASSERT(mReportData); return mReportData->mPxActorA; }
PX_INLINE PxActor* getPxActorB() const { PX_ASSERT(mReportData); return mReportData->mPxActorB; }
PX_INLINE bool streamResetStamp(PxU32 cmpStamp);
PX_FORCE_INLINE PxIntBool isInContactReportActorPairSet() const { return (getFlags() & eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET); }
PX_FORCE_INLINE void setInContactReportActorPairSet() { raiseFlags(eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET); }
PX_FORCE_INLINE void clearInContactReportActorPairSet() { clearFlags(eIS_IN_CONTACT_REPORT_ACTOR_PAIR_SET); }
PX_FORCE_INLINE void createContactReportData(NPhaseCore&);
PX_FORCE_INLINE void convert(const ActorPair& aPair) { PX_ASSERT(!aPair.isReportPair()); setTouchCount(aPair.getTouchCount()); mRefCount = aPair.getRefCount(); }
PX_FORCE_INLINE static ActorPairReport& cast(ActorPair& aPair) { PX_ASSERT(aPair.isReportPair()); return static_cast<ActorPairReport&>(aPair); }
private:
ActorSim& mActorA;
ActorSim& mActorB;
public:
ActorPairContactReportData* mReportData;
};
} // namespace Sc
//// Sc::ActorPair implementations
PX_FORCE_INLINE void Sc::ActorPair::setTouchCount(PxU32 count)
{
PX_ASSERT(count <= (PX_MAX_U32 >> sTouchCountShift));
if (count == (PX_MAX_U32 >> sTouchCountShift)) // we rely on inc/dec behaviour here which means we'll always pass the max value before overflowing.
{
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Sc::ActorPair: maximum count of touching shapes per pair reached, any additional touch will introduce undefined behavior.");
}
mTouchCount_internalFlags = (mTouchCount_internalFlags & sFlagMask) | (count << sTouchCountShift);
}
PX_FORCE_INLINE void Sc::ActorPair::clearFlags(PxU32 flags)
{
PX_ASSERT(flags < ActorPairFlags::eMAX);
PxU32 tmpFlags = getFlags();
tmpFlags &= ~flags;
mTouchCount_internalFlags &= ~sFlagMask;
raiseFlags(tmpFlags);
}
//// Sc::ActorPairReport implementations
PX_FORCE_INLINE Sc::ActorPairReport::ActorPairReport(ActorSim& actor0, ActorSim& actor1) : ActorPair(),
mActorA (actor0),
mActorB (actor1),
mReportData (NULL)
{
PX_ASSERT(getFlags() == 0);
raiseFlags(ActorPair::eIS_REPORT_PAIR);
}
PX_FORCE_INLINE Sc::ActorPairReport::~ActorPairReport()
{
PX_ASSERT(mReportData == NULL);
}
PX_INLINE bool Sc::ActorPairReport::streamResetStamp(PxU32 cmpStamp)
{
PX_ASSERT(mReportData);
const bool ret = (cmpStamp != mReportData->mStrmResetStamp);
mReportData->mStrmResetStamp = cmpStamp;
return ret;
}
PX_INLINE Sc::ContactStreamManager& Sc::ActorPairReport::createContactStreamManager(NPhaseCore& npCore)
{
// Lazy create report data
if(!mReportData)
createContactReportData(npCore);
return mReportData->mContactStreamManager;
}
PX_FORCE_INLINE void Sc::ActorPairReport::createContactReportData(NPhaseCore& npCore)
{
PX_ASSERT(!mReportData);
Sc::ActorPairContactReportData* reportData = npCore.createActorPairContactReportData();
mReportData = reportData;
if(reportData)
{
const ActorCore& actorCoreA = mActorA.getActorCore();
const ActorCore& actorCoreB = mActorB.getActorCore();
reportData->mActorAID = mActorA.getActorID();
reportData->mActorBID = mActorB.getActorID();
#if PX_SUPPORT_GPU_PHYSX
if (mActorA.getActorType() == PxActorType::eDEFORMABLE_VOLUME)
reportData->mPxActorA = static_cast<const DeformableVolumeCore&>(actorCoreA).getPxActor();
else if (mActorA.getActorType() == PxActorType::eDEFORMABLE_SURFACE)
reportData->mPxActorA = static_cast<const DeformableSurfaceCore&>(actorCoreA).getPxActor();
else
#endif
reportData->mPxActorA = static_cast<const RigidCore&>(actorCoreA).getPxActor();
#if PX_SUPPORT_GPU_PHYSX
if (mActorB.getActorType() == PxActorType::eDEFORMABLE_VOLUME)
reportData->mPxActorB = static_cast<const DeformableVolumeCore&>(actorCoreB).getPxActor();
else if (mActorB.getActorType() == PxActorType::eDEFORMABLE_SURFACE)
reportData->mPxActorB = static_cast<const DeformableSurfaceCore&>(actorCoreB).getPxActor();
else
#endif
reportData->mPxActorB = static_cast<const RigidCore&>(actorCoreB).getPxActor();
}
}
}
#endif

View File

@@ -0,0 +1,167 @@
// 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.
#include "ScActorSim.h"
#include "ScActorCore.h"
#include "ScElementSim.h"
#include "ScScene.h"
#include "ScInteraction.h"
using namespace physx;
using namespace Sc;
static const PxFilterObjectType::Enum gFilterType[PxActorType::eACTOR_COUNT] =
{
PxFilterObjectType::eRIGID_STATIC, // PxActorType::eRIGID_STATIC
PxFilterObjectType::eRIGID_DYNAMIC, // PxActorType::eRIGID_DYNAMIC
PxFilterObjectType::eARTICULATION, // PxActorType::eARTICULATION_LINK
PxFilterObjectType::eDEFORMABLE_SURFACE,// PxActorType::eDEFORMABLE_SURFACE
PxFilterObjectType::eDEFORMABLE_VOLUME, // PxActorType::eDEFORMABLE_VOLUME
PxFilterObjectType::ePARTICLESYSTEM, // PxActorType::ePBD_PARTICLESYSTEM
};
static const PxU32 gFilterFlagEx[PxActorType::eACTOR_COUNT] =
{
PxFilterObjectFlagEx::eRIGID_STATIC, // PxActorType::eRIGID_STATIC
PxFilterObjectFlagEx::eRIGID_DYNAMIC, // PxActorType::eRIGID_DYNAMIC
PxFilterObjectFlagEx::eRIGID_DYNAMIC, // PxActorType::eARTICULATION_LINK
PxFilterObjectFlagEx::eNON_RIGID|PxFilterObjectFlagEx::eDEFORMABLE_SURFACE, // PxActorType::eDEFORMABLE_SURFACE
PxFilterObjectFlagEx::eNON_RIGID|PxFilterObjectFlagEx::eDEFORMABLE_VOLUME, // PxActorType::eDEFORMABLE_VOLUME
PxFilterObjectFlagEx::eNON_RIGID|PxFilterObjectFlagEx::ePARTICLESYSTEM, // PxActorType::ePBD_PARTICLESYSTEM
};
// PT: if this breaks, you need to update the above table
PX_COMPILE_TIME_ASSERT(PxActorType::eACTOR_COUNT==6);
// PT: make sure that the highest flag fits into 16bit
PX_COMPILE_TIME_ASSERT(PxFilterObjectFlagEx::eLAST<=0xffff);
Sc::ActorSim::ActorSim(Scene& scene, ActorCore& core) :
mScene (scene),
mCore (core),
mActiveListIndex (SC_NOT_IN_SCENE_INDEX),
mActiveCompoundListIndex(SC_NOT_IN_SCENE_INDEX),
mNodeIndex (PX_INVALID_NODE),
mInternalFlags (0)
{
core.setSim(this);
mId = scene.getActorIDTracker().createID();
{
PX_ASSERT(gFilterType[PxActorType::eRIGID_STATIC] == PxFilterObjectType::eRIGID_STATIC);
PX_ASSERT(gFilterType[PxActorType::eRIGID_DYNAMIC] == PxFilterObjectType::eRIGID_DYNAMIC);
PX_ASSERT(gFilterType[PxActorType::eARTICULATION_LINK] == PxFilterObjectType::eARTICULATION);
PX_ASSERT(gFilterType[PxActorType::eDEFORMABLE_SURFACE] == PxFilterObjectType::eDEFORMABLE_SURFACE);
PX_ASSERT(gFilterType[PxActorType::eDEFORMABLE_VOLUME] == PxFilterObjectType::eDEFORMABLE_VOLUME);
PX_ASSERT(gFilterType[PxActorType::ePBD_PARTICLESYSTEM] == PxFilterObjectType::ePARTICLESYSTEM);
const PxActorType::Enum actorType = getActorType();
PxFilterObjectAttributes filterAttr = 0;
setFilterObjectAttributeType(filterAttr, gFilterType[actorType]);
filterAttr |= gFilterFlagEx[actorType];
mFilterFlags = PxTo16(filterAttr);
}
}
Sc::ActorSim::~ActorSim()
{
mInteractions.releaseMem(*this);
mScene.getActorIDTracker().releaseID(mId);
}
void Sc::ActorSim::registerInteractionInActor(Interaction* interaction)
{
const PxU32 id = mInteractions.size();
mInteractions.pushBack(interaction, *this);
interaction->setActorId(this, id);
}
void Sc::ActorSim::unregisterInteractionFromActor(Interaction* interaction)
{
const PxU32 i = interaction->getActorId(this);
PX_ASSERT(i < mInteractions.size());
mInteractions.replaceWithLast(i);
if(i<mInteractions.size())
{
if(mInteractions[i]) // ### DEFENSIVE PT: for OM-122969
mInteractions[i]->setActorId(this, i);
else
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Sc::ActorSim::unregisterInteractionFromActor: found null interaction!");
}
}
void Sc::ActorSim::reallocInteractions(Sc::Interaction**& mem, PxU32& capacity, PxU32 size, PxU32 requiredMinCapacity)
{
Interaction** newMem;
PxU32 newCapacity;
if(requiredMinCapacity==0)
{
newCapacity = 0;
newMem = 0;
}
else if(requiredMinCapacity<=INLINE_INTERACTION_CAPACITY)
{
newCapacity = INLINE_INTERACTION_CAPACITY;
newMem = mInlineInteractionMem;
}
else
{
newCapacity = PxNextPowerOfTwo(requiredMinCapacity-1);
newMem = reinterpret_cast<Interaction**>(mScene.allocatePointerBlock(newCapacity));
}
PX_ASSERT(newCapacity >= requiredMinCapacity && requiredMinCapacity>=size);
if(mem)
{
PxMemCopy(newMem, mem, size*sizeof(Interaction*));
if(mem!=mInlineInteractionMem)
mScene.deallocatePointerBlock(reinterpret_cast<void**>(mem), capacity);
}
capacity = newCapacity;
mem = newMem;
}
void Sc::ActorSim::setActorsInteractionsDirty(InteractionDirtyFlag::Enum flag, const ActorSim* other, PxU8 interactionFlag)
{
PxU32 size = getActorInteractionCount();
Interaction** interactions = getActorInteractions();
while(size--)
{
Interaction* interaction = *interactions++;
if((!other || other == &interaction->getActorSim0() || other == &interaction->getActorSim1()) && (interaction->readInteractionFlag(interactionFlag)))
interaction->setDirty(flag);
}
}

View File

@@ -0,0 +1,223 @@
// 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_ACTOR_SIM_H
#define SC_ACTOR_SIM_H
#include "foundation/PxUserAllocated.h"
#include "CmPtrTable.h"
#include "CmUtils.h"
#include "PxActor.h"
#include "ScInteractionFlags.h"
#include "ScActorCore.h"
#include "PxsSimpleIslandManager.h"
#include "PxFiltering.h"
namespace physx
{
class PxActor;
namespace Sc
{
#define SC_NOT_IN_SCENE_INDEX 0xffffffff // the body is not in the scene yet
#define SC_NOT_IN_ACTIVE_LIST_INDEX 0xfffffffe // the body is in the scene but not in the active list
struct PxFilterObjectFlagEx : PxFilterObjectFlag
{
enum Enum
{
eRIGID_STATIC = eNEXT_FREE,
eRIGID_DYNAMIC = eNEXT_FREE<<1,
eNON_RIGID = eNEXT_FREE<<2,
eDEFORMABLE_SURFACE = eNEXT_FREE<<3,
eDEFORMABLE_VOLUME = eNEXT_FREE<<4,
ePARTICLESYSTEM = eNEXT_FREE<<5,
eLAST = ePARTICLESYSTEM
};
};
static const PxReal ScInternalWakeCounterResetValue = 20.0f*0.02f;
class Interaction;
class ElementSim;
class Scene;
class ShapeManager : public PxUserAllocated
{
public:
ShapeManager() {}
~ShapeManager() {}
PX_FORCE_INLINE PxU32 getNbElements() const
{
return mShapes.getCount();
}
PX_FORCE_INLINE ElementSim** getElements()
{
return reinterpret_cast<ElementSim**>(mShapes.getPtrs());
}
PX_FORCE_INLINE ElementSim*const* getElements() const
{
return reinterpret_cast<ElementSim*const*>(mShapes.getPtrs());
}
// void onElementAttach(ElementSim& element);
void onElementDetach(ElementSim& element);
Cm::PtrTable mShapes;
};
class ActorSim : public ShapeManager
{
friend class Scene; // the scene is allowed to set the scene array index
friend class Interaction;
PX_NOCOPY(ActorSim)
public:
enum InternalFlags
{
//BF_DISABLE_GRAVITY = 1 << 0, // Don't apply the scene's gravity
BF_HAS_STATIC_TOUCH = 1 << 1, // Set when a body is part of an island with static contacts. Needed to be able to recalculate adaptive force if this changes
BF_KINEMATIC_MOVED = 1 << 2, // Set when the kinematic was moved
BF_ON_DEATHROW = 1 << 3, // Set when the body is destroyed
BF_IS_IN_SLEEP_LIST = 1 << 4, // Set when the body is added to the list of bodies which were put to sleep
BF_IS_IN_WAKEUP_LIST = 1 << 5, // Set when the body is added to the list of bodies which were woken up
BF_SLEEP_NOTIFY = 1 << 6, // A sleep notification should be sent for this body (and not a wakeup event, even if the body is part of the woken list as well)
BF_WAKEUP_NOTIFY = 1 << 7, // A wake up notification should be sent for this body (and not a sleep event, even if the body is part of the sleep list as well)
BF_HAS_CONSTRAINTS = 1 << 8, // Set if the body has one or more constraints
BF_KINEMATIC_SETTLING = 1 << 9, // Set when the body was moved kinematically last frame
BF_KINEMATIC_SETTLING_2 = 1 << 10,
BF_KINEMATIC_MOVE_FLAGS = BF_KINEMATIC_MOVED | BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2, //Used to clear kinematic masks in 1 call
BF_KINEMATIC_SURFACE_VELOCITY = 1 << 11, //Set when the application calls setKinematicVelocity. Actor remains awake until application calls clearKinematicVelocity.
BF_IS_COMPOUND_RIGID = 1 << 12, // Set when the body is a compound actor, we dont want to set the sq bounds
// PT: WARNING: flags stored on 16-bits now.
};
ActorSim(Scene&, ActorCore&);
virtual ~ActorSim();
// Get the scene the actor resides in
PX_FORCE_INLINE Scene& getScene() const { return mScene; }
// Get the number of interactions connected to the actor
PX_FORCE_INLINE PxU32 getActorInteractionCount() const { return mInteractions.size(); }
// Get an iterator to the interactions connected to the actor
PX_FORCE_INLINE Interaction** getActorInteractions() const { return mInteractions.begin(); }
// Get the type ID of the actor
PX_FORCE_INLINE PxActorType::Enum getActorType() const { return mCore.getActorCoreType(); }
// Returns true if the actor is a dynamic rigid body (including articulation links)
PX_FORCE_INLINE PxU16 isDynamicRigid() const { return mFilterFlags & PxFilterObjectFlagEx::eRIGID_DYNAMIC; }
PX_FORCE_INLINE PxU16 isDeformableSurface() const { return mFilterFlags & PxFilterObjectFlagEx::eDEFORMABLE_SURFACE; }
PX_FORCE_INLINE PxU16 isDeformableVolume() const { return mFilterFlags & PxFilterObjectFlagEx::eDEFORMABLE_VOLUME; }
PX_FORCE_INLINE PxU16 isParticleSystem() const { return mFilterFlags & PxFilterObjectFlagEx::ePARTICLESYSTEM; }
PX_FORCE_INLINE PxU16 isNonRigid() const { return mFilterFlags & PxFilterObjectFlagEx::eNON_RIGID; }
PX_FORCE_INLINE PxU16 isStaticRigid() const { return mFilterFlags & PxFilterObjectFlagEx::eRIGID_STATIC; }
virtual void postActorFlagChange(PxU32, PxU32) {}
void setActorsInteractionsDirty(InteractionDirtyFlag::Enum flag, const ActorSim* other, PxU8 interactionFlag);
PX_FORCE_INLINE ActorCore& getActorCore() const { return mCore; }
PX_FORCE_INLINE bool isActive() const { return (mActiveListIndex < SC_NOT_IN_ACTIVE_LIST_INDEX); }
PX_FORCE_INLINE PxU32 getActiveListIndex() const { return mActiveListIndex; } // if the body is active, the index is smaller than SC_NOT_IN_ACTIVE_LIST_INDEX
PX_FORCE_INLINE void setActiveListIndex(PxU32 index) { mActiveListIndex = index; }
PX_FORCE_INLINE PxU32 getActiveCompoundListIndex() const { return mActiveCompoundListIndex; } // if the body is active and is compound, the index is smaller than SC_NOT_IN_ACTIVE_LIST_INDEX
PX_FORCE_INLINE void setActiveCompoundListIndex(PxU32 index) { mActiveCompoundListIndex = index; }
PX_FORCE_INLINE PxNodeIndex getNodeIndex() const { return mNodeIndex; }
PX_FORCE_INLINE PxU32 getActorID() const { return mId; }
PX_FORCE_INLINE PxU16 getInternalFlag() const { return mInternalFlags; }
PX_FORCE_INLINE PxU16 readInternalFlag(InternalFlags flag) const { return PxU16(mInternalFlags & flag); }
PX_FORCE_INLINE void raiseInternalFlag(InternalFlags flag) { mInternalFlags |= flag; }
PX_FORCE_INLINE void clearInternalFlag(InternalFlags flag) { mInternalFlags &= ~flag; }
PX_FORCE_INLINE PxFilterObjectAttributes getFilterAttributes() const { return PxFilterObjectAttributes(mFilterFlags); }
virtual PxActor* getPxActor() const = 0;
//This can all be removed and functionality can be subsumed by the island system, removing the need for this
//virtual call and any associated work
virtual void registerCountedInteraction() {}
virtual void unregisterCountedInteraction() {}
virtual PxU32 getNumCountedInteractions() const { return 0; }
virtual void internalWakeUp(PxReal wakeCounterValue = ScInternalWakeCounterResetValue) { PX_UNUSED(wakeCounterValue); }
private:
//These are called from interaction creation/destruction
void registerInteractionInActor(Interaction* interaction);
void unregisterInteractionFromActor(Interaction* interaction);
void reallocInteractions(Sc::Interaction**& mem, PxU32& capacity, PxU32 size, PxU32 requiredMinCapacity);
protected:
// dsequeira: interaction arrays are a major cause of small allocations, so we don't want to delegate them to the heap allocator
// it's not clear this inline array is really needed, we should take it out and see whether the cache perf is worse
static const PxU32 INLINE_INTERACTION_CAPACITY = 4;
Interaction* mInlineInteractionMem[INLINE_INTERACTION_CAPACITY];
Cm::OwnedArray<Sc::Interaction*, Sc::ActorSim, PxU32, &Sc::ActorSim::reallocInteractions>
mInteractions;
Scene& mScene;
ActorCore& mCore;
// Sleeping
PxU32 mActiveListIndex; // Used by Scene to track active bodies
PxU32 mActiveCompoundListIndex; // Used by Scene to track active compound bodies
// Island manager
PxNodeIndex mNodeIndex;
PxU32 mId; // PT: ID provided by Sc::Scene::mActorIDTracker
PxU16 mInternalFlags;
PxU16 mFilterFlags; // PT: PxFilterObjectAttributes. Capturing the type information in local flags here is redundant
// but avoids reading the Core memory from the Sim object, and is also faster to test multiple types at once.
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,274 @@
// 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.
#include "ScArticulationCore.h"
#include "ScPhysics.h"
#include "ScBodyCore.h"
#include "ScBodySim.h"
#include "ScArticulationSim.h"
using namespace physx;
Sc::ArticulationCore::ArticulationCore() :
mSim(NULL)
{
const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale();
mCore.solverIterationCounts = 1<<8 | 4;
mCore.sleepThreshold = 5e-5f * scale.speed * scale.speed;
mCore.freezeThreshold = 5e-6f * scale.speed * scale.speed;
mCore.wakeCounter = Physics::sWakeCounterOnCreation;
mCore.gpuRemapIndex = 0xffffffff;
}
Sc::ArticulationCore::~ArticulationCore()
{
}
//--------------------------------------------------------------
//
// ArticulationCore interface implementation
//
//--------------------------------------------------------------
void Sc::ArticulationCore::setWakeCounter(const PxReal v)
{
mCore.wakeCounter = v;
if (mSim)
{
mSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_WAKECOUNTER);
}
#if PX_DEBUG
if(mSim)
mSim->debugCheckWakeCounterOfLinks(v);
#endif
}
bool Sc::ArticulationCore::isSleeping() const
{
return mSim ? mSim->isSleeping() : (mCore.wakeCounter == 0.0f);
}
void Sc::ArticulationCore::wakeUp(PxReal wakeCounter)
{
mCore.wakeCounter = wakeCounter;
if (mSim)
{
Dy::FeatherstoneArticulation* arti = static_cast<Dy::FeatherstoneArticulation*>(mSim->getLowLevelArticulation());
arti->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_WAKECOUNTER);
}
#if PX_DEBUG
if(mSim)
mSim->debugCheckSleepStateOfLinks(false);
#endif
}
void Sc::ArticulationCore::putToSleep()
{
mCore.wakeCounter = 0.0f;
if (mSim)
{
Dy::FeatherstoneArticulation* arti = static_cast<Dy::FeatherstoneArticulation*>(mSim->getLowLevelArticulation());
arti->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_WAKECOUNTER);
}
#if PX_DEBUG
if(mSim)
mSim->debugCheckSleepStateOfLinks(true);
#endif
}
void Sc::ArticulationCore::setArticulationFlags(PxArticulationFlags flags)
{
mCore.flags = flags;
if(mSim)
{
mSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_USER_FLAGS);
const bool isFixedBaseLink = flags & PxArticulationFlag::eFIX_BASE;
mSim->setFixedBaseLink(isFixedBaseLink);
}
}
PxU32 Sc::ArticulationCore::getDofs() const
{
return mSim ? mSim->getDofs() : 0xFFFFFFFFu;
}
PxArticulationCache* Sc::ArticulationCore::createCache() const
{
return mSim ? mSim->createCache() : NULL;
}
PxU32 Sc::ArticulationCore::getCacheDataSize() const
{
return mSim ? mSim->getCacheDataSize() : 0xFFFFFFFFu;
}
void Sc::ArticulationCore::zeroCache(PxArticulationCache& cache) const
{
if(mSim)
mSim->zeroCache(cache);
}
bool Sc::ArticulationCore::applyCache(PxArticulationCache& cache, const PxArticulationCacheFlags flag) const
{
if(mSim)
return mSim->applyCache(cache, flag);
return false;
}
void Sc::ArticulationCore::copyInternalStateToCache(PxArticulationCache& cache, const PxArticulationCacheFlags flag, const bool isGpuSimEnabled) const
{
if(mSim)
mSim->copyInternalStateToCache(cache, flag, isGpuSimEnabled);
}
void Sc::ArticulationCore::packJointData(const PxReal* maximum, PxReal* reduced) const
{
if(mSim)
mSim->packJointData(maximum, reduced);
}
void Sc::ArticulationCore::unpackJointData(const PxReal* reduced, PxReal* maximum) const
{
if(mSim)
mSim->unpackJointData(reduced, maximum);
}
void Sc::ArticulationCore::commonInit() const
{
if(mSim)
mSim->commonInit();
}
void Sc::ArticulationCore::computeGeneralizedGravityForce(PxArticulationCache& cache, const bool rootMotion) const
{
if(mSim)
mSim->computeGeneralizedGravityForce(cache, rootMotion);
}
void Sc::ArticulationCore::computeCoriolisAndCentrifugalForce(PxArticulationCache& cache, const bool rootMotion) const
{
if(mSim)
mSim->computeCoriolisAndCentrifugalForce(cache, rootMotion);
}
void Sc::ArticulationCore::computeGeneralizedExternalForce(PxArticulationCache& cache) const
{
if(mSim)
mSim->computeGeneralizedExternalForce(cache);
}
void Sc::ArticulationCore::computeJointAcceleration(PxArticulationCache& cache) const
{
if(mSim)
mSim->computeJointAcceleration(cache);
}
void Sc::ArticulationCore::computeJointForce(PxArticulationCache& cache) const
{
if(mSim)
mSim->computeJointForce(cache);
}
void Sc::ArticulationCore::computeDenseJacobian(PxArticulationCache& cache, PxU32& nRows, PxU32& nCols) const
{
if(mSim)
mSim->computeDenseJacobian(cache, nRows, nCols);
}
void Sc::ArticulationCore::computeCoefficientMatrix(PxArticulationCache& cache) const
{
if(mSim)
mSim->computeCoefficientMatrix(cache);
}
bool Sc::ArticulationCore::computeLambda(PxArticulationCache& cache, PxArticulationCache& initialState, const PxReal* const jointTorque, const PxVec3 gravity, const PxU32 maxIter) const
{
return mSim ? mSim->computeLambda(cache, initialState, jointTorque, gravity, maxIter) : false;
}
void Sc::ArticulationCore::computeGeneralizedMassMatrix(PxArticulationCache& cache, const bool rootMotion) const
{
if(mSim)
mSim->computeGeneralizedMassMatrix(cache, rootMotion);
}
PxVec3 Sc::ArticulationCore::computeArticulationCOM(const bool rootFrame) const
{
return mSim ? mSim->computeArticulationCOM(rootFrame) : PxVec3(0.0f);
}
void Sc::ArticulationCore::computeCentroidalMomentumMatrix(PxArticulationCache& cache) const
{
if(mSim)
mSim->computeCentroidalMomentumMatrix(cache);
}
PxU32 Sc::ArticulationCore::getCoefficientMatrixSize() const
{
return mSim ? mSim->getCoefficientMatrixSize() : 0xFFFFFFFFu;
}
PxSpatialVelocity Sc::ArticulationCore::getLinkAcceleration(const PxU32 linkId, const bool isGpuSimEnabled) const
{
return mSim ? mSim->getLinkAcceleration(linkId, isGpuSimEnabled) : PxSpatialVelocity();
}
PxU32 Sc::ArticulationCore::getGpuArticulationIndex() const
{
return mSim ? mCore.gpuRemapIndex : 0xffffffff;
}
void Sc::ArticulationCore::updateKinematic(PxArticulationKinematicFlags flags)
{
PX_ASSERT(mSim);
if (mSim)
mSim->updateKinematic(flags);
}
PxNodeIndex Sc::ArticulationCore::getIslandNodeIndex() const
{
return mSim ? mSim->getIslandNodeIndex() : PxNodeIndex(PX_INVALID_NODE);
}
void Sc::ArticulationCore::setGlobalPose()
{
if(mSim)
mSim->setGlobalPose();
}

View File

@@ -0,0 +1,306 @@
// 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.
#include "ScArticulationJointCore.h"
#include "ScArticulationCore.h"
#include "ScArticulationSim.h"
#include "ScArticulationJointSim.h"
#include "ScBodyCore.h"
#include "ScPhysics.h"
using namespace physx;
Sc::ArticulationJointCore::ArticulationJointCore(const PxTransform& parentFrame, const PxTransform& childFrame) :
mCore (parentFrame, childFrame),
mSim (NULL),
mArticulation (NULL),
mRootType (NULL),
mLLLinkIndex (0xffffffff)
{
}
Sc::ArticulationJointCore::~ArticulationJointCore()
{
PX_ASSERT(getSim() == 0);
}
void Sc::ArticulationJointCore::setSimDirty()
{
Sc::ArticulationJointSim* sim = getSim();
if(sim)
sim->setDirty();
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
llarticulation->mJcalcDirty = true;
}
}
void Sc::ArticulationJointCore::setParentPose(const PxTransform& t)
{
// AD: we check if it changed at all to avoid marking the complete articulation dirty for a jcalc.
// The jcalc internally checks these ArticulationJointCoreDirtyFlag again so we would skip most things
// but we'd still check all the joints. The same is also true for the following functions.
if (!(mCore.parentPose == t))
{
mCore.parentPose = t;
setDirty();
}
}
void Sc::ArticulationJointCore::setChildPose(const PxTransform& t)
{
if (!(mCore.childPose == t))
{
mCore.childPose = t;
setDirty();
}
}
void Sc::ArticulationJointCore::setTargetP(PxArticulationAxis::Enum axis, PxReal targetP)
{
// this sets the target position in the core.
mCore.targetP[axis] = targetP;
// this sets the target position in the ll articulation. This needs to happen immediately because we might
// look up the value using the cache API again, and that one is reading directly from the llArticulation.
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
Dy::ArticulationData& data = llarticulation->getArticulationData();
Dy::ArticulationJointCoreData* jointData = data.getJointData();
Dy::ArticulationJointCoreData& jointDatum = jointData[mLLLinkIndex];
PxReal* jointTargetPositions = data.getJointTargetPositions();
PxReal* jTargetPosition = &jointTargetPositions[jointDatum.jointOffset];
const PxU32 dofId = mCore.invDofIds[axis];
if (dofId != 0xff)
{
jTargetPosition[dofId] = targetP;
artiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_JOINT_TARGET_POS);
}
}
// AD: does not need setDirty - we write directly into the llArticulation and the GPU part is
// handled by setArticulationDirty.
}
void Sc::ArticulationJointCore::setTargetV(PxArticulationAxis::Enum axis, PxReal targetV)
{
// this sets the target velocity in the core.
mCore.targetV[axis] = targetV;
// this sets the target velocity in the ll articulation. This needs to happen immediately because we might
// look up the value using the cache API again, and that one is reading directly from the llArticulation.
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
Dy::ArticulationData& data = llarticulation->getArticulationData();
Dy::ArticulationJointCoreData* jointData = data.getJointData();
Dy::ArticulationJointCoreData& jointDatum = jointData[mLLLinkIndex];
PxReal* jointTargetVelocities = data.getJointTargetVelocities();
PxReal* jTargetVelocity = &jointTargetVelocities[jointDatum.jointOffset];
const PxU32 dofId = mCore.invDofIds[axis];
if (dofId != 0xff)
{
jTargetVelocity[dofId] = targetV;
artiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_JOINT_TARGET_VEL);
}
}
// AD: does not need setDirty - we write directly into the llArticulation and the GPU part is
// handled by setArticulationDirty.
}
void Sc::ArticulationJointCore::setArmature(PxArticulationAxis::Enum axis, PxReal armature)
{
if (mCore.armature[axis] != armature)
{
mCore.armature[axis] = armature;
setSimDirty();
}
}
void Sc::ArticulationJointCore::setJointPosition(PxArticulationAxis::Enum axis, const PxReal jointPos)
{
// this sets the position in the core.
mCore.jointPos[axis] = jointPos;
// this sets the position in the ll articulation. This needs to happen immediately because we might
// look up the value using the cache API again, and that one is reading directly from the llArticulation.
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
Dy::ArticulationData& data = llarticulation->getArticulationData();
Dy::ArticulationJointCoreData* jointData = data.getJointData();
Dy::ArticulationJointCoreData& jointDatum = jointData[mLLLinkIndex];
PxReal* jointPositions = data.getJointPositions();
PxReal* jPosition = &jointPositions[jointDatum.jointOffset];
const PxU32 dofId = mCore.invDofIds[axis];
if (dofId != 0xff)
{
jPosition[dofId] = jointPos;
artiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_POSITIONS);
}
}
}
// AD: we need this indirection right now because we could have updated joint vel using the cache, so
// the read from the joint core might be stale.
PxReal Sc::ArticulationJointCore::getJointPosition(PxArticulationAxis::Enum axis) const
{
PxReal jointPos = mCore.jointPos[axis];
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
const Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
const Dy::ArticulationData& data = llarticulation->getArticulationData();
const Dy::ArticulationJointCoreData* jointData = data.getJointData();
const Dy::ArticulationJointCoreData& jointDatum = jointData[mLLLinkIndex];
const PxReal* jointPositions = data.getJointPositions();
const PxReal* jPosition = &jointPositions[jointDatum.jointOffset];
const PxU32 dofId = mCore.invDofIds[axis];
if(dofId != 0xff)
jointPos = jPosition[dofId];
}
return jointPos;
}
void Sc::ArticulationJointCore::setJointVelocity(PxArticulationAxis::Enum axis, const PxReal jointVel)
{
mCore.jointVel[axis] = jointVel;
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
Dy::ArticulationData& data = llarticulation->getArticulationData();
Dy::ArticulationJointCoreData* jointData = data.getJointData();
Dy::ArticulationJointCoreData& jointDatum = jointData[mLLLinkIndex];
PxReal* jointVelocities = data.getJointVelocities();
PxReal* jVelocity = &jointVelocities[jointDatum.jointOffset];
const PxU32 dofId = mCore.invDofIds[axis];
if (dofId != 0xff)
{
jVelocity[dofId] = jointVel;
artiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_VELOCITIES);
}
}
}
// AD: we need this indirection right now because we could have updated joint vel using the cache, so
// the read from the joint core might be stale.
PxReal Sc::ArticulationJointCore::getJointVelocity(PxArticulationAxis::Enum axis) const
{
PxReal jointVel = mCore.jointVel[axis];
ArticulationSim* artiSim = mArticulation->getSim();
if (artiSim && artiSim->isLLArticulationInitialized())
{
const Dy::FeatherstoneArticulation* llarticulation = artiSim->getLowLevelArticulation();
const Dy::ArticulationData& data = llarticulation->getArticulationData();
const Dy::ArticulationJointCoreData* jointData = data.getJointData();
const Dy::ArticulationJointCoreData& jointDatum = jointData[mLLLinkIndex];
const PxReal* jointVelocities = data.getJointVelocities();
const PxReal* jVelocities = &jointVelocities[jointDatum.jointOffset];
const PxU32 dofId = mCore.invDofIds[axis];
if (dofId != 0xff)
jointVel = jVelocities[dofId];
}
return jointVel;
}
void Sc::ArticulationJointCore::setLimit(PxArticulationAxis::Enum axis, const PxArticulationLimit& limit)
{
mCore.setLimit(axis, limit);
setSimDirty();
}
void Sc::ArticulationJointCore::setDrive(PxArticulationAxis::Enum axis, const PxArticulationDrive& drive)
{
mCore.setDrive(axis, drive);
setSimDirty();
}
void Sc::ArticulationJointCore::setFrictionCoefficient(PxReal frictionCoefficient)
{
mCore.setFrictionCoefficient(frictionCoefficient);
setSimDirty();
}
void Sc::ArticulationJointCore::setFrictionParams(PxArticulationAxis::Enum axis, const PxJointFrictionParams& jointFrictionParams)
{
mCore.setFrictionParams(axis, jointFrictionParams);
setSimDirty();
}
void Sc::ArticulationJointCore::setMaxJointVelocity(PxReal maxJointV)
{
mCore.setMaxJointVelocity(maxJointV);
setSimDirty();
}
void Sc::ArticulationJointCore::setMaxJointVelocity(PxArticulationAxis::Enum axis, PxReal maxJointV)
{
mCore.setMaxJointVelocity(axis, maxJointV);
setSimDirty();
}

View File

@@ -0,0 +1,97 @@
// 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.
#include "ScArticulationJointSim.h"
#include "ScArticulationJointCore.h"
#include "ScBodySim.h"
#include "ScScene.h"
#include "PxsRigidBody.h"
#include "ScArticulationSim.h"
#include "PxsSimpleIslandManager.h"
using namespace physx;
Sc::ArticulationJointSim::ArticulationJointSim(ArticulationJointCore& joint, ActorSim& parent, ActorSim& child) :
Interaction (parent, child, InteractionType::eARTICULATION, 0),
mCore (joint)
{
{
onActivate();
registerInActors();
}
BodySim& childBody = static_cast<BodySim&>(child),
& parentBody = static_cast<BodySim&>(parent);
parentBody.getArticulation()->addBody(childBody, &parentBody, this);
mCore.setSim(this);
}
Sc::ArticulationJointSim::~ArticulationJointSim()
{
// articulation interactions do not make use of the dirty flags yet. If they did, a setClean(true) has to be introduced here.
PX_ASSERT(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST));
PX_ASSERT(!getDirtyFlags());
unregisterFromActors();
mCore.setSim(NULL);
}
Sc::BodySim& Sc::ArticulationJointSim::getParent() const
{
return static_cast<BodySim&>(getActorSim0());
}
Sc::BodySim& Sc::ArticulationJointSim::getChild() const
{
return static_cast<BodySim&>(getActorSim1());
}
bool Sc::ArticulationJointSim::onActivate()
{
if(!(getParent().isActive() && getChild().isActive()))
return false;
raiseInteractionFlag(InteractionFlag::eIS_ACTIVE);
return true;
}
bool Sc::ArticulationJointSim::onDeactivate()
{
clearInteractionFlag(InteractionFlag::eIS_ACTIVE);
return true;
}
void Sc::ArticulationJointSim::setDirty()
{
Dy::ArticulationJointCore& llCore = mCore.getCore();
ArticulationSim* sim = mCore.getArticulation()->getSim();
sim->setJointDirty(llCore);
}

View File

@@ -0,0 +1,66 @@
// 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_ARTICULATION_JOINT_SIM_H
#define SC_ARTICULATION_JOINT_SIM_H
#include "ScInteraction.h"
namespace physx
{
namespace Sc
{
class ArticulationJointCore;
class BodySim;
class ArticulationJointSim : public Interaction
{
PX_NOCOPY(ArticulationJointSim)
public:
ArticulationJointSim(ArticulationJointCore& joint, ActorSim& parent, ActorSim& child);
~ArticulationJointSim();
bool onActivate();
bool onDeactivate();
PX_FORCE_INLINE ArticulationJointCore& getCore() const { return mCore; }
BodySim& getParent() const;
BodySim& getChild() const;
void setDirty();
private:
ArticulationJointCore& mCore;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,83 @@
// 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.
#include "ScArticulationMimicJointSim.h"
#include "ScArticulationMimicJointCore.h"
#include "PxArticulationReducedCoordinate.h"
#include "ScArticulationSim.h"
#include "PxArticulationReducedCoordinate.h"
#include "DyArticulationMimicJointCore.h"
namespace physx
{
Sc::ArticulationMimicJointSim::ArticulationMimicJointSim(ArticulationMimicJointCore& mimicJointCore, Scene& scene) :
mScene(scene), mCore(mimicJointCore),
mLLIndex(0xffffffff)
{
mimicJointCore.setSim(this);
mLLMimicJoint.axisA = mimicJointCore.mAxisA;
mLLMimicJoint.axisB = mimicJointCore.mAxisB;
mLLMimicJoint.gearRatio = mimicJointCore.mGearRatio;
mLLMimicJoint.offset = mimicJointCore.mOffset;
mLLMimicJoint.naturalFrequency = mimicJointCore.mNaturalFrequency;
mLLMimicJoint.dampingRatio = mimicJointCore.mDampingRatio;
}
Sc::ArticulationMimicJointSim::~ArticulationMimicJointSim()
{
mCore.setSim(NULL);
}
void Sc::ArticulationMimicJointSim::setGearRatio(const PxReal gearRatio)
{
mLLMimicJoint.gearRatio = gearRatio;
mArticulationSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_MIMIC_JOINT);
}
void Sc::ArticulationMimicJointSim::setOffset(const PxReal offset)
{
mLLMimicJoint.offset = offset;
mArticulationSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_MIMIC_JOINT);
}
void Sc::ArticulationMimicJointSim::setNaturalFrequency(const PxReal naturalFrequency)
{
mLLMimicJoint.naturalFrequency = naturalFrequency;
mArticulationSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_MIMIC_JOINT);
}
void Sc::ArticulationMimicJointSim::setDampingRatio(const PxReal dampingRatio)
{
mLLMimicJoint.dampingRatio = dampingRatio;
mArticulationSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_MIMIC_JOINT);
}
}

View File

@@ -0,0 +1,85 @@
// 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_ARTICULATION_MIMIC_JOINT_SIM_H
#define SC_ARTICULATION_MIMIC_JOINT_SIM_H
#include "foundation/PxUserAllocated.h"
#include "PxArticulationReducedCoordinate.h"
#include "DyFeatherstoneArticulation.h"
#include "DyArticulationMimicJointCore.h"
namespace physx
{
namespace Sc
{
class Scene;
class ArticulationMimicJointCore;
class ArticulationCore;
class ArticulationSim;
class ArticulationMimicJointSim : public PxUserAllocated
{
PX_NOCOPY(ArticulationMimicJointSim)
public:
ArticulationMimicJointSim(Sc::ArticulationMimicJointCore& core, Sc::Scene& scene);
~ArticulationMimicJointSim();
PX_FORCE_INLINE Sc::Scene& getScene() { return mScene; }
PX_FORCE_INLINE const Sc::Scene& getScene() const { return mScene; }
PX_FORCE_INLINE void setLowLevelIndex(const PxU32 llIndex) { mLLIndex = llIndex;}
PX_FORCE_INLINE PxU32 getLowLevelIndex() const { return mLLIndex; }
PX_FORCE_INLINE Sc::ArticulationMimicJointCore& getCore() { return mCore; }
PX_FORCE_INLINE const Sc::ArticulationMimicJointCore& getCore() const { return mCore; }
PX_FORCE_INLINE Dy::ArticulationMimicJointCore& getLLMimicJoint() { return mLLMimicJoint; }
void setGearRatio(const PxReal gearRatio);
void setOffset(const PxReal offset);
void setNaturalFrequency(const PxReal naturalFrequency);
void setDampingRatio(const PxReal dampingRatio);
Sc::Scene& mScene;
Sc::ArticulationMimicJointCore& mCore;
Sc::ArticulationSim* mArticulationSim;
Dy::ArticulationMimicJointCore mLLMimicJoint;
PxU32 mLLIndex;
};
}
}
#endif //SC_ARTICULATION_MIMIC_JOINT_SIM_H

View File

@@ -0,0 +1,825 @@
// 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.
#include "ScArticulationSim.h"
#include "ScArticulationCore.h"
#include "ScArticulationJointSim.h"
#include "ScArticulationJointCore.h"
#include "ScBodySim.h"
#include "ScConstraintSim.h"
#include "ScArticulationTendonSim.h"
#include "ScArticulationMimicJointSim.h"
#include "ScScene.h"
#include "DyConstraint.h"
#include "DyFeatherstoneArticulation.h"
#include "PxsContext.h"
#include "CmSpatialVector.h"
#include "foundation/PxVecMath.h"
#include "PxsSimpleIslandManager.h"
#include "ScShapeSim.h"
#include "PxsSimulationController.h"
#include "DyIslandManager.h"
using namespace physx;
using namespace Dy;
using namespace Sc;
using namespace IG;
ArticulationSim* Sc::getArticulationSim(const IslandSim& islandSim, PxNodeIndex nodeIndex)
{
void* userData = getArticulationFromIG(islandSim, nodeIndex)->getUserData();
return reinterpret_cast<ArticulationSim*>(userData);
}
Sc::ArticulationSim::ArticulationSim(ArticulationCore& core, Scene& scene, BodyCore& root) :
mLLArticulation (NULL),
mScene (scene),
mCore (core),
mLinks ("ScArticulationSim::links"),
mBodies ("ScArticulationSim::bodies"),
mJoints ("ScArticulationSim::joints"),
mMaxDepth (0),
mIsLLArticulationInitialized(false)
{
mLinks.reserve(16);
mJoints.reserve(16);
mBodies.reserve(16);
mLLArticulation = mScene.createLLArticulation(this);
mIslandNodeIndex = scene.getSimpleIslandManager()->addNode(false, false, IG::Node::eARTICULATION_TYPE, mLLArticulation);
if(!mLLArticulation)
{
PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Articulation: could not allocate low-level resources.");
return;
}
PX_ASSERT(root.getSim());
addBody(*root.getSim(), NULL, NULL);
mCore.setSim(this);
mLLArticulation->setDyContext(mScene.getDynamicsContext());
mLLArticulation->getSolverDesc().initData(&core.getCore(), NULL);
//mLLArticulation->onUpdateSolverDesc();
}
Sc::ArticulationSim::~ArticulationSim()
{
if (!mLLArticulation)
return;
mScene.destroyLLArticulation(*mLLArticulation);
mScene.getSimpleIslandManager()->removeNode(mIslandNodeIndex);
mCore.setSim(NULL);
}
PxU32 Sc::ArticulationSim::findBodyIndex(BodySim& body) const
{
for(PxU32 i=0; i<mBodies.size(); i++)
{
if(mBodies[i]==&body)
return i;
}
PX_ASSERT(0);
return 0x80000000;
}
void Sc::ArticulationSim::addLoopConstraint(ConstraintSim* constraintSim)
{
const PxU32 size = mLoopConstraints.size();
if (size < mLoopConstraints.size())
mLoopConstraints.reserve(size*2 + 1);
BodySim* bodySim0 = constraintSim->getBody(0);
BodySim* bodySim1 = constraintSim->getBody(1);
ArticulationLoopConstraint lConstraint;
if (bodySim0)
lConstraint.linkIndex0 = findBodyIndex(*bodySim0);
else
lConstraint.linkIndex0 = 0x80000000;
if(bodySim1)
lConstraint.linkIndex1 = findBodyIndex(*bodySim1);
else
lConstraint.linkIndex1 = 0x80000000;
lConstraint.constraint = &constraintSim->getLowLevelConstraint();
mLoopConstraints.pushBack(lConstraint);
}
void Sc::ArticulationSim::removeLoopConstraint(ConstraintSim* constraintSim)
{
Dy::Constraint* constraint = &constraintSim->getLowLevelConstraint();
const PxU32 size = mLoopConstraints.size();
PxU32 index = 0;
while (index < size && mLoopConstraints[index].constraint != constraint)
++index;
if (index != size)
mLoopConstraints.replaceWithLast(index);
}
void Sc::ArticulationSim::updateCached(PxBitMapPinned* shapeChangedMap)
{
for(PxU32 i=0; i<mBodies.size(); i++)
mBodies[i]->updateCached(shapeChangedMap);
}
void Sc::ArticulationSim::markShapesUpdated(PxBitMapPinned* shapeChangedMap)
{
for (PxU32 a = 0; a < mBodies.size(); ++a)
{
PxU32 nbElems = mBodies[a]->getNbElements();
ElementSim** elems = mBodies[a]->getElements();
while (nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
if (sim->isInBroadPhase())
shapeChangedMap->growAndSet(sim->getElementID());
}
}
}
void Sc::ArticulationSim::addBody(BodySim& body, BodySim* parent, ArticulationJointSim* joint)
{
mBodies.pushBack(&body);
mJoints.pushBack(joint);
mLLArticulation->addBody();
const PxU32 index = mLinks.size();
PX_ASSERT((((index==0) && (joint == 0)) && (parent == 0)) ||
(((index!=0) && joint) && (parent && (parent->getArticulation() == this))));
ArticulationLink& link = mLinks.insert();
link.bodyCore = &body.getBodyCore().getCore();
link.mPathToRootStartIndex = 0;
link.mPathToRootCount = 0;
link.mChildrenStartIndex = 0xffffffff;
link.mNumChildren = 0;
bool shouldSleep;
bool currentlyAsleep;
const bool bodyReadyForSleep = body.checkSleepReadinessBesidesWakeCounter();
const PxReal wakeCounter = getCore().getWakeCounter();
if(parent)
{
currentlyAsleep = !mBodies[0]->isActive();
shouldSleep = currentlyAsleep && bodyReadyForSleep;
PxU32 parentIndex = findBodyIndex(*parent);
link.parent = parentIndex;
ArticulationLink& parentLink = mLinks[parentIndex];
link.inboundJoint = &joint->getCore().getCore();
if (parentLink.mChildrenStartIndex == 0xffffffff)
parentLink.mChildrenStartIndex = index;
parentLink.mNumChildren++;
}
else
{
currentlyAsleep = (wakeCounter == 0.0f);
shouldSleep = currentlyAsleep && bodyReadyForSleep;
link.parent = DY_ARTICULATION_LINK_NONE;
link.inboundJoint = NULL;
}
if(currentlyAsleep && !shouldSleep)
{
for(PxU32 i=0; i < (mBodies.size() - 1); i++)
mBodies[i]->internalWakeUpArticulationLink(wakeCounter);
}
body.setArticulation(this, wakeCounter, shouldSleep, index);
}
void Sc::ArticulationSim::removeBody(BodySim& body)
{
for (PxU32 i = 0; i < mBodies.size(); ++i)
{
if (mBodies[i] == &body)
{
mBodies.replaceWithLast(i);
mJoints.replaceWithLast(i);
break;
}
}
}
void Sc::ArticulationSim::addTendon(ArticulationSpatialTendonSim* const tendonSim)
{
tendonSim->mArtiSim = this;
const PxU32 index = mSpatialTendons.size();
Dy::ArticulationSpatialTendon& llTendon = tendonSim->mLLTendon;
llTendon.setTendonIndex(index);
mSpatialTendons.pushBack(&llTendon);
//mSpatialTendons.pushBack(&tendonSim->mLLTendon);
}
void Sc::ArticulationSim::addTendon(ArticulationFixedTendonSim* const tendonSim)
{
tendonSim->mArtiSim = this;
const PxU32 index = mFixedTendons.size();
Dy::ArticulationFixedTendon& llTendon = tendonSim->mLLTendon;
llTendon.setTendonIndex(index);
mFixedTendons.pushBack(&llTendon);
}
void Sc::ArticulationSim::addMimicJoint(ArticulationMimicJointSim* const mimicJointSim, const PxU32 linkA, const PxU32 linkB)
{
const PxU32 index = mMimicJoints.size();
mimicJointSim->setLowLevelIndex(index);
mimicJointSim->mArticulationSim = this;
Dy::ArticulationMimicJointCore& llMimicJoint = mimicJointSim->getLLMimicJoint();
llMimicJoint.linkA = linkA;
llMimicJoint.linkB = linkB;
mMimicJoints.pushBack(&llMimicJoint);
}
void Sc::ArticulationSim::createLLStructure()
{
if(!mBodies.size())
return;
mLLArticulation->setupLinks(mLinks.size(), mLinks.begin());
mLLArticulation->assignTendons(mSpatialTendons.size(), mSpatialTendons.begin());
mLLArticulation->assignTendons(mFixedTendons.size(), mFixedTendons.begin());
mLLArticulation->assignMimicJoints(mMimicJoints.size(), mMimicJoints.begin());
mIsLLArticulationInitialized = true;
}
void Sc::ArticulationSim::initializeConfiguration()
{
Dy::ArticulationData& data = mLLArticulation->getArticulationData();
mLLArticulation->jcalc(data);
mLLArticulation->mJcalcDirty = false;
Dy::ArticulationLink* links = data.getLinks();
Dy::ArticulationJointCoreData* jointData = data.getJointData();
const PxU32 linkCount = data.getLinkCount();
PxReal* jointVelocites = data.getJointVelocities();
PxReal* jointPositions = data.getJointPositions();
PxReal* jointTargetPositions = data.getJointTargetPositions();
PxReal* jointTargetVelocities = data.getJointTargetVelocities();
for (PxU32 linkID = 1; linkID < linkCount; ++linkID)
{
Dy::ArticulationLink& link = links[linkID];
Dy::ArticulationJointCore* joint = link.inboundJoint;
Dy::ArticulationJointCoreData& jointDatum = jointData[linkID];
PxReal* jPositions = &jointPositions[jointDatum.jointOffset];
PxReal* jVelocites = &jointVelocites[jointDatum.jointOffset];
PxReal* jTargetPositions = &jointTargetPositions[jointDatum.jointOffset];
PxReal* jTargetVelocities = &jointTargetVelocities[jointDatum.jointOffset];
for (PxU8 i = 0; i < jointDatum.nbDof; ++i)
{
const PxU32 dofId = joint->dofIds[i];
jPositions[i] = joint->jointPos[dofId];
jVelocites[i] = joint->jointVel[dofId];
jTargetPositions[i] = joint->targetP[dofId];
jTargetVelocities[i] = joint->targetV[dofId];
}
}
PxU32 flags = (Dy::ArticulationDirtyFlag::eDIRTY_POSITIONS |
Dy::ArticulationDirtyFlag::eDIRTY_VELOCITIES |
Dy::ArticulationDirtyFlag::eDIRTY_JOINT_TARGET_POS |
Dy::ArticulationDirtyFlag::eDIRTY_JOINT_TARGET_VEL);
mLLArticulation->raiseGPUDirtyFlag(Dy::ArticulationDirtyFlag::Enum(flags));
mLLArticulation->initPathToRoot();
}
void Sc::ArticulationSim::updateKinematic(PxArticulationKinematicFlags flags)
{
Dy::ArticulationData& data = mLLArticulation->getArticulationData();
if (mLLArticulation->mJcalcDirty)
{
mLLArticulation->jcalc(data);
mLLArticulation->mJcalcDirty = false;
}
if ((flags & PxArticulationKinematicFlag::ePOSITION))
{
mLLArticulation->raiseGPUDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_POSITIONS);
mLLArticulation->teleportLinks(data);
}
if ((flags & PxArticulationKinematicFlag::ePOSITION) ||
(flags & PxArticulationKinematicFlag::eVELOCITY))
{
mLLArticulation->raiseGPUDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_VELOCITIES);
mLLArticulation->computeLinkVelocities(data);
}
}
void Sc::ArticulationSim::copyJointStatus(const PxU32 linkID)
{
Dy::ArticulationData& data = mLLArticulation->getArticulationData();
Dy::ArticulationLink* links = data.getLinks();
Dy::ArticulationJointCoreData* jointData = data.getJointData();
Dy::ArticulationLink& link = links[linkID];
Dy::ArticulationJointCore* joint = link.inboundJoint;
Dy::ArticulationJointCoreData& jointDatum = jointData[linkID];
PxReal* jointVelocites = data.getJointVelocities();
PxReal* jointPositions = data.getJointPositions();
PxReal* jVelocities = &jointVelocites[jointDatum.jointOffset];
PxReal* jPositions = &jointPositions[jointDatum.jointOffset];
for(PxU8 i = 0; i < jointDatum.nbDof; ++i)
{
const PxU32 dofId = joint->dofIds[i];
joint->jointPos[dofId] = jPositions[i];
joint->jointVel[dofId] = jVelocities[i];
}
}
void Sc::ArticulationSim::updateCCDLinks(PxArray<BodySim*>& sims)
{
for (PxU32 a = 0; a < mBodies.size(); ++a)
{
if (mBodies[a]->getLowLevelBody().getCore().mFlags & PxRigidBodyFlag::eENABLE_CCD)
{
sims.pushBack(mBodies[a]);
}
}
}
void Sc::ArticulationSim::putToSleep()
{
for (PxU32 i = 0; i < mLinks.size(); i++)
{
BodySim* bodySim = mBodies[i];
PxsRigidBody& rigid = bodySim->getLowLevelBody();
PxsBodyCore& bodyCore = bodySim->getBodyCore().getCore();
//rigid.setPose(rigid.getLastCCDTransform());
//KS - the IG deactivates bodies in parallel with the solver. It appears that under certain circumstances, the solver's integration (which performs
//sleep checks) could decide that the body is no longer a candidate for sleeping on the same frame that the island gen decides to deactivate the island
//that the body is contained in. This is a rare occurrence but the behavior we want to emulate is that of IG running before solver so we should therefore
//permit the IG to make the authoritative decision over whether the body should be active or inactive.
bodyCore.wakeCounter = 0.0f;
bodyCore.linearVelocity = PxVec3(0.0f);
bodyCore.angularVelocity = PxVec3(0.0f);
rigid.clearAllFrameFlags();
//Force update
}
mScene.getSimulationController()->updateArticulation(mLLArticulation, mIslandNodeIndex);
}
void Sc::ArticulationSim::sleepCheck(PxReal dt)
{
if(!mBodies.size())
return;
#if PX_CHECKED
{
PxReal maxTimer = 0.0f, minTimer = PX_MAX_F32;
bool allActive = true, noneActive = true;
PX_UNUSED(allActive);
PX_UNUSED(noneActive);
for(PxU32 i=0;i<mLinks.size();i++)
{
PxReal timer = mBodies[i]->getBodyCore().getWakeCounter();
maxTimer = PxMax(maxTimer, timer);
minTimer = PxMin(minTimer, timer);
bool active = mBodies[i]->isActive();
allActive &= active;
noneActive &= !active;
}
// either all links are asleep, or no links are asleep
PX_ASSERT(maxTimer==0 || minTimer!=0);
PX_ASSERT(allActive || noneActive);
}
#endif
if(!mBodies[0]->isActive())
return;
const PxReal sleepThreshold = getCore().getCore().sleepThreshold;
PxReal maxTimer = 0.0f , minTimer = PX_MAX_F32;
for(PxU32 i=0;i<mLinks.size();i++)
{
const Cm::SpatialVector& motionVelocity = mLLArticulation->getMotionVelocity(i);
PxReal timer = mBodies[i]->updateWakeCounter(dt, sleepThreshold, motionVelocity);
maxTimer = PxMax(maxTimer, timer);
minTimer = PxMin(minTimer, timer);
}
mCore.setWakeCounterInternal(maxTimer);
if(maxTimer != 0.0f)
{
if(minTimer == 0.0f)
{
// make sure nothing goes to sleep unless everything does
for(PxU32 i=0;i<mLinks.size();i++)
mBodies[i]->getBodyCore().setWakeCounterFromSim(PxMax(1e-6f, mBodies[i]->getBodyCore().getWakeCounter()));
}
return;
}
for(PxU32 i=0;i<mLinks.size();i++)
{
mBodies[i]->notifyReadyForSleeping();
mBodies[i]->getLowLevelBody().resetSleepFilter();
}
mScene.getSimpleIslandManager()->deactivateNode(mIslandNodeIndex);
}
bool Sc::ArticulationSim::isSleeping() const
{
return (mBodies.size() > 0) ? (!mBodies[0]->isActive()) : true;
}
void Sc::ArticulationSim::internalWakeUp(PxReal wakeCounter)
{
if(mCore.getWakeCounter() < wakeCounter)
{
mCore.setWakeCounterInternal(wakeCounter);
for(PxU32 i=0;i<mBodies.size();i++)
mBodies[i]->internalWakeUpArticulationLink(wakeCounter);
}
}
void Sc::ArticulationSim::updateForces(PxReal dt)
{
PxU32 count = 0;
bool anyForcesApplied = false;
for(PxU32 i=0;i<mBodies.size();i++)
{
if (i+1 < mBodies.size())
{
PxPrefetchLine(mBodies[i+1],128);
PxPrefetchLine(mBodies[i+1],256);
}
anyForcesApplied |= mBodies[i]->updateForces(dt, NULL, NULL, count, &mLLArticulation->getSolverDesc().acceleration[i], NULL);
}
if(anyForcesApplied)
mLLArticulation->raiseGPUDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_EXT_ACCEL);
}
void Sc::ArticulationSim::clearAcceleration(PxReal dt)
{
PxU32 count = 0;
bool anyBodyRetains = false;
for (PxU32 i = 0; i < mBodies.size(); i++)
{
if (i + 1 < mBodies.size())
{
PxPrefetchLine(mBodies[i + 1], 128);
PxPrefetchLine(mBodies[i + 1], 256);
}
const bool accDirty = mBodies[i]->readVelocityModFlag(VMF_ACC_DIRTY);
// the code restores the pre-impulse state:
// if we only applied an impulse and no acceleration, we clear the acceleration here.
// if we applied an acceleration, we re-apply the acceleration terms we have in the velMod.
// we cleared out the impulse here when we pushed the data at the start of the sim.
if (!accDirty)
{
mLLArticulation->getSolverDesc().acceleration[i].linear = PxVec3(0.f);
mLLArticulation->getSolverDesc().acceleration[i].angular = PxVec3(0.f);
}
else
{
mBodies[i]->updateForces(dt, NULL, NULL, count, &mLLArticulation->getSolverDesc().acceleration[i], NULL);
}
// we need to raise the dirty flag if retain accelerations is on
// because in that case we need to restore the acceleration without impulses. We
// can only do that using the CPU->GPU codepath because we don't distinguish between
// acceleration and impulses on the GPU.
// The flag must be raised here because we don't know at the start of the next sim step
// that the data in velMod is actually valid and the articulation would not be added
// to the dirty list.
// without retain accelerations, the accelerations are cleared directly on the GPU.
if (mBodies[i]->getFlagsFast() & PxRigidBodyFlag::eRETAIN_ACCELERATIONS)
anyBodyRetains = true;
}
if (anyBodyRetains)
{
mScene.getSimulationController()->updateArticulationExtAccel(mLLArticulation, mIslandNodeIndex);
}
}
void Sc::ArticulationSim::saveLastCCDTransform()
{
for(PxU32 i=0;i<mBodies.size();i++)
{
if (i+1 < mBodies.size())
{
PxPrefetchLine(mBodies[i+1],128);
PxPrefetchLine(mBodies[i+1],256);
}
mBodies[i]->getLowLevelBody().saveLastCCDTransform();
}
}
void Sc::ArticulationSim::setFixedBaseLink(bool value)
{
const PxU32 linkCount = mLinks.size();
if(linkCount > 0)
mLinks[0].bodyCore->fixedBaseLink = PxU8(value);
}
PxU32 Sc::ArticulationSim::getDofs() const
{
return mLLArticulation->getDofs();
}
PxU32 Sc::ArticulationSim::getDof(const PxU32 linkID) const
{
return mLLArticulation->getDof(linkID);
}
PX_COMPILE_TIME_ASSERT(sizeof(Cm::SpatialVector)==sizeof(PxSpatialForce));
PxArticulationCache* Sc::ArticulationSim::createCache()
{
return FeatherstoneArticulation::createCache(getDofs(), mLinks.size());
}
PxU32 Sc::ArticulationSim::getCacheDataSize() const
{
return FeatherstoneArticulation::getCacheDataSize(getDofs(), mLinks.size());
}
void Sc::ArticulationSim::zeroCache(PxArticulationCache& cache) const
{
const PxU32 cacheDataSize = getCacheDataSize();
PxMemZero(cache.externalForces, cacheDataSize);
}
//copy external data to internal data
bool Sc::ArticulationSim::applyCache(PxArticulationCache& cache, const PxArticulationCacheFlags flag) const
{
//checkResize();
bool shouldWake = false;
if (mLLArticulation->applyCache(cache, flag, shouldWake))
{
mScene.getSimulationController()->updateArticulation(mLLArticulation, mIslandNodeIndex);
}
return shouldWake;
}
//copy internal data to external data
void Sc::ArticulationSim::copyInternalStateToCache(PxArticulationCache& cache, const PxArticulationCacheFlags flag, const bool isGpuSimEnabled) const
{
mLLArticulation->copyInternalStateToCache(cache, flag, isGpuSimEnabled);
}
void Sc::ArticulationSim::packJointData(const PxReal* maximum, PxReal* reduced) const
{
mLLArticulation->packJointData(maximum, reduced);
}
void Sc::ArticulationSim::unpackJointData(const PxReal* reduced, PxReal* maximum) const
{
mLLArticulation->unpackJointData(reduced, maximum);
}
void Sc::ArticulationSim::commonInit()
{
mLLArticulation->initializeCommonData();
}
void Sc::ArticulationSim::computeGeneralizedGravityForce(PxArticulationCache& cache, const bool rootMotion)
{
mLLArticulation->getGeneralizedGravityForce(mScene.getGravity(), cache, rootMotion);
}
void Sc::ArticulationSim::computeCoriolisAndCentrifugalForce(PxArticulationCache& cache, const bool rootMotion)
{
mLLArticulation->getCoriolisAndCentrifugalForce(cache, rootMotion);
}
void Sc::ArticulationSim::computeGeneralizedExternalForce(PxArticulationCache& cache)
{
mLLArticulation->getGeneralizedExternalForce(cache);
}
void Sc::ArticulationSim::computeJointAcceleration(PxArticulationCache& cache)
{
mLLArticulation->getJointAcceleration(mScene.getGravity(), cache);
}
void Sc::ArticulationSim::computeJointForce(PxArticulationCache& cache)
{
mLLArticulation->getJointForce(cache);
}
void Sc::ArticulationSim::computeDenseJacobian(PxArticulationCache& cache, PxU32& nRows, PxU32& nCols)
{
mLLArticulation->getDenseJacobian(cache, nRows, nCols);
}
void Sc::ArticulationSim::computeCoefficientMatrix(PxArticulationCache& cache)
{
mLLArticulation->getCoefficientMatrixWithLoopJoints(mLoopConstraints.begin(), mLoopConstraints.size(), cache);
}
bool Sc::ArticulationSim::computeLambda(PxArticulationCache& cache, PxArticulationCache& initialState,
const PxReal* const jointTorque, const PxVec3 gravity, const PxU32 maxIter)
{
const PxReal invLengthScale = 1.f / mScene.getLengthScale();
return mLLArticulation->getLambda(mLoopConstraints.begin(), mLoopConstraints.size(), cache, initialState, jointTorque, gravity, maxIter, invLengthScale);
}
void Sc::ArticulationSim::computeGeneralizedMassMatrix(PxArticulationCache& cache, const bool rootMotion)
{
mLLArticulation->getGeneralizedMassMatrixCRB(cache, rootMotion);
/*const PxU32 totalDofs = mLLArticulation->getDofs();
PxReal* massMatrix = reinterpret_cast<PxReal*>(PX_ALLOC(sizeof(PxReal) * totalDofs * totalDofs, "MassMatrix"));
PxMemCopy(massMatrix, cache.massMatrix, sizeof(PxReal)*totalDofs * totalDofs);
mLLArticulation->getGeneralizedMassMatrix(cache);
PxReal* massMatrix1 = cache.massMatrix;
for (PxU32 i = 0; i < totalDofs; ++i)
{
PxReal* row = &massMatrix1[i * totalDofs];
for (PxU32 j = 0; j < totalDofs; ++j)
{
const PxReal dif = row[j] - massMatrix[j*totalDofs + i];
PX_ASSERT (PxAbs(dif) < 2e-4f)
}
}
PX_FREE(massMatrix);*/
}
PxVec3 Sc::ArticulationSim::computeArticulationCOM(const bool rootFrame)
{
return mLLArticulation->getArticulationCOM(rootFrame);
}
void Sc::ArticulationSim::computeCentroidalMomentumMatrix(PxArticulationCache& cache)
{
mLLArticulation->getCentroidalMomentumMatrix(cache);
}
PxU32 Sc::ArticulationSim::getCoefficientMatrixSize() const
{
const PxU32 size = mLoopConstraints.size();
const PxU32 totalDofs = mLLArticulation->getDofs();
return size * totalDofs;
}
void Sc::ArticulationSim::setRootLinearVelocity(const PxVec3& velocity)
{
mLLArticulation->setRootLinearVelocity(velocity);
}
void Sc::ArticulationSim::setRootAngularVelocity(const PxVec3& velocity)
{
mLLArticulation->setRootAngularVelocity(velocity);
}
PxSpatialVelocity Sc::ArticulationSim::getLinkVelocity(const PxU32 linkId) const
{
Cm::SpatialVector vel = mLLArticulation->getLinkScalarVelocity(linkId);
return reinterpret_cast<PxSpatialVelocity&>(vel);
}
PxSpatialVelocity Sc::ArticulationSim::getLinkAcceleration(const PxU32 linkId, const bool isGpuSimEnabled) const
{
Cm::SpatialVector accel = mLLArticulation->getMotionAcceleration(linkId, isGpuSimEnabled);
return reinterpret_cast<PxSpatialVelocity&>(accel);
}
// This method allows user teleport the root links and the articulation
//system update all other links pose
void Sc::ArticulationSim::setGlobalPose()
{
mLLArticulation->teleportRootLink();
}
void Sc::ArticulationSim::setJointDirty(Dy::ArticulationJointCore& jointCore)
{
PX_UNUSED(jointCore);
mScene.getSimulationController()->updateArticulationJoint(mLLArticulation, mIslandNodeIndex);
}
void Sc::ArticulationSim::setArticulationDirty(PxU32 flag)
{
Dy::FeatherstoneArticulation* featherstoneArtic = static_cast<Dy::FeatherstoneArticulation*>(mLLArticulation);
featherstoneArtic->raiseGPUDirtyFlag(Dy::ArticulationDirtyFlag::Enum(flag));
mScene.getSimulationController()->updateArticulation(mLLArticulation, mIslandNodeIndex);
}
void Sc::ArticulationSim::debugCheckWakeCounterOfLinks(PxReal wakeCounter) const
{
PX_UNUSED(wakeCounter);
#if PX_DEBUG
// make sure the links are in sync with the articulation
for(PxU32 i=0; i < mBodies.size(); i++)
{
PX_ASSERT(mBodies[i]->getBodyCore().getWakeCounter() == wakeCounter);
}
#endif
}
void Sc::ArticulationSim::debugCheckSleepStateOfLinks(bool isSleeping) const
{
PX_UNUSED(isSleeping);
#if PX_DEBUG
// make sure the links are in sync with the articulation
for(PxU32 i=0; i < mBodies.size(); i++)
{
if (isSleeping)
{
PX_ASSERT(!mBodies[i]->isActive());
PX_ASSERT(mBodies[i]->getBodyCore().getWakeCounter() == 0.0f);
PX_ASSERT(mBodies[i]->checkSleepReadinessBesidesWakeCounter());
}
else
PX_ASSERT(mBodies[i]->isActive());
}
#endif
}
PxU32 Sc::ArticulationSim::getRootActorIndex() const
{
return mBodies[0]->getActorID();
}

View File

@@ -0,0 +1,228 @@
// 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_ARTICULATION_SIM_H
#define SC_ARTICULATION_SIM_H
#include "foundation/PxUserAllocated.h"
#include "ScArticulationCore.h"
#include "PxsSimpleIslandManager.h"
#include "DyArticulationTendon.h"
namespace physx
{
namespace Bp
{
class BoundsArray;
}
namespace Sc
{
class BodySim;
class BodyCore;
class ArticulationJointSim;
class ArticulationSpatialTendonSim;
class ArticulationFixedTendonSim;
class ArticulationMimicJointSim;
class ArticulationCore;
class Scene;
class ConstraintSim;
struct ArticulationSimDirtyFlag
{
enum Enum
{
eNONE = 0,
eUPDATE = 1 << 0
};
};
typedef PxFlags<ArticulationSimDirtyFlag::Enum, PxU32> ArticulationSimDirtyFlags;
class ArticulationSim : public PxUserAllocated
{
PX_NOCOPY(ArticulationSim)
public:
ArticulationSim(ArticulationCore& core,
Scene& scene,
BodyCore& root);
~ArticulationSim();
PX_FORCE_INLINE Dy::FeatherstoneArticulation* getLowLevelArticulation() const { return mLLArticulation; }
PX_FORCE_INLINE ArticulationCore& getCore() const { return mCore; }
//we don't need removeBody method anymore because when the articulation is removed from the scene, the articulation sim will
//get completely distroy and when we re-add the articulation to the scene, all the data will get recomputed
void addBody(BodySim& body,
BodySim* parent,
ArticulationJointSim* joint);
void removeBody(BodySim& body);
//we don't need complementary removeTendon/removeMimicJoint functions because
//the articulation sim will be completely destroyed when the articulation is removed from the scene.
//When we re-add the articulation to the scene all the data will be recomputed.
void addTendon(ArticulationSpatialTendonSim* const);
void addTendon(ArticulationFixedTendonSim* const);
void addMimicJoint(ArticulationMimicJointSim* const mimicJoint, const PxU32 linkA, const PxU32 linkB);
void createLLStructure(); // resize LL memory if necessary
void initializeConfiguration();
void debugCheckWakeCounterOfLinks(PxReal wakeCounter) const;
void debugCheckSleepStateOfLinks(bool isSleeping) const;
bool isSleeping() const;
void internalWakeUp(PxReal wakeCounter); // called when sim sets sleep timer
void sleepCheck(PxReal dt);
void putToSleep();
void updateCCDLinks(PxArray<BodySim*>& sims);
void updateCached(PxBitMapPinned* shapehapeChangedMap);
void markShapesUpdated(PxBitMapPinned* shapeChangedMap);
void updateContactDistance(PxReal* contactDistance, PxReal dt, const Bp::BoundsArray& boundsArray);
void setActive(bool b, bool asPartOfCreation=false);
void updateForces(PxReal dt);
void saveLastCCDTransform();
void clearAcceleration(PxReal dt);
void setFixedBaseLink(bool value);
//external reduced coordinate implementation
PxU32 getDofs() const;
//This function return the dof of the inbound joint, which belong to a link with corresponding linkID
PxU32 getDof(const PxU32 linkID) const;
PxArticulationCache* createCache();
PxU32 getCacheDataSize() const;
void zeroCache(PxArticulationCache&) const;
bool applyCache(PxArticulationCache& cache, const PxArticulationCacheFlags flag) const;
void copyInternalStateToCache
(PxArticulationCache& cache, const PxArticulationCacheFlags flag, const bool isGpuSimEnabled) const;
void packJointData(const PxReal* maximum, PxReal* reduced) const;
void unpackJointData(const PxReal* reduced, PxReal* maximum) const;
void commonInit();
void computeGeneralizedGravityForce(PxArticulationCache& cache, const bool rootMotion);
void computeCoriolisAndCentrifugalForce(PxArticulationCache& cache, const bool rootMotion);
void computeGeneralizedExternalForce(PxArticulationCache& cache);
void computeJointAcceleration(PxArticulationCache& cache);
void computeJointForce(PxArticulationCache& cache);
void computeKinematicJacobian(const PxU32 linkID, PxArticulationCache& cache);
void computeDenseJacobian(PxArticulationCache& cache, PxU32& nRows, PxU32& nCols);
void computeCoefficientMatrix(PxArticulationCache& cache);
bool computeLambda(PxArticulationCache& cache, PxArticulationCache& rollBackCache, const PxReal* jointTorque, const PxVec3 gravity, const PxU32 maxIter);
void computeGeneralizedMassMatrix(PxArticulationCache& cache, const bool rootMotion);
PxVec3 computeArticulationCOM(const bool rootFrame);
void computeCentroidalMomentumMatrix(PxArticulationCache& cache);
PxU32 getCoefficientMatrixSize() const;
void setRootLinearVelocity(const PxVec3& velocity);
void setRootAngularVelocity(const PxVec3& velocity);
PxSpatialVelocity getLinkVelocity(const PxU32 linkId) const;
PxSpatialVelocity getLinkAcceleration(const PxU32 linkId, const bool isGpuSimEnabled) const;
//internal method implementation
PX_FORCE_INLINE PxNodeIndex getIslandNodeIndex() const { return mIslandNodeIndex; }
void setGlobalPose();
PxU32 findBodyIndex(BodySim &body) const;
void setJointDirty(Dy::ArticulationJointCore& jointCore);
void addLoopConstraint(ConstraintSim* constraint);
void removeLoopConstraint(ConstraintSim* constraint);
PX_FORCE_INLINE PxU32 getMaxDepth() { return mMaxDepth; }
void setArticulationDirty(PxU32 flag);
PX_FORCE_INLINE void setDirtyFlag(ArticulationSimDirtyFlag::Enum flag) { mDirtyFlags = flag; }
PX_FORCE_INLINE ArticulationSimDirtyFlags getDirtyFlag() const { return mDirtyFlags; }
PX_FORCE_INLINE const Dy::ArticulationLink& getLink(const PxU32 linkId) const { return mLinks[linkId]; }
PxU32 getRootActorIndex() const;
void updateKinematic(PxArticulationKinematicFlags flags);
void copyJointStatus(const PxU32 linkIndex);
PX_FORCE_INLINE bool isLLArticulationInitialized() const { return mIsLLArticulationInitialized; }
private:
Dy::FeatherstoneArticulation* mLLArticulation;
Scene& mScene;
ArticulationCore& mCore;
PxArray<Dy::ArticulationLink> mLinks;
PxArray<BodySim*> mBodies;
PxArray<ArticulationJointSim*> mJoints;
PxArray<Dy::ArticulationSpatialTendon*> mSpatialTendons;
PxArray<Dy::ArticulationFixedTendon*> mFixedTendons;
PxArray<Dy::ArticulationMimicJointCore*> mMimicJoints;
PxNodeIndex mIslandNodeIndex;
PxArray <Dy::ArticulationLoopConstraint> mLoopConstraints;
PxU32 mMaxDepth;
bool mIsLLArticulationInitialized;
ArticulationSimDirtyFlags mDirtyFlags;
};
ArticulationSim* getArticulationSim(const IG::IslandSim& islandSim, PxNodeIndex nodeIndex);
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,163 @@
// 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.
#include "ScArticulationTendonCore.h"
#include "ScArticulationTendonSim.h"
using namespace physx;
void Sc::ArticulationSpatialTendonCore::setStiffness(const PxReal stiffness)
{
mStiffness = stiffness;
if (mSim)
mSim->setStiffness(stiffness);
}
PxReal Sc::ArticulationSpatialTendonCore::getStiffness() const
{
return mStiffness;
}
void Sc::ArticulationSpatialTendonCore::setDamping(const PxReal damping)
{
mDamping = damping;
if (mSim)
mSim->setDamping(damping);
}
PxReal Sc::ArticulationSpatialTendonCore::getDamping() const
{
return mDamping;
}
void Sc::ArticulationSpatialTendonCore::setLimitStiffness(const PxReal stiffness)
{
mLimitStiffness = stiffness;
if (mSim)
mSim->setLimitStiffness(stiffness);
}
PxReal Sc::ArticulationSpatialTendonCore::getLimitStiffness() const
{
return mLimitStiffness;
}
void Sc::ArticulationSpatialTendonCore::setOffset(const PxReal offset)
{
mOffset = offset;
if (mSim)
mSim->setOffset(offset);
}
PxReal Sc::ArticulationSpatialTendonCore::getOffset() const
{
return mOffset;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
void Sc::ArticulationFixedTendonCore::setStiffness(const PxReal stiffness)
{
mStiffness = stiffness;
if (mSim)
mSim->setStiffness(stiffness);
}
PxReal Sc::ArticulationFixedTendonCore::getStiffness() const
{
return mStiffness;
}
void Sc::ArticulationFixedTendonCore::setDamping(const PxReal damping)
{
mDamping = damping;
if (mSim)
mSim->setDamping(damping);
}
PxReal Sc::ArticulationFixedTendonCore::getDamping() const
{
return mDamping;
}
void Sc::ArticulationFixedTendonCore::setLimitStiffness(const PxReal stiffness)
{
mLimitStiffness = stiffness;
if (mSim)
mSim->setLimitStiffness(stiffness);
}
PxReal Sc::ArticulationFixedTendonCore::getLimitStiffness() const
{
return mLimitStiffness;
}
void Sc::ArticulationFixedTendonCore::setSpringRestLength(const PxReal restLength)
{
mRestLength = restLength;
if (mSim)
mSim->setSpringRestLength(restLength);
}
PxReal Sc::ArticulationFixedTendonCore::getSpringRestLength() const
{
return mRestLength;
}
void Sc::ArticulationFixedTendonCore::setLimitRange(const PxReal lowLimit, const PxReal highLimit)
{
mLowLimit = lowLimit;
mHighLimit = highLimit;
if (mSim)
mSim->setLimitRange(lowLimit, highLimit);
}
void Sc::ArticulationFixedTendonCore::getLimitRange(PxReal& lowLimit, PxReal& highLimit) const
{
lowLimit = mLowLimit;
highLimit = mHighLimit;
}
void Sc::ArticulationFixedTendonCore::setOffset(const PxReal offset)
{
mOffset = offset;
if (mSim)
mSim->setOffset(offset);
}
PxReal Sc::ArticulationFixedTendonCore::getOffset() const
{
return mOffset;
}

View File

@@ -0,0 +1,44 @@
// 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.
#include "ScArticulationTendonJointCore.h"
#include "ScArticulationTendonSim.h"
using namespace physx;
void Sc::ArticulationTendonJointCore::setCoefficient(PxArticulationAxis::Enum axis_, const PxReal coefficient_, const PxReal recipCoefficient_)
{
axis = axis_;
coefficient = coefficient_;
recipCoefficient = recipCoefficient_;
if (mTendonSim)
{
mTendonSim->setTendonJointCoefficient(*this, axis_, coefficient, recipCoefficient);
}
}

View File

@@ -0,0 +1,373 @@
// 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.
#include "ScArticulationTendonSim.h"
#include "ScArticulationTendonCore.h"
#include "ScArticulationAttachmentCore.h"
#include "ScArticulationTendonJointCore.h"
#include "ScArticulationJointCore.h"
#include "ScScene.h"
#include "DyArticulationTendon.h"
#include "ScArticulationSim.h"
using namespace physx;
Sc::ArticulationSpatialTendonSim::ArticulationSpatialTendonSim(ArticulationSpatialTendonCore& tendon, Scene& scene) :
mTendonCore(tendon), mScene(scene)
{
mTendonCore.setSim(this);
mLLTendon.mStiffness = tendon.mStiffness;
mLLTendon.mDamping = tendon.mDamping;
mLLTendon.mOffset = tendon.mOffset;
mLLTendon.mLimitStiffness = tendon.mLimitStiffness;
}
Sc::ArticulationSpatialTendonSim::~ArticulationSpatialTendonSim()
{
mTendonCore.setSim(NULL);
}
void Sc::ArticulationSpatialTendonSim::setStiffness(const PxReal stiffness)
{
mLLTendon.mStiffness = stiffness;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON);
}
PxReal Sc::ArticulationSpatialTendonSim::getStiffness() const
{
return mLLTendon.mStiffness;
}
void Sc::ArticulationSpatialTendonSim::setDamping(const PxReal damping)
{
mLLTendon.mDamping = damping;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON);
}
PxReal Sc::ArticulationSpatialTendonSim::getDamping() const
{
return mLLTendon.mDamping;
}
void Sc::ArticulationSpatialTendonSim::setLimitStiffness(const PxReal stiffness)
{
mLLTendon.mLimitStiffness = stiffness;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
PxReal Sc::ArticulationSpatialTendonSim::getLimitStiffness() const
{
return mLLTendon.mLimitStiffness;
}
void Sc::ArticulationSpatialTendonSim::setOffset(const PxReal offset)
{
mLLTendon.mOffset = offset;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON);
}
PxReal Sc::ArticulationSpatialTendonSim::getOffset() const
{
return mLLTendon.mOffset;
}
void Sc::ArticulationSpatialTendonSim::setAttachmentCoefficient(ArticulationAttachmentCore& core, const PxReal coefficient)
{
const PxU32 index = core.mAttachmentIndex;
Dy::ArticulationAttachment& attachment = mLLTendon.getAttachment(index);
attachment.coefficient = coefficient;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON_ATTACHMENT);
}
void Sc::ArticulationSpatialTendonSim::setAttachmentRelativeOffset(ArticulationAttachmentCore& core, const PxVec3& offset)
{
const PxU32 index = core.mAttachmentIndex;
Dy::ArticulationAttachment& attachment = mLLTendon.getAttachment(index);
attachment.relativeOffset = offset;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON_ATTACHMENT);
}
void Sc::ArticulationSpatialTendonSim::setAttachmentLimits(ArticulationAttachmentCore& core, const PxReal lowLimit, const PxReal highLimit)
{
const PxU32 index = core.mAttachmentIndex;
Dy::ArticulationAttachment& attachment = mLLTendon.getAttachment(index);
attachment.lowLimit = lowLimit;
attachment.highLimit = highLimit;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON_ATTACHMENT);
}
void Sc::ArticulationSpatialTendonSim::setAttachmentRestLength(ArticulationAttachmentCore& core, const PxReal restLength)
{
const PxU32 index = core.mAttachmentIndex;
Dy::ArticulationAttachment& attachment = mLLTendon.getAttachment(index);
attachment.restLength = restLength;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_SPATIAL_TENDON_ATTACHMENT);
}
void Sc::ArticulationSpatialTendonSim::addAttachment(ArticulationAttachmentCore& core)
{
const PxU32 index = mLLTendon.getNewID();
Dy::ArticulationAttachment& attachment = mLLTendon.getAttachment(index);
attachment.relativeOffset = core.mRelativeOffset;
attachment.linkInd = PxU16(core.mLLLinkIndex);
attachment.lowLimit = core.mLowLimit;
attachment.highLimit = core.mHighLimit;
attachment.coefficient = core.mCoefficient;
attachment.myInd = index;
attachment.children = 0;
attachment.childCount = 0;
attachment.restLength = core.mRestLength;
core.mAttachmentIndex = index;
core.mTendonSim = this;
if (core.mParent)
{
const PxU32 parentIndex = core.mParent->mAttachmentIndex;
attachment.parent = parentIndex;
mLLTendon.getAttachment(parentIndex).children |= Dy::ArticulationAttachmentBitField(1) << index;
mLLTendon.getAttachment(parentIndex).childCount++;
}
else
{
attachment.parent = DY_ARTICULATION_ATTACHMENT_NONE;
}
}
void Sc::ArticulationSpatialTendonSim::removeAttachment(ArticulationAttachmentCore& core)
{
const PxU32 index = core.mAttachmentIndex;
Dy::ArticulationAttachment& attachment = mLLTendon.getAttachment(index);
PX_ASSERT(attachment.childCount == 0);
if (attachment.parent != DY_ARTICULATION_ATTACHMENT_NONE)
{
Dy::ArticulationAttachment& parent = mLLTendon.getAttachment(attachment.parent);
parent.children &= ~(Dy::ArticulationAttachmentBitField(1) << index);
parent.childCount--;
}
mLLTendon.freeID(index);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
Sc::ArticulationFixedTendonSim::ArticulationFixedTendonSim(ArticulationFixedTendonCore& tendon, Scene& scene) :
mTendonCore(tendon), mScene(scene)
{
mTendonCore.setSim(this);
mLLTendon.mStiffness = tendon.mStiffness;
mLLTendon.mDamping = tendon.mDamping;
mLLTendon.mOffset = tendon.mOffset;
mLLTendon.mLimitStiffness = tendon.mLimitStiffness;
mLLTendon.mLowLimit = tendon.mLowLimit;
mLLTendon.mHighLimit = tendon.mHighLimit;
mLLTendon.mRestLength = tendon.mRestLength;
}
Sc::ArticulationFixedTendonSim::~ArticulationFixedTendonSim()
{
mTendonCore.setSim(NULL);
}
void Sc::ArticulationFixedTendonSim::setStiffness(const PxReal stiffness)
{
mLLTendon.mStiffness = stiffness;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
PxReal Sc::ArticulationFixedTendonSim::getStiffness() const
{
return mLLTendon.mStiffness;
}
void Sc::ArticulationFixedTendonSim::setDamping(const PxReal damping)
{
mLLTendon.mDamping = damping;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
PxReal Sc::ArticulationFixedTendonSim::getDamping() const
{
return mLLTendon.mDamping;
}
void Sc::ArticulationFixedTendonSim::setLimitStiffness(const PxReal stiffness)
{
mLLTendon.mLimitStiffness = stiffness;
Dy::FeatherstoneArticulation* llArticulation = static_cast<Dy::FeatherstoneArticulation*>(mArtiSim->getLowLevelArticulation());
llArticulation->setGpuDirtyFlag(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
PxReal Sc::ArticulationFixedTendonSim::getLimitStiffness() const
{
return mLLTendon.mLimitStiffness;
}
void Sc::ArticulationFixedTendonSim::setOffset(const PxReal offset)
{
mLLTendon.mOffset = offset;
mArtiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
PxReal Sc::ArticulationFixedTendonSim::getOffset() const
{
return mLLTendon.mOffset;
}
void Sc::ArticulationFixedTendonSim::setSpringRestLength(const PxReal restLength)
{
mLLTendon.mRestLength = restLength;
mArtiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
PxReal Sc::ArticulationFixedTendonSim::getSpringRestLength() const
{
return mLLTendon.mRestLength;
}
void Sc::ArticulationFixedTendonSim::setLimitRange(const PxReal lowLimit, const PxReal highLimit)
{
mLLTendon.mLowLimit = lowLimit;
mLLTendon.mHighLimit = highLimit;
mArtiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON);
}
void Sc::ArticulationFixedTendonSim::getLimitRange(PxReal& lowLimit, PxReal& highLimit) const
{
lowLimit = mLLTendon.mLowLimit;
highLimit = mLLTendon.mHighLimit;
}
void Sc::ArticulationFixedTendonSim::addTendonJoint(ArticulationTendonJointCore& tendonJointCore)
{
const PxU32 jointIndex = mLLTendon.getNewID();
Dy::ArticulationTendonJoint& tendonJoint = mLLTendon.getTendonJoint(jointIndex);
tendonJoint.axis = PxU16(tendonJointCore.axis);
tendonJoint.coefficient = tendonJointCore.coefficient;
tendonJoint.recipCoefficient = tendonJointCore.recipCoefficient;
tendonJoint.linkInd = PxU16(tendonJointCore.mLLLinkIndex);
tendonJoint.children = 0;
tendonJoint.childCount = 0;
tendonJointCore.mLLTendonJointIndex = jointIndex;
//tendonJointCore.mLLTendonJoint = &tendonJoint;
tendonJointCore.mTendonSim = this;
if (tendonJointCore.mParent)
{
const PxU32 parentIndex = tendonJointCore.mParent->mLLTendonJointIndex;
tendonJoint.parent = parentIndex;
mLLTendon.getTendonJoint(parentIndex).children |= Dy::ArticulationAttachmentBitField(1) << jointIndex;
mLLTendon.getTendonJoint(parentIndex).childCount++;
}
else
{
tendonJoint.parent = DY_ARTICULATION_ATTACHMENT_NONE;
}
}
void Sc::ArticulationFixedTendonSim::removeTendonJoint(ArticulationTendonJointCore& core)
{
const PxU32 index = core.mLLTendonJointIndex;
Dy::ArticulationTendonJoint& tendonJoint = mLLTendon.getTendonJoint(index);
PX_ASSERT(tendonJoint.childCount == 0);
if (tendonJoint.parent != DY_ARTICULATION_ATTACHMENT_NONE)
{
Dy::ArticulationTendonJoint& parent = mLLTendon.getTendonJoint(tendonJoint.parent);
parent.children &= ~(Dy::ArticulationAttachmentBitField(1) << index);
parent.childCount--;
}
mLLTendon.freeID(index);
}
void Sc::ArticulationFixedTendonSim::setTendonJointCoefficient(ArticulationTendonJointCore& core, const PxArticulationAxis::Enum axis, const float coefficient, const float recipCoefficient)
{
const PxU32 index = core.mLLTendonJointIndex;
Dy::ArticulationTendonJoint& tendonJoint = mLLTendon.getTendonJoint(index);
tendonJoint.axis = PxU16(axis);
tendonJoint.coefficient = coefficient;
tendonJoint.recipCoefficient = recipCoefficient;
mArtiSim->setArticulationDirty(Dy::ArticulationDirtyFlag::eDIRTY_FIXED_TENDON_JOINT);
}

View File

@@ -0,0 +1,123 @@
// 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_ARTICULATION_TENDON_SIM_H
#define SC_ARTICULATION_TENDON_SIM_H
#include "foundation/PxUserAllocated.h"
#include "DyArticulationTendon.h"
namespace physx
{
namespace Sc
{
class ArticulationFixedTendonCore;
class ArticulationTendonJointCore;
class ArticulationSpatialTendonCore;
class ArticulationAttachmentCore;
class Scene;
class ArticulationJointCore;
class ArticulationSim;
class ArticulationSpatialTendonSim : public PxUserAllocated
{
PX_NOCOPY(ArticulationSpatialTendonSim)
public:
ArticulationSpatialTendonSim(ArticulationSpatialTendonCore& tendon, Scene& scene);
virtual ~ArticulationSpatialTendonSim();
void setStiffness(const PxReal stiffness);
PxReal getStiffness() const;
void setDamping(const PxReal damping);
PxReal getDamping() const;
void setLimitStiffness(const PxReal stiffness);
PxReal getLimitStiffness() const;
void setOffset(const PxReal offset);
PxReal getOffset() const;
void setAttachmentCoefficient(ArticulationAttachmentCore& core, const PxReal coefficient);
void setAttachmentRelativeOffset(ArticulationAttachmentCore& core, const PxVec3& offset);
void setAttachmentLimits(ArticulationAttachmentCore& core, const PxReal lowLimit, const PxReal highLimit);
void setAttachmentRestLength(ArticulationAttachmentCore& core, const PxReal restLength);
void addAttachment(ArticulationAttachmentCore& core);
void removeAttachment(ArticulationAttachmentCore& core);
Dy::ArticulationSpatialTendon mLLTendon;
ArticulationSpatialTendonCore& mTendonCore;
ArticulationSim* mArtiSim;
Scene& mScene;
};
class ArticulationFixedTendonSim : public PxUserAllocated
{
PX_NOCOPY(ArticulationFixedTendonSim)
public:
ArticulationFixedTendonSim(ArticulationFixedTendonCore& tendon, Scene& scene);
virtual ~ArticulationFixedTendonSim();
void setStiffness(const PxReal stiffness);
PxReal getStiffness() const;
void setDamping(const PxReal damping);
PxReal getDamping() const;
void setLimitStiffness(const PxReal stiffness);
PxReal getLimitStiffness() const;
void setOffset(const PxReal offset);
PxReal getOffset() const;
void setSpringRestLength(const PxReal restLength);
PxReal getSpringRestLength() const;
void setLimitRange(const PxReal lowLimit, const PxReal highLimit);
void getLimitRange(PxReal& lowLimit, PxReal& highLimit) const;
void addTendonJoint(ArticulationTendonJointCore& tendonJointCore);
void removeTendonJoint(ArticulationTendonJointCore& core);
void setTendonJointCoefficient(ArticulationTendonJointCore& core, const PxArticulationAxis::Enum axis, const float coefficient, const float recipCoefficient);
Dy::ArticulationFixedTendon mLLTendon;
ArticulationFixedTendonCore& mTendonCore;
ArticulationSim* mArtiSim;
Scene& mScene;
};
}//namespace Sc
}//namespace physx
#endif

View File

@@ -0,0 +1,619 @@
// 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.
#include "ScBodyCore.h"
#include "ScBodySim.h"
#include "ScPhysics.h"
#include "ScScene.h"
#include "PxsSimulationController.h"
#include "ScArticulationSim.h"
using namespace physx;
static void updateBodySim(Sc::BodyCore& bodyCore)
{
Sc::BodySim* bodySim = bodyCore.getSim();
if(bodySim)
bodySim->getScene().updateBodySim(*bodySim);
}
Sc::BodyCore::BodyCore(PxActorType::Enum type, const PxTransform& bodyPose) : RigidCore(type)
{
const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale();
const bool isDynamic = type == PxActorType::eRIGID_DYNAMIC;
const float linearDamping = isDynamic ? 0.0f : 0.05f;
const float maxLinearVelocitySq = isDynamic ? 1e32f /*PX_MAX_F32*/ : 100.f * 100.f * scale.length * scale.length;
const float maxAngularVelocitySq = isDynamic ? 100.0f * 100.0f : 50.0f * 50.0f;
mCore.init(bodyPose, PxVec3(1.0f), 1.0f, Sc::Physics::sWakeCounterOnCreation, scale.speed, linearDamping, 0.05f, maxLinearVelocitySq, maxAngularVelocitySq,
type);
}
Sc::BodyCore::~BodyCore()
{
PX_ASSERT(getSim() == 0);
}
Sc::BodySim* Sc::BodyCore::getSim() const
{
return static_cast<BodySim*>(Sc::ActorCore::getSim());
}
void Sc::BodyCore::restoreDynamicData()
{
BodySim* sim = getSim();
PX_ASSERT(sim);
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PxsBodyCore& core = getCore();
simStateRestoreBodyProperties(simStateData, core);
}
//--------------------------------------------------------------
//
// BodyCore interface implementation
//
//--------------------------------------------------------------
void Sc::BodyCore::setBody2World(const PxTransform& p)
{
mCore.body2World = p;
PX_ASSERT(p.p.isFinite());
PX_ASSERT(p.q.isFinite());
BodySim* sim = getSim();
if(sim)
{
sim->postBody2WorldChange();
sim->getScene().updateBodySim(*sim);
}
}
void Sc::BodyCore::setCMassLocalPose(const PxTransform& newBody2Actor)
{
const PxTransform oldActor2World = mCore.body2World * mCore.getBody2Actor().getInverse();
const PxTransform newBody2World = oldActor2World * newBody2Actor;
PX_ASSERT(newBody2World.p.isFinite());
PX_ASSERT(newBody2World.q.isFinite());
mCore.body2World = newBody2World;
setBody2Actor(newBody2Actor);
}
void Sc::BodyCore::setLinearVelocity(const PxVec3& v, bool skipBodySimUpdate)
{
mCore.linearVelocity = v;
PX_ASSERT(!skipBodySimUpdate || (getFlags() & PxRigidBodyFlag::eKINEMATIC));
if(!skipBodySimUpdate)
updateBodySim(*this);
}
void Sc::BodyCore::setAngularVelocity(const PxVec3& v, bool skipBodySimUpdate)
{
mCore.angularVelocity = v;
PX_ASSERT(!skipBodySimUpdate || (getFlags() & PxRigidBodyFlag::eKINEMATIC));
if(!skipBodySimUpdate)
updateBodySim(*this);
}
void Sc::BodyCore::setCfmScale(PxReal cfmScale)
{
mCore.cfmScale = cfmScale;
updateBodySim(*this);
}
void Sc::BodyCore::setBody2Actor(const PxTransform& p)
{
PX_ASSERT(p.p.isFinite());
PX_ASSERT(p.q.isFinite());
mCore.setBody2Actor(p);
updateBodySim(*this);
}
void Sc::BodyCore::addSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc)
{
BodySim* sim = getSim();
PX_ASSERT(sim);
sim->addSpatialAcceleration(linAcc, angAcc);
}
void Sc::BodyCore::setSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc)
{
BodySim* sim = getSim();
PX_ASSERT(sim);
sim->setSpatialAcceleration(linAcc, angAcc);
}
void Sc::BodyCore::clearSpatialAcceleration(bool force, bool torque)
{
PX_ASSERT(force || torque);
BodySim* sim = getSim();
PX_ASSERT(sim);
sim->clearSpatialAcceleration(force, torque);
}
void Sc::BodyCore::addSpatialVelocity(const PxVec3* linVelDelta, const PxVec3* angVelDelta)
{
BodySim* sim = getSim();
PX_ASSERT(sim);
sim->addSpatialVelocity(linVelDelta, angVelDelta);
}
void Sc::BodyCore::clearSpatialVelocity(bool force, bool torque)
{
PX_ASSERT(force || torque);
BodySim* sim = getSim();
PX_ASSERT(sim);
sim->clearSpatialVelocity(force, torque);
}
PxReal Sc::BodyCore::getInverseMass() const
{
BodySim* sim = getSim();
if(!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
return mCore.inverseMass;
}
else
{
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
return simStateData->getKinematicData()->backupInvMass;
}
}
void Sc::BodyCore::setInverseMass(PxReal m)
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
mCore.inverseMass = m;
updateBodySim(*this);
}
else
{
SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
simStateData->getKinematicData()->backupInvMass = m;
}
}
const PxVec3& Sc::BodyCore::getInverseInertia() const
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
return mCore.inverseInertia;
}
else
{
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
return (simStateData->getKinematicData()->backupInverseInertia);
}
}
void Sc::BodyCore::setInverseInertia(const PxVec3& i)
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
mCore.inverseInertia = i;
updateBodySim(*this);
}
else
{
SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
simStateData->getKinematicData()->backupInverseInertia = i;
}
}
PxReal Sc::BodyCore::getLinearDamping() const
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
return mCore.linearDamping;
}
else
{
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
return (simStateData->getKinematicData()->backupLinearDamping);
}
}
void Sc::BodyCore::setLinearDamping(PxReal d)
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
mCore.linearDamping = d;
updateBodySim(*this);
}
else
{
SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
simStateData->getKinematicData()->backupLinearDamping = d;
}
}
PxReal Sc::BodyCore::getAngularDamping() const
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
return mCore.angularDamping;
}
else
{
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
return (simStateData->getKinematicData()->backupAngularDamping);
}
}
void Sc::BodyCore::setAngularDamping(PxReal v)
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
mCore.angularDamping = v;
updateBodySim(*this);
}
else
{
SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
simStateData->getKinematicData()->backupAngularDamping = v;
}
}
PxReal Sc::BodyCore::getMaxAngVelSq() const
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
return mCore.maxAngularVelocitySq;
}
else
{
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
return (simStateData->getKinematicData()->backupMaxAngVelSq);
}
}
void Sc::BodyCore::setMaxAngVelSq(PxReal v)
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
mCore.maxAngularVelocitySq = v;
updateBodySim(*this);
}
else
{
SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
simStateData->getKinematicData()->backupMaxAngVelSq = v;
}
}
PxReal Sc::BodyCore::getMaxLinVelSq() const
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
return mCore.maxLinearVelocitySq;
}
else
{
const SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
return (simStateData->getKinematicData()->backupMaxLinVelSq);
}
}
void Sc::BodyCore::setMaxLinVelSq(PxReal v)
{
BodySim* sim = getSim();
if (!sim || (!(getFlags() & PxRigidBodyFlag::eKINEMATIC)))
{
mCore.maxLinearVelocitySq = v;
updateBodySim(*this);
}
else
{
SimStateData* simStateData = sim->getSimStateData(true);
PX_ASSERT(simStateData);
PX_ASSERT(simStateData->getKinematicData());
simStateData->getKinematicData()->backupMaxLinVelSq = v;
}
}
void Sc::BodyCore::setFlags(PxRigidBodyFlags f)
{
const PxRigidBodyFlags old = mCore.mFlags;
if(f != old)
{
const PxU32 wasKinematic = old & PxRigidBodyFlag::eKINEMATIC;
const PxU32 isKinematic = f & PxRigidBodyFlag::eKINEMATIC;
const bool switchToKinematic = ((!wasKinematic) && isKinematic);
const bool switchToDynamic = (wasKinematic && (!isKinematic));
mCore.mFlags = f;
BodySim* sim = getSim();
if (sim)
{
const PxU32 posePreviewFlag = f & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW;
if(PxU32(old & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW) != posePreviewFlag)
sim->postPosePreviewChange(posePreviewFlag);
// for those who might wonder about the complexity here:
// our current behavior is that you are not allowed to set a kinematic target unless the object is in a scene.
// Thus, the kinematic data should only be created/destroyed when we know for sure that we are in a scene.
if(switchToKinematic)
sim->switchToKinematic();
else if(switchToDynamic)
sim->switchToDynamic();
const PxU32 wasSpeculativeCCD = old & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD;
const PxU32 isSpeculativeCCD = f & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD;
if(wasSpeculativeCCD ^ isSpeculativeCCD)
{
if(wasSpeculativeCCD)
{
sim->removeFromSpeculativeCCDMap();
sim->getLowLevelBody().mInternalFlags &= (~PxsRigidBody::eSPECULATIVE_CCD);
}
else
{
//Kinematic body switch puts the body to sleep, so we do not mark the speculative CCD bitmap for this actor to true in this case.
if(!switchToKinematic)
sim->addToSpeculativeCCDMap();
sim->getLowLevelBody().mInternalFlags |= (PxsRigidBody::eSPECULATIVE_CCD);
}
}
const PxU32 wasIntegrateGyroscopic = old & PxRigidBodyFlag::eENABLE_GYROSCOPIC_FORCES;
const PxU32 isIntegrateGyroscopic = f & PxRigidBodyFlag::eENABLE_GYROSCOPIC_FORCES;
if (wasIntegrateGyroscopic ^ isIntegrateGyroscopic)
{
if(wasIntegrateGyroscopic)
sim->getLowLevelBody().mInternalFlags &= (~PxsRigidBody::eENABLE_GYROSCOPIC);
else
sim->getLowLevelBody().mInternalFlags |= (PxsRigidBody::eENABLE_GYROSCOPIC);
}
const PxU32 wasRetainAccel = old & PxRigidBodyFlag::eRETAIN_ACCELERATIONS;
const PxU32 isRetainAccel = f & PxRigidBodyFlag::eRETAIN_ACCELERATIONS;
if (wasRetainAccel ^ isRetainAccel)
{
if (wasRetainAccel)
sim->getLowLevelBody().mInternalFlags &= (~PxsRigidBody::eRETAIN_ACCELERATION);
else
sim->getLowLevelBody().mInternalFlags |= (PxsRigidBody::eRETAIN_ACCELERATION);
}
//Force flag change through...
sim->getScene().updateBodySim(*sim);
}
if(switchToKinematic)
{
if (sim)
sim->getLowLevelBody().mInternalFlags |= PxsRigidBody::eVELOCITY_COPY_GPU;
putToSleep();
}
if(sim)
{
const PxRigidBodyFlags ktFlags(PxRigidBodyFlag::eUSE_KINEMATIC_TARGET_FOR_SCENE_QUERIES | PxRigidBodyFlag::eKINEMATIC);
const bool hadKt = (old & ktFlags) == ktFlags;
const bool hasKt = (f & ktFlags) == ktFlags;
if(hasKt && !hadKt)
sim->destroySqBounds();
else if(hadKt && !hasKt)
sim->createSqBounds();
}
}
}
void Sc::BodyCore::setMaxContactImpulse(PxReal m)
{
mCore.maxContactImpulse = m;
updateBodySim(*this);
}
void Sc::BodyCore::setOffsetSlop(PxReal slop)
{
mCore.offsetSlop = slop;
updateBodySim(*this);
}
PxNodeIndex Sc::BodyCore::getInternalIslandNodeIndex() const
{
BodySim* sim = getSim();
return sim ? sim->getNodeIndex() : PxNodeIndex(PX_INVALID_NODE);
}
void Sc::BodyCore::setWakeCounter(PxReal wakeCounter, bool forceWakeUp)
{
mCore.wakeCounter = wakeCounter;
BodySim* sim = getSim();
if(sim)
{
//wake counter change, we need to trigger dma pxgbodysim data again
sim->getScene().updateBodySim(*sim);
if ((wakeCounter > 0.0f) || forceWakeUp)
sim->wakeUp();
sim->postSetWakeCounter(wakeCounter, forceWakeUp);
}
}
void Sc::BodyCore::setSleepThreshold(PxReal t)
{
mCore.sleepThreshold = t;
updateBodySim(*this);
}
void Sc::BodyCore::setFreezeThreshold(PxReal t)
{
mCore.freezeThreshold = t;
updateBodySim(*this);
}
bool Sc::BodyCore::isSleeping() const
{
BodySim* sim = getSim();
return sim ? !sim->isActive() : true;
}
void Sc::BodyCore::putToSleep()
{
mCore.linearVelocity = PxVec3(0.0f);
mCore.angularVelocity = PxVec3(0.0f);
// important to clear all values before setting the wake counter because the values decide
// whether an object is ready to go to sleep or not.
setWakeCounter(0.0f);
BodySim* sim = getSim();
if(sim)
sim->putToSleep();
}
void Sc::BodyCore::onOriginShift(const PxVec3& shift)
{
mCore.body2World.p -= shift;
BodySim* b = getSim();
if(b)
b->onOriginShift(shift, getFlags() & PxRigidBodyFlag::eKINEMATIC); // BodySim might not exist if actor has simulation disabled (PxActorFlag::eDISABLE_SIMULATION)
}
// PT: TODO: why do we test against NULL everywhere but not in 'isFrozen' ?
PxIntBool Sc::BodyCore::isFrozen() const
{
return getSim()->isFrozen();
}
void Sc::BodyCore::setSolverIterationCounts(PxU16 c)
{
mCore.solverIterationCounts = c;
Sc::BodySim* sim = getSim();
if (sim)
{
sim->getLowLevelBody().mSolverIterationCounts = c;
sim->getScene().setDynamicsDirty();
}
}
///////////////////////////////////////////////////////////////////////////////
bool Sc::BodyCore::getKinematicTarget(PxTransform& p) const
{
PX_ASSERT(mCore.mFlags & PxRigidBodyFlag::eKINEMATIC);
const BodySim* sim = getSim();
return (sim && simStateGetKinematicTarget(sim->getSimStateData_Unchecked(), p));
}
bool Sc::BodyCore::getHasValidKinematicTarget() const
{
//The use pattern for this is that we should only look for kinematic data if we know it is kinematic.
//We might look for velmod data even if it is kinematic.
BodySim* sim = getSim();
return (sim && simStateGetHasValidKinematicTarget(sim->getSimStateData_Unchecked()));
}
void Sc::BodyCore::setKinematicTarget(const PxTransform& p, PxReal wakeCounter)
{
PX_ASSERT(mCore.mFlags & PxRigidBodyFlag::eKINEMATIC);
Sc::BodySim* sim = getSim();
PX_ASSERT(sim);
sim->setKinematicTarget(p);
wakeUp(wakeCounter);
}
void Sc::BodyCore::invalidateKinematicTarget()
{
Sc::BodySim* sim = getSim();
PX_ASSERT(sim);
simStateInvalidateKinematicTarget(sim->getSimStateData_Unchecked());
}
void Sc::BodyCore::setFixedBaseLink(bool value)
{
BodySim* sim = getSim();
if(sim)
sim->getLowLevelBody().mCore->fixedBaseLink = PxU8(value);
}
void Sc::BodyCore::onRemoveKinematicFromScene()
{
PX_ASSERT(mCore.mFlags & PxRigidBodyFlag::eKINEMATIC);
PX_ASSERT(getSim() && getSim()->checkSimStateKinematicStatus(true));
// make sure that a kinematic which is not part of a scene is in the expected state
mCore.wakeCounter = 0.0f;
mCore.linearVelocity = PxVec3(0.0f);
mCore.angularVelocity = PxVec3(0.0f);
}
///////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,863 @@
// 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.
#include "ScBodySim.h"
#include "ScShapeSim.h"
#include "ScScene.h"
#include "ScArticulationSim.h"
#include "PxsContext.h"
#include "PxsSimpleIslandManager.h"
#include "PxsSimulationController.h"
#include "ScSimStateData.h"
using namespace physx;
using namespace Dy;
using namespace Sc;
#define PX_FREEZE_INTERVAL 1.5f
#define PX_FREE_EXIT_THRESHOLD 4.f
#define PX_FREEZE_TOLERANCE 0.25f
#define PX_SLEEP_DAMPING 0.5f
#define PX_FREEZE_SCALE 0.9f
static void updateBPGroup(ActorSim* sim)
{
PxU32 nbElems = sim->getNbElements();
ElementSim** elems = sim->getElements();
while (nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
current->updateBPGroup();
}
}
BodySim::BodySim(Scene& scene, BodyCore& core, bool compound) :
RigidSim (scene, core),
mLLBody (&core.getCore(), PX_FREEZE_INTERVAL),
mSimStateData (NULL),
mVelModState (VMF_GRAVITY_DIRTY),
mArticulation (NULL)
{
core.getCore().numCountedInteractions = 0;
core.getCore().disableGravity = core.getActorFlags() & PxActorFlag::eDISABLE_GRAVITY;
if(core.getFlags() & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD)
mLLBody.mInternalFlags |= PxsRigidBody::eSPECULATIVE_CCD;
if(core.getFlags() & PxRigidBodyFlag::eENABLE_GYROSCOPIC_FORCES)
mLLBody.mInternalFlags |= PxsRigidBody::eENABLE_GYROSCOPIC;
if(core.getFlags() & PxRigidBodyFlag::eRETAIN_ACCELERATIONS)
mLLBody.mInternalFlags |= PxsRigidBody::eRETAIN_ACCELERATION;
// PT: don't read the core ptr we just wrote, use input param
// PT: at time of writing we get a big L2 here because even though bodycore has been prefetched, the wake counter is 160 bytes away
const bool isAwake = (core.getWakeCounter() > 0) ||
(!core.getLinearVelocity().isZero()) ||
(!core.getAngularVelocity().isZero());
const bool isKine = isKinematic();
IG::SimpleIslandManager* simpleIslandManager = scene.getSimpleIslandManager();
if(!isArticulationLink())
{
mNodeIndex = simpleIslandManager->addNode(isAwake, isKine, IG::Node::eRIGID_BODY_TYPE, &mLLBody);
}
else
{
if(mArticulation)
{
const PxU32 linkIndex = mArticulation->findBodyIndex(*this);
const PxNodeIndex index = mArticulation->getIslandNodeIndex();
mNodeIndex.setIndices(index.index(), linkIndex);
}
}
PX_ASSERT(mActiveListIndex == SC_NOT_IN_SCENE_INDEX);
// A.B. need to set the compound rigid flag early enough, so that we add the rigid into
// active list and do not create the shape bounds
if(compound)
raiseInternalFlag(BF_IS_COMPOUND_RIGID);
setActive(isAwake, true);
if(isAwake)
{
scene.addToActiveList(*this);
PX_ASSERT(isActive());
}
else
{
mActiveListIndex = SC_NOT_IN_ACTIVE_LIST_INDEX;
mActiveCompoundListIndex = SC_NOT_IN_ACTIVE_LIST_INDEX;
PX_ASSERT(!isActive());
simpleIslandManager->deactivateNode(mNodeIndex);
}
if(isKine)
{
initKinematicStateBase(core, true);
setupSimStateData(true);
notifyPutToSleep(); // sleep state of kinematics is fully controlled by the simulation controller not the island manager
mFilterFlags |= PxFilterObjectFlag::eKINEMATIC;
}
}
BodySim::~BodySim()
{
Scene& scene = mScene;
const bool active = isActive();
tearDownSimStateData(isKinematic());
PX_ASSERT(!mSimStateData);
// PX-4603. AD: assuming that the articulation code cleans up the dirty state in case this is an articulation link.
if (!isArticulationLink())
mScene.getVelocityModifyMap().boundedReset(mNodeIndex.index());
PX_ASSERT(!readInternalFlag(BF_ON_DEATHROW)); // Before 3.0 it could happen that destroy could get called twice. Assert to make sure this is fixed.
raiseInternalFlag(BF_ON_DEATHROW);
scene.removeBody(*this);
//Articulations are represented by a single node, so they must only be removed by the articulation and not the links!
if(mArticulation == NULL && mNodeIndex.articulationLinkId() == 0) //If it wasn't an articulation link, then we can remove it
scene.getSimpleIslandManager()->removeNode(mNodeIndex);
PX_ASSERT(mActiveListIndex != SC_NOT_IN_SCENE_INDEX);
if (active)
scene.removeFromActiveList(*this);
mActiveListIndex = SC_NOT_IN_SCENE_INDEX;
mActiveCompoundListIndex = SC_NOT_IN_SCENE_INDEX;
mCore.setSim(NULL);
}
void BodySim::updateCached(PxBitMapPinned* shapeChangedMap)
{
if(!(mLLBody.mInternalFlags & PxsRigidBody::eFROZEN))
{
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
current->updateCached(0, shapeChangedMap);
}
}
}
void BodySim::updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray)
{
PX_ASSERT(!(mLLBody.mInternalFlags & PxsRigidBody::eFROZEN)); // PT: should not be called otherwise
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
current->updateCached(transformCache, boundsArray);
}
}
bool BodySim::setupSimStateData(bool isKinematic)
{
SimStateData* data = mSimStateData;
if(!data)
{
data = mScene.getSimStateDataPool()->construct();
if(!data)
return false;
}
if(isKinematic)
{
PX_ASSERT(!mSimStateData || !mSimStateData->isKine());
PX_PLACEMENT_NEW(data, SimStateData(SimStateData::eKine));
Kinematic* kine = data->getKinematicData();
kine->targetValid = 0;
simStateBackupAndClearBodyProperties(data, getBodyCore().getCore());
}
else
{
PX_ASSERT(!mSimStateData || !mSimStateData->isVelMod());
PX_PLACEMENT_NEW(data, SimStateData(SimStateData::eVelMod));
VelocityMod* velmod = data->getVelocityModData();
velmod->clear();
}
mSimStateData = data;
return true;
}
void BodySim::tearDownSimStateData(bool isKinematic)
{
PX_ASSERT(!mSimStateData || mSimStateData->isKine() == isKinematic);
if (mSimStateData)
{
if (isKinematic)
simStateRestoreBodyProperties(mSimStateData, getBodyCore().getCore());
mScene.getSimStateDataPool()->destroy(mSimStateData);
mSimStateData = NULL;
}
}
void BodySim::switchToKinematic()
{
setupSimStateData(true);
{
initKinematicStateBase(getBodyCore(), false);
// - interactions need to get refiltered to make sure that kinematic-kinematic and kinematic-static pairs get suppressed
// - unlike postSwitchToDynamic(), constraint interactions are not marked dirty here because a transition to kinematic will put the object asleep which in turn
// triggers onDeactivate() on the constraint pairs that are active. If such pairs get deactivated, they will get removed from the list of active breakable
// constraints automatically.
setActorsInteractionsDirty(InteractionDirtyFlag::eBODY_KINEMATIC, NULL, InteractionFlag::eFILTERABLE);
mScene.getSimpleIslandManager()->setKinematic(mNodeIndex);
updateBPGroup(this);
}
mScene.setDynamicsDirty();
mFilterFlags |= PxFilterObjectFlag::eKINEMATIC;
}
void BodySim::switchToDynamic()
{
tearDownSimStateData(true);
{
mScene.getSimpleIslandManager()->setDynamic(mNodeIndex);
setForcesToDefaults(true);
// - interactions need to get refiltered to make sure that former kinematic-kinematic and kinematic-static pairs get enabled
// - switching from kinematic to dynamic does not change the sleep state of the body. The constraint interactions are marked dirty
// to check later whether they need to be activated plus potentially tracked for constraint break testing. This special treatment
// is necessary because constraints between two kinematic bodies are considered inactive, no matter whether one of the kinematics
// is active (has a target) or not.
setActorsInteractionsDirty(InteractionDirtyFlag::eBODY_KINEMATIC, NULL, InteractionFlag::eFILTERABLE | InteractionFlag::eCONSTRAINT);
clearInternalFlag(BF_KINEMATIC_MOVE_FLAGS);
if(isActive())
mScene.swapInActiveBodyList(*this);
//
updateBPGroup(this);
}
mScene.setDynamicsDirty();
mFilterFlags &= ~PxFilterObjectFlag::eKINEMATIC;
}
void BodySim::setKinematicTarget(const PxTransform& p)
{
PX_ASSERT(getSimStateData(true));
PX_ASSERT(getSimStateData(true)->isKine());
simStateSetKinematicTarget(getSimStateData_Unchecked(), p);
PX_ASSERT(getSimStateData(true)->getKinematicData()->targetValid);
raiseInternalFlag(BF_KINEMATIC_MOVED); // Important to set this here already because trigger interactions need to have this information when being activated.
clearInternalFlag(BF_KINEMATIC_SURFACE_VELOCITY);
}
void BodySim::addSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc)
{
notifyDirtySpatialAcceleration();
if (!mSimStateData || !mSimStateData->isVelMod())
setupSimStateData(false);
VelocityMod* velmod = mSimStateData->getVelocityModData();
if (linAcc)
velmod->accumulateLinearVelModPerSec(*linAcc);
if (angAcc)
velmod->accumulateAngularVelModPerSec(*angAcc);
}
void BodySim::setSpatialAcceleration(const PxVec3* linAcc, const PxVec3* angAcc)
{
notifyDirtySpatialAcceleration();
if (!mSimStateData || !mSimStateData->isVelMod())
setupSimStateData(false);
VelocityMod* velmod = mSimStateData->getVelocityModData();
if (linAcc)
velmod->setLinearVelModPerSec(*linAcc);
if (angAcc)
velmod->setAngularVelModPerSec(*angAcc);
}
void BodySim::clearSpatialAcceleration(bool force, bool torque)
{
PX_ASSERT(force || torque);
notifyDirtySpatialAcceleration();
if (mSimStateData)
{
PX_ASSERT(mSimStateData->isVelMod());
VelocityMod* velmod = mSimStateData->getVelocityModData();
if (force)
velmod->clearLinearVelModPerSec();
if (torque)
velmod->clearAngularVelModPerSec();
}
}
void BodySim::addSpatialVelocity(const PxVec3* linVelDelta, const PxVec3* angVelDelta)
{
notifyDirtySpatialVelocity();
if (!mSimStateData || !mSimStateData->isVelMod())
setupSimStateData(false);
VelocityMod* velmod = mSimStateData->getVelocityModData();
if (linVelDelta)
velmod->accumulateLinearVelModPerStep(*linVelDelta);
if (angVelDelta)
velmod->accumulateAngularVelModPerStep(*angVelDelta);
}
void BodySim::clearSpatialVelocity(bool force, bool torque)
{
PX_ASSERT(force || torque);
notifyDirtySpatialVelocity();
if (mSimStateData)
{
PX_ASSERT(mSimStateData->isVelMod());
VelocityMod* velmod = mSimStateData->getVelocityModData();
if (force)
velmod->clearLinearVelModPerStep();
if (torque)
velmod->clearAngularVelModPerStep();
}
}
void BodySim::raiseVelocityModFlagAndNotify(VelocityModFlags flag)
{
//The dirty flag is stored separately in the BodySim so that we query the dirty flag before going to
//the expense of querying the simStateData for the velmod values.
raiseVelocityModFlag(flag);
if (!isArticulationLink())
mScene.getVelocityModifyMap().growAndSet(getNodeIndex().index());
else
mScene.addDirtyArticulationSim(getArticulation());
}
void BodySim::postActorFlagChange(PxU32 oldFlags, PxU32 newFlags)
{
// PT: don't convert to bool if not needed
const PxU32 wasWeightless = oldFlags & PxActorFlag::eDISABLE_GRAVITY;
const PxU32 isWeightless = newFlags & PxActorFlag::eDISABLE_GRAVITY;
if (isWeightless != wasWeightless)
{
if (mVelModState == 0)
raiseVelocityModFlag(VMF_GRAVITY_DIRTY);
getBodyCore().getCore().disableGravity = isWeightless!=0;
if(mArticulation)
mArticulation->setArticulationDirty(ArticulationDirtyFlag::eDIRTY_LINKS); // forces an update in PxgSimulationController::updateGpuArticulationSim
}
}
void BodySim::postBody2WorldChange()
{
mLLBody.saveLastCCDTransform();
notifyShapesOfTransformChange();
}
void BodySim::postSetWakeCounter(PxReal t, bool forceWakeUp)
{
if ((t > 0.0f) || forceWakeUp)
notifyNotReadyForSleeping();
else
{
const bool readyForSleep = checkSleepReadinessBesidesWakeCounter();
if (readyForSleep)
notifyReadyForSleeping();
}
}
void BodySim::postPosePreviewChange(PxU32 posePreviewFlag)
{
if (isActive())
{
if (posePreviewFlag & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW)
mScene.addToPosePreviewList(*this);
else
mScene.removeFromPosePreviewList(*this);
}
else
PX_ASSERT(!mScene.isInPosePreviewList(*this));
}
void BodySim::activate()
{
BodyCore& core = getBodyCore();
// Activate body
{
PX_ASSERT((!isKinematic()) || notInScene() || readInternalFlag(InternalFlags(BF_KINEMATIC_MOVED | BF_KINEMATIC_SURFACE_VELOCITY))); // kinematics should only get activated when a target is set.
// exception: object gets newly added, then the state change will happen later
if(!isArticulationLink())
{
mLLBody.mInternalFlags &= (~PxsRigidBody::eFROZEN);
// Put in list of activated bodies. The list gets cleared at the end of a sim step after the sleep callbacks have been fired.
mScene.onBodyWakeUp(this);
}
if(core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW)
{
PX_ASSERT(!mScene.isInPosePreviewList(*this));
mScene.addToPosePreviewList(*this);
}
createSqBounds();
}
activateInteractions(*this);
//set speculative CCD bit map if speculative CCD flag is on
if(core.getFlags() & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD)
addToSpeculativeCCDMap();
}
void BodySim::deactivate()
{
deactivateInteractions(*this);
BodyCore& core = getBodyCore();
// Deactivate body
{
PX_ASSERT((!isKinematic()) || notInScene() || !readInternalFlag(BF_KINEMATIC_MOVED)); // kinematics should only get deactivated when no target is set.
// exception: object gets newly added, then the state change will happen later
if(!readInternalFlag(BF_ON_DEATHROW))
{
// Set velocity to 0.
// Note: this is also fine if the method gets called because the user puts something to sleep (this behavior is documented in the API)
PX_ASSERT(core.getWakeCounter() == 0.0f);
const PxVec3 zero(0.0f);
core.setLinearVelocityInternal(zero);
core.setAngularVelocityInternal(zero);
setForcesToDefaults(!core.getCore().disableGravity);
}
if(!isArticulationLink()) // Articulations have their own sleep logic.
mScene.onBodySleep(this);
if(core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW)
{
PX_ASSERT(mScene.isInPosePreviewList(*this));
mScene.removeFromPosePreviewList(*this);
}
destroySqBounds();
}
// reset speculative CCD bit map if speculative CCD flag is on
if(core.getFlags() & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD)
removeFromSpeculativeCCDMap();
}
void BodySim::wakeUp()
{
setActive(true);
notifyWakeUp();
}
void BodySim::putToSleep()
{
PX_ASSERT(getBodyCore().getWakeCounter() == 0.0f);
PX_ASSERT(getBodyCore().getLinearVelocity().isZero());
PX_ASSERT(getBodyCore().getAngularVelocity().isZero());
notifyDirtySpatialAcceleration();
notifyDirtySpatialVelocity();
simStateClearVelMod(getSimStateData_Unchecked());
setActive(false);
notifyPutToSleep();
}
void BodySim::internalWakeUp(PxReal wakeCounterValue)
{
if(mArticulation)
mArticulation->internalWakeUp(wakeCounterValue);
else
internalWakeUpBase(wakeCounterValue);
}
void BodySim::internalWakeUpArticulationLink(PxReal wakeCounterValue)
{
PX_ASSERT(mArticulation);
internalWakeUpBase(wakeCounterValue);
}
void BodySim::internalWakeUpBase(PxReal wakeCounterValue) //this one can only increase the wake counter, not decrease it, so it can't be used to put things to sleep!
{
if ((!isKinematic()) && (getBodyCore().getWakeCounter() < wakeCounterValue))
{
PX_ASSERT(wakeCounterValue > 0.0f);
getBodyCore().setWakeCounterFromSim(wakeCounterValue);
//we need to update the gpu body sim because we reset the wake counter for the body core
mScene.updateBodySim(*this);
setActive(true);
notifyWakeUp();
if(0) // PT: commented-out for PX-2197
mLLBody.mInternalFlags &= (~PxsRigidBody::eFROZEN);
}
}
void BodySim::notifyReadyForSleeping()
{
if(mArticulation == NULL)
mScene.getSimpleIslandManager()->deactivateNode(mNodeIndex);
}
void BodySim::notifyNotReadyForSleeping()
{
mScene.getSimpleIslandManager()->activateNode(mNodeIndex);
}
void BodySim::notifyWakeUp()
{
mScene.getSimpleIslandManager()->activateNode(mNodeIndex);
}
void BodySim::notifyPutToSleep()
{
mScene.getSimpleIslandManager()->putNodeToSleep(mNodeIndex);
}
//This function will be called by CPU sleepCheck code
// PT: TODO: actually this seems to be only called by the articulation sim code, while regular rigid bodies use a copy of that code in LowLevelDynamics?
PxReal BodySim::updateWakeCounter(PxReal dt, PxReal energyThreshold, const Cm::SpatialVector& motionVelocity)
{
// update the body's sleep state and
BodyCore& core = getBodyCore();
const PxReal wakeCounterResetTime = ScInternalWakeCounterResetValue;
PxReal wc = core.getWakeCounter();
{
PxVec3 bcSleepLinVelAcc = mLLBody.mSleepLinVelAcc;
PxVec3 bcSleepAngVelAcc = mLLBody.mSleepAngVelAcc;
if(wc < wakeCounterResetTime * 0.5f || wc < dt)
{
const PxTransform& body2World = getBody2World();
// calculate normalized energy: kinetic energy divided by mass
const PxVec3 t = core.getInverseInertia();
const PxVec3 inertia(t.x > 0.0f ? 1.0f/t.x : 1.0f, t.y > 0.0f ? 1.0f/t.y : 1.0f, t.z > 0.0f ? 1.0f/t.z : 1.0f);
PxVec3 sleepLinVelAcc = motionVelocity.linear;
PxVec3 sleepAngVelAcc = body2World.q.rotateInv(motionVelocity.angular);
bcSleepLinVelAcc += sleepLinVelAcc;
bcSleepAngVelAcc += sleepAngVelAcc;
PxReal invMass = core.getInverseMass();
if(invMass == 0.0f)
invMass = 1.0f;
const PxReal angular = bcSleepAngVelAcc.multiply(bcSleepAngVelAcc).dot(inertia) * invMass;
const PxReal linear = bcSleepLinVelAcc.magnitudeSquared();
const PxReal normalizedEnergy = 0.5f * (angular + linear);
// scale threshold by cluster factor (more contacts => higher sleep threshold)
const PxReal clusterFactor = PxReal(1 + getNumCountedInteractions());
const PxReal threshold = clusterFactor*energyThreshold;
if (normalizedEnergy >= threshold)
{
PX_ASSERT(isActive());
mLLBody.resetSleepFilter();
const float factor = threshold == 0.0f ? 2.0f : PxMin(normalizedEnergy/threshold, 2.0f);
PxReal oldWc = wc;
wc = factor * 0.5f * wakeCounterResetTime + dt * (clusterFactor - 1.0f);
core.setWakeCounterFromSim(wc);
if (oldWc == 0.0f) // for the case where a sleeping body got activated by the system (not the user) AND got processed by the solver as well
notifyNotReadyForSleeping();
return wc;
}
}
mLLBody.mSleepLinVelAcc = bcSleepLinVelAcc;
mLLBody.mSleepAngVelAcc = bcSleepAngVelAcc;
}
wc = PxMax(wc-dt, 0.0f);
core.setWakeCounterFromSim(wc);
return wc;
}
PX_FORCE_INLINE void BodySim::initKinematicStateBase(BodyCore&, bool asPartOfCreation)
{
PX_ASSERT(!readInternalFlag(BF_KINEMATIC_MOVED));
if (!asPartOfCreation && isActive())
mScene.swapInActiveBodyList(*this);
//mLLBody.setAccelerationV(Cm::SpatialVector::zero());
// Need to be before setting setRigidBodyFlag::KINEMATIC
}
bool BodySim::updateForces(PxReal dt, PxsRigidBody** updatedBodySims, PxU32* updatedBodyNodeIndices, PxU32& index, Cm::SpatialVector* acceleration,
PxsExternalAccelerationProvider* externalAccelerations, PxU32 maxNumExternalAccelerations)
{
PxVec3 linVelDt(0.0f), angVelDt(0.0f);
const bool accDirty = readVelocityModFlag(VMF_ACC_DIRTY);
const bool velDirty = readVelocityModFlag(VMF_VEL_DIRTY);
SimStateData* simStateData = NULL;
bool forceChangeApplied = false;
//if we change the logic like this, which means we don't need to have two separate variables in the pxgbodysim to represent linAcc and angAcc. However, this
//means angAcc will be always 0
if( (accDirty || velDirty) && ((simStateData = getSimStateData(false)) != NULL) )
{
VelocityMod* velmod = simStateData->getVelocityModData();
//we don't have support for articulation yet
if (updatedBodySims)
{
updatedBodySims[index] = &getLowLevelBody();
updatedBodyNodeIndices[index++] = getNodeIndex().index();
}
if(velDirty)
{
linVelDt = velmod->getLinearVelModPerStep();
angVelDt = velmod->getAngularVelModPerStep();
}
if (accDirty)
{
linVelDt += velmod->getLinearVelModPerSec()*dt;
angVelDt += velmod->getAngularVelModPerSec()*dt;
}
if (acceleration)
{
const PxReal invDt = 1.f / dt;
acceleration->linear = linVelDt * invDt;
acceleration->angular = angVelDt * invDt;
}
else
{
if (mScene.getFlags() & PxSceneFlag::eENABLE_EXTERNAL_FORCES_EVERY_ITERATION_TGS)
{
if (linVelDt != PxVec3(0.0f) || angVelDt != PxVec3(0.0f))
{
const PxReal invDt = 1.f / dt;
PxsRigidBodyExternalAcceleration acc(linVelDt * invDt, angVelDt * invDt);
externalAccelerations->setValue(acc, getNodeIndex().index(), maxNumExternalAccelerations);
}
}
else
getBodyCore().updateVelocities(linVelDt, angVelDt);
}
forceChangeApplied = true;
}
setForcesToDefaults(readVelocityModFlag(VMF_ACC_DIRTY));
return forceChangeApplied;
}
void BodySim::onConstraintDetach()
{
PX_ASSERT(readInternalFlag(BF_HAS_CONSTRAINTS));
PxU32 size = getActorInteractionCount();
Interaction** interactions = getActorInteractions();
unregisterCountedInteraction();
while(size--)
{
const Interaction* interaction = *interactions++;
if(interaction->getType() == InteractionType::eCONSTRAINTSHADER)
return;
}
clearInternalFlag(BF_HAS_CONSTRAINTS); // There are no other constraint interactions left
}
void BodySim::setArticulation(ArticulationSim* a, PxReal wakeCounter, bool asleep, PxU32 bodyIndex)
{
mArticulation = a;
if(a)
{
PxNodeIndex index = mArticulation->getIslandNodeIndex();
mNodeIndex.setIndices(index.index(), bodyIndex);
getBodyCore().setWakeCounterFromSim(wakeCounter);
if (getFlagsFast() & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD)
mScene.setSpeculativeCCDArticulationLink(mNodeIndex.index());
//Articulations defer registering their shapes with the nphaseContext until the IG node index is known.
{
// PT: TODO: skip this on CPU
PxvNphaseImplementationContext* ctx = mScene.getLowLevelContext()->getNphaseImplementationContext();
ElementSim** current = getElements();
PxU32 nbElements = getNbElements();
while (nbElements--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*current++);
ctx->registerShape(mNodeIndex, sim->getCore().getCore(), sim->getElementID(), sim->getActor().getPxActor());
}
}
//Force node index into LL shapes
{
PxsSimulationController* sc = getScene().getSimulationController();
if(sc->mGPU)
{
const PxNodeIndex nodeIndex = mNodeIndex;
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
sc->setPxgShapeBodyNodeIndex(nodeIndex, sim->getElementID());
}
}
}
if (a->getCore().getArticulationFlags() & PxArticulationFlag::eDISABLE_SELF_COLLISION)
{
//We need to reset the group IDs for all shapes in this body...
ElementSim** current = getElements();
PxU32 nbElements = getNbElements();
Bp::AABBManagerBase* aabbMgr = mScene.getAABBManager();
Bp::FilterGroup::Enum rootGroup = Bp::getFilterGroup(false, a->getRootActorIndex(), false);
while (nbElements--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*current++);
aabbMgr->setBPGroup(sim->getElementID(), rootGroup);
}
}
if (!asleep)
{
setActive(true);
notifyWakeUp();
}
else
{
notifyReadyForSleeping();
notifyPutToSleep();
setActive(false);
}
}
else
{
//Setting a 1 in the articulation ID to avoid returning the node Index to the node index
//manager
mNodeIndex.setIndices(PX_INVALID_NODE, 1);
}
}
void BodySim::createSqBounds()
{
if(!isActive() || usingSqKinematicTarget() || readInternalFlag(BF_IS_COMPOUND_RIGID))
return;
PX_ASSERT(!isFrozen());
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
current->createSqBounds();
}
}
void BodySim::destroySqBounds()
{
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
current->destroySqBounds();
}
}
void BodySim::freezeTransforms(PxBitMapPinned* shapeChangedMap)
{
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
sim->updateCached(PxsTransformFlag::eFROZEN, shapeChangedMap);
sim->destroySqBounds();
}
}
void BodySim::disableCompound()
{
if(isActive())
mScene.removeFromActiveCompoundBodyList(*this);
clearInternalFlag(BF_IS_COMPOUND_RIGID);
}

View File

@@ -0,0 +1,275 @@
// 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

View File

@@ -0,0 +1,139 @@
// 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.
#include "ScBroadphase.h"
#include "BpAABBManagerBase.h"
#include "ScShapeSim.h"
#include "common/PxProfileZone.h"
using namespace physx;
using namespace Sc;
using namespace Bp;
///////////////////////////////////////////////////////////////////////////////
BroadphaseManager::BroadphaseManager() :
mBroadPhaseCallback (NULL),
mOutOfBoundsIDs ("sceneOutOfBoundsIds")
{
}
BroadphaseManager::~BroadphaseManager()
{
}
void BroadphaseManager::prepareOutOfBoundsCallbacks(AABBManagerBase* aabbManager)
{
AABBManagerBase::OutOfBoundsData data;
if(!aabbManager->getOutOfBoundsObjects(data))
return;
PxU32 nbOut = data.mNbOutOfBoundsObjects;
void** outObjects = data.mOutOfBoundsObjects;
mOutOfBoundsIDs.clear();
while(nbOut--)
{
const ElementSim* volume = reinterpret_cast<const ElementSim*>(*outObjects++);
const Sc::ShapeSim* sim = static_cast<const Sc::ShapeSim*>(volume);
mOutOfBoundsIDs.pushBack(sim->getElementID());
}
}
bool BroadphaseManager::fireOutOfBoundsCallbacks(Bp::AABBManagerBase* aabbManager, const ObjectIDTracker& tracker, PxU64 contextID)
{
PX_UNUSED(contextID);
AABBManagerBase::OutOfBoundsData data;
if(!aabbManager->getOutOfBoundsObjects(data))
return false;
bool outputWarning = false;
PxBroadPhaseCallback* cb = mBroadPhaseCallback;
// Actors
{
PxU32 nbOut = data.mNbOutOfBoundsObjects;
void** outObjects = data.mOutOfBoundsObjects;
for(PxU32 i=0;i<nbOut;i++)
{
ElementSim* volume = reinterpret_cast<ElementSim*>(outObjects[i]);
Sc::ShapeSim* sim = static_cast<Sc::ShapeSim*>(volume);
// PT: TODO: I'm not sure the split between prepareOutOfBoundsCallbacks / fireOutOfBoundsCallbacks
// and the test for deletion is still needed after the removal of SCB
if(tracker.isDeletedID(mOutOfBoundsIDs[i]))
continue;
if(cb)
{
PX_PROFILE_ZONE("USERCODE - PxBroadPhaseCallback::onObjectOutOfBounds", contextID);
ActorSim& actor = volume->getActor();
RigidSim& rigidSim = static_cast<RigidSim&>(actor);
PxActor* pxActor = rigidSim.getPxActor();
PxShape* px = sim->getPxShape();
cb->onObjectOutOfBounds(*px, *pxActor);
}
else
outputWarning = true;
}
}
// Aggregates
{
PxU32 nbOut = data.mNbOutOfBoundsAggregates;
void** outAgg = data.mOutOfBoundsAggregates;
for(PxU32 i=0;i<nbOut;i++)
{
PxAggregate* px = reinterpret_cast<PxAggregate*>(outAgg[i]);
if(cb)
{
PX_PROFILE_ZONE("USERCODE - PxBroadPhaseCallback::onObjectOutOfBounds", contextID);
cb->onObjectOutOfBounds(*px);
}
else
outputWarning = true;
}
}
aabbManager->clearOutOfBoundsObjects();
return outputWarning;
}
void BroadphaseManager::flush(Bp::AABBManagerBase* /*aabbManager*/)
{
mOutOfBoundsIDs.reset();
}

View File

@@ -0,0 +1,720 @@
// 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.
#include "common/PxProfileZone.h"
#include "ScBodySim.h"
#include "ScShapeSim.h"
#include "ScArticulationSim.h"
#include "ScScene.h"
#include "DyIslandManager.h"
using namespace physx;
using namespace Sc;
///////////////////////////////////////////////////////////////////////////////
void BodySim::addToSpeculativeCCDMap()
{
if(mNodeIndex.isValid())
{
if(isArticulationLink())
mScene.setSpeculativeCCDArticulationLink(mNodeIndex.index());
else
mScene.setSpeculativeCCDRigidBody(mNodeIndex.index());
}
}
void BodySim::removeFromSpeculativeCCDMap()
{
if(mNodeIndex.isValid())
{
if(isArticulationLink())
mScene.resetSpeculativeCCDArticulationLink(mNodeIndex.index());
else
mScene.resetSpeculativeCCDRigidBody(mNodeIndex.index());
}
}
// PT: TODO: consider using a non-member function for this one
void BodySim::updateContactDistance(PxReal* contactDistance, PxReal dt, const Bp::BoundsArray& boundsArray)
{
const PxsRigidBody& llBody = getLowLevelBody();
const PxRigidBodyFlags flags = llBody.getCore().mFlags;
// PT: TODO: no need to test eENABLE_SPECULATIVE_CCD if we parsed mSpeculativeCCDRigidBodyBitMap initially
if((flags & PxRigidBodyFlag::eENABLE_SPECULATIVE_CCD) && !(llBody.mInternalFlags & PxsRigidBody::eFROZEN))
{
// PT: if both CCD flags are enabled we're in "hybrid mode" and we only use speculative contacts for the angular part
const PxReal linearInflation = (flags & PxRigidBodyFlag::eENABLE_CCD) ? 0.0f : llBody.getLinearVelocity().magnitude() * dt;
const float angVelMagTimesDt = llBody.getAngularVelocity().magnitude() * dt;
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while(nbElems--)
{
ShapeSim* current = static_cast<ShapeSim*>(*elems++);
const PxU32 index = current->getElementID();
const PxBounds3& bounds = boundsArray.getBounds(index);
const PxReal radius = bounds.getExtents().magnitude();
//Heuristic for angular velocity...
const PxReal angularInflation = angVelMagTimesDt * radius;
contactDistance[index] = linearInflation + current->getContactOffset() + angularInflation;
}
}
}
void Sc::ArticulationSim::updateContactDistance(PxReal* contactDistance, PxReal dt, const Bp::BoundsArray& boundsArray)
{
const PxU32 size = mBodies.size();
for(PxU32 i=0; i<size; i++)
mBodies[i]->updateContactDistance(contactDistance, dt, boundsArray);
}
namespace
{
class SpeculativeCCDBaseTask : public Cm::Task
{
PX_NOCOPY(SpeculativeCCDBaseTask)
public:
const Bp::BoundsArray& mBoundsArray;
float* mContactDistances;
const float mDt;
SpeculativeCCDBaseTask(PxU64 contextID, const Bp::BoundsArray& boundsArray, PxReal* contactDistances, PxReal dt) :
Cm::Task (contextID),
mBoundsArray (boundsArray),
mContactDistances (contactDistances),
mDt (dt)
{}
};
class SpeculativeCCDContactDistanceUpdateTask : public SpeculativeCCDBaseTask
{
public:
static const PxU32 MaxBodies = 128;
BodySim* mBodySims[MaxBodies];
PxU32 mNbBodies;
SpeculativeCCDContactDistanceUpdateTask(PxU64 contextID, PxReal* contactDistances, PxReal dt, const Bp::BoundsArray& boundsArray) :
SpeculativeCCDBaseTask (contextID, boundsArray, contactDistances, dt),
mNbBodies (0)
{}
virtual void runInternal()
{
const PxU32 nb = mNbBodies;
for(PxU32 i=0; i<nb; i++)
mBodySims[i]->updateContactDistance(mContactDistances, mDt, mBoundsArray);
}
virtual const char* getName() const { return "SpeculativeCCDContactDistanceUpdateTask"; }
private:
PX_NOCOPY(SpeculativeCCDContactDistanceUpdateTask)
};
class SpeculativeCCDContactDistanceArticulationUpdateTask : public SpeculativeCCDBaseTask
{
public:
ArticulationSim* mArticulation;
SpeculativeCCDContactDistanceArticulationUpdateTask(PxU64 contextID, PxReal* contactDistances, PxReal dt, const Bp::BoundsArray& boundsArray, ArticulationSim* sim) :
SpeculativeCCDBaseTask (contextID, boundsArray, contactDistances, dt),
mArticulation (sim)
{}
virtual void runInternal()
{
mArticulation->updateContactDistance(mContactDistances, mDt, mBoundsArray);
}
virtual const char* getName() const { return "SpeculativeCCDContactDistanceArticulationUpdateTask"; }
private:
PX_NOCOPY(SpeculativeCCDContactDistanceArticulationUpdateTask)
};
}
static SpeculativeCCDContactDistanceUpdateTask* createCCDTask(Cm::FlushPool& pool, PxU64 contextID, PxReal* contactDistances, PxReal dt, const Bp::BoundsArray& boundsArray)
{
return PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceUpdateTask)), SpeculativeCCDContactDistanceUpdateTask)(contextID, contactDistances, dt, boundsArray);
}
void Sc::Scene::updateContactDistances(PxBaseTask* continuation)
{
PX_PROFILE_ZONE("Scene.updateContactDistances", mContextId);
Cm::FlushPool& pool = mLLContext->getTaskPool();
IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim();
bool hasContactDistanceChanged = mHasContactDistanceChanged;
// PT: TODO: it is quite unfortunate that we cannot shortcut parsing the bitmaps. Consider switching to arrays.
// We remove sleeping bodies from the map but we never shrink it....
// PT: TODO: why do we need to involve the island manager here?
// PT: TODO: why do we do that on sleeping bodies? Why don't we use mActiveBodies?
// PxArray<BodyCore*> mActiveBodies; // Sorted: kinematic before dynamic
// ===> because we remove bodies from the bitmap in BodySim::deactivate()
//calculate contact distance for speculative CCD shapes
if(1)
{
PxBitMap::Iterator speculativeCCDIter(mSpeculativeCCDRigidBodyBitMap);
SpeculativeCCDContactDistanceUpdateTask* ccdTask = createCCDTask(pool, mContextId, mContactDistance->begin(), mDt, *mBoundsArray);
PxBitMapPinned& changedMap = mAABBManager->getChangedAABBMgActorHandleMap();
const size_t bodyOffset = PX_OFFSET_OF_RT(BodySim, getLowLevelBody());
//printf("\n");
//PxU32 count = 0;
PxU32 nbBodies = 0;
PxU32 index;
while((index = speculativeCCDIter.getNext()) != PxBitMap::Iterator::DONE)
{
PxsRigidBody* rigidBody = getRigidBodyFromIG(islandSim, PxNodeIndex(index));
BodySim* bodySim = reinterpret_cast<BodySim*>(reinterpret_cast<PxU8*>(rigidBody)-bodyOffset);
if(bodySim)
{
//printf("%d\n", bodySim->getActiveListIndex());
//printf("%d: %d\n", count++, bodySim->isActive());
hasContactDistanceChanged = true;
ccdTask->mBodySims[nbBodies++] = bodySim;
// PT: ### changedMap pattern #1
// PT: TODO: isn't there a problem here? The task function will only touch the shapes whose body has the
// speculative flag and isn't frozen, but here we mark all shapes as changed no matter what.
//
// Also we test some bodySim data and one bit of each ShapeSim here, not great.
PxU32 nbElems = bodySim->getNbElements();
ElementSim** elems = bodySim->getElements();
while(nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
if(sim->getFlags() & PxShapeFlag::eSIMULATION_SHAPE)
changedMap.growAndSet(sim->getElementID());
}
// PT: TODO: better load balancing?
if(nbBodies == SpeculativeCCDContactDistanceUpdateTask::MaxBodies)
{
ccdTask->mNbBodies = nbBodies;
nbBodies = 0;
startTask(ccdTask, continuation);
if(continuation)
ccdTask = createCCDTask(pool, mContextId, mContactDistance->begin(), mDt, *mBoundsArray);
else
ccdTask->mNbBodies = 0; // PT: no need to create a new task in single-threaded mode
}
}
}
if(nbBodies)
{
ccdTask->mNbBodies = nbBodies;
startTask(ccdTask, continuation);
}
}
/* else
{
// PT: codepath without mSpeculativeCCDRigidBodyBitMap
PxU32 nb = mActiveBodies.size();
BodyCore** bodies = mActiveBodies.begin();
while(nb--)
{
const BodyCore* current = *bodies++;
BodySim* bodySim = current->getSim();
if(bodySim)
{
...
}
}
}*/
//calculate contact distance for articulation links
{
PxBitMap::Iterator articulateCCDIter(mSpeculativeCDDArticulationBitMap);
PxU32 index;
while((index = articulateCCDIter.getNext()) != PxBitMap::Iterator::DONE)
{
ArticulationSim* articulationSim = getArticulationSim(islandSim, PxNodeIndex(index));
if(articulationSim)
{
hasContactDistanceChanged = true;
if(continuation)
{
SpeculativeCCDContactDistanceArticulationUpdateTask* articulationUpdateTask = PX_PLACEMENT_NEW(pool.allocate(sizeof(SpeculativeCCDContactDistanceArticulationUpdateTask)), SpeculativeCCDContactDistanceArticulationUpdateTask)(mContextId, mContactDistance->begin(), mDt, *mBoundsArray, articulationSim);
articulationUpdateTask->setContinuation(continuation);
articulationUpdateTask->removeReference();
}
else
{
articulationSim->updateContactDistance(mContactDistance->begin(), mDt, *mBoundsArray);
}
}
}
}
mHasContactDistanceChanged = hasContactDistanceChanged;
}
///////////////////////////////////////////////////////////////////////////////
#include "ScNPhaseCore.h"
#include "ScShapeInteraction.h"
#include "PxsCCD.h"
#include "PxsSimulationController.h"
#include "CmTransformUtils.h"
void Sc::Scene::setCCDContactModifyCallback(PxCCDContactModifyCallback* callback)
{
mCCDContext->setCCDContactModifyCallback(callback);
}
PxCCDContactModifyCallback* Sc::Scene::getCCDContactModifyCallback() const
{
return mCCDContext->getCCDContactModifyCallback();
}
void Sc::Scene::setCCDMaxPasses(PxU32 ccdMaxPasses)
{
mCCDContext->setCCDMaxPasses(ccdMaxPasses);
}
PxU32 Sc::Scene::getCCDMaxPasses() const
{
return mCCDContext->getCCDMaxPasses();
}
void Sc::Scene::setCCDThreshold(PxReal t)
{
mCCDContext->setCCDThreshold(t);
}
PxReal Sc::Scene::getCCDThreshold() const
{
return mCCDContext->getCCDThreshold();
}
void Sc::Scene::collectPostSolverVelocitiesBeforeCCD()
{
if(mContactReportsNeedPostSolverVelocity)
{
ActorPairReport*const* actorPairs = mNPhaseCore->getContactReportActorPairs();
PxU32 nbActorPairs = mNPhaseCore->getNbContactReportActorPairs();
for(PxU32 i=0; i < nbActorPairs; i++)
{
if(i < (nbActorPairs - 1))
PxPrefetchLine(actorPairs[i+1]);
ActorPairReport* aPair = actorPairs[i];
ContactStreamManager& cs = aPair->getContactStreamManager();
PxU32 streamManagerFlag = cs.getFlags();
if(streamManagerFlag & ContactStreamManagerFlag::eINVALID_STREAM)
continue;
PxU8* stream = mNPhaseCore->getContactReportPairData(cs.bufferIndex);
if(i + 1 < nbActorPairs)
PxPrefetch(&(actorPairs[i+1]->getContactStreamManager()));
if(!cs.extraDataSize)
continue;
else if (streamManagerFlag & ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY)
cs.setContactReportPostSolverVelocity(stream, aPair->getActorA(), aPair->getActorB());
}
}
}
void Sc::Scene::updateCCDMultiPass(PxBaseTask* parentContinuation)
{
getCcdBodies().forceSize_Unsafe(mSimulationControllerCallback->getNbCcdBodies());
// second run of the broadphase for making sure objects we have integrated did not tunnel.
if(mPublicFlags & PxSceneFlag::eENABLE_CCD)
{
if(mContactReportsNeedPostSolverVelocity)
{
// the CCD code will overwrite the post solver body velocities, hence, we need to extract the info
// first if any CCD enabled pair requested it.
collectPostSolverVelocitiesBeforeCCD();
}
//We use 2 CCD task chains to be able to chain together an arbitrary number of ccd passes
if(mPostCCDPass.size() != 2)
{
mPostCCDPass.clear();
mUpdateCCDSinglePass.clear();
mCCDBroadPhase.clear();
mCCDBroadPhaseAABB.clear();
mPostCCDPass.reserve(2);
mUpdateCCDSinglePass.reserve(2);
mUpdateCCDSinglePass2.reserve(2);
mUpdateCCDSinglePass3.reserve(2);
mCCDBroadPhase.reserve(2);
mCCDBroadPhaseAABB.reserve(2);
for (int j = 0; j < 2; j++)
{
mPostCCDPass.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::postCCDPass>(mContextId, this, "ScScene.postCCDPass"));
mUpdateCCDSinglePass.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePass>(mContextId, this, "ScScene.updateCCDSinglePass"));
mUpdateCCDSinglePass2.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePassStage2>(mContextId, this, "ScScene.updateCCDSinglePassStage2"));
mUpdateCCDSinglePass3.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::updateCCDSinglePassStage3>(mContextId, this, "ScScene.updateCCDSinglePassStage3"));
mCCDBroadPhase.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::ccdBroadPhase>(mContextId, this, "ScScene.ccdBroadPhase"));
mCCDBroadPhaseAABB.pushBack(Cm::DelegateTask<Sc::Scene, &Sc::Scene::ccdBroadPhaseAABB>(mContextId, this, "ScScene.ccdBroadPhaseAABB"));
}
}
//reset thread context in a place we know all tasks possibly accessing it, are in sync with. (see US6664)
mLLContext->resetThreadContexts();
mCCDContext->updateCCDBegin();
mCCDBroadPhase[0].setContinuation(parentContinuation);
mCCDBroadPhaseAABB[0].setContinuation(&mCCDBroadPhase[0]);
mCCDBroadPhase[0].removeReference();
mCCDBroadPhaseAABB[0].removeReference();
}
}
namespace
{
class UpdateCCDBoundsTask : public Cm::Task
{
Bp::BoundsArray* mBoundArray;
PxsTransformCache* mTransformCache;
BodySim** mBodySims;
PxU32 mNbToProcess;
PxI32* mNumFastMovingShapes;
public:
static const PxU32 MaxPerTask = 256;
UpdateCCDBoundsTask(PxU64 contextID, Bp::BoundsArray* boundsArray, PxsTransformCache* transformCache, BodySim** bodySims, PxU32 nbToProcess, PxI32* numFastMovingShapes) :
Cm::Task (contextID),
mBoundArray (boundsArray),
mTransformCache (transformCache),
mBodySims (bodySims),
mNbToProcess (nbToProcess),
mNumFastMovingShapes(numFastMovingShapes)
{
}
virtual const char* getName() const { return "UpdateCCDBoundsTask";}
PxIntBool updateSweptBounds(ShapeSim* sim, BodySim* body)
{
PX_ASSERT(body==sim->getBodySim());
const PxU32 elementID = sim->getElementID();
const ShapeCore& shapeCore = sim->getCore();
const PxTransform& endPose = mTransformCache->getTransformCache(elementID).transform;
const PxGeometry& shapeGeom = shapeCore.getGeometry();
const PxsRigidBody& rigidBody = body->getLowLevelBody();
const PxsBodyCore& bodyCore = body->getBodyCore().getCore();
PX_ALIGN(16, PxTransform shape2World);
Cm::getDynamicGlobalPoseAligned(rigidBody.mLastTransform, shapeCore.getShape2Actor(), bodyCore.getBody2Actor(), shape2World);
const float ccdThreshold = computeCCDThreshold(shapeGeom);
PxBounds3 bounds = Gu::computeBounds(shapeGeom, endPose);
PxIntBool isFastMoving;
if(1)
{
// PT: this alternative implementation avoids computing the start bounds for slow moving objects.
isFastMoving = (shape2World.p - endPose.p).magnitudeSquared() >= ccdThreshold * ccdThreshold ? 1 : 0;
if(isFastMoving)
{
const PxBounds3 startBounds = Gu::computeBounds(shapeGeom, shape2World);
bounds.include(startBounds);
}
}
else
{
const PxBounds3 startBounds = Gu::computeBounds(shapeGeom, shape2World);
isFastMoving = (startBounds.getCenter() - bounds.getCenter()).magnitudeSquared() >= ccdThreshold * ccdThreshold ? 1 : 0;
if(isFastMoving)
bounds.include(startBounds);
}
PX_ASSERT(bounds.minimum.x <= bounds.maximum.x
&& bounds.minimum.y <= bounds.maximum.y
&& bounds.minimum.z <= bounds.maximum.z);
mBoundArray->setBounds(bounds, elementID);
return isFastMoving;
}
virtual void runInternal()
{
PxU32 activeShapes = 0;
const PxU32 nb = mNbToProcess;
for(PxU32 i=0; i<nb; i++)
{
PxU32 isFastMoving = 0;
BodySim& bodySim = *mBodySims[i];
PxU32 nbElems = bodySim.getNbElements();
ElementSim** elems = bodySim.getElements();
while(nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
if(sim->getFlags() & PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE))
{
const PxIntBool fastMovingShape = updateSweptBounds(sim, &bodySim);
activeShapes += fastMovingShape;
isFastMoving = isFastMoving | fastMovingShape;
}
}
bodySim.getLowLevelBody().getCore().isFastMoving = isFastMoving!=0;
}
PxAtomicAdd(mNumFastMovingShapes, PxI32(activeShapes));
}
};
}
void Sc::Scene::ccdBroadPhaseAABB(PxBaseTask* continuation)
{
PX_PROFILE_START_CROSSTHREAD("Sim.ccdBroadPhaseComplete", mContextId);
PX_PROFILE_ZONE("Sim.ccdBroadPhaseAABB", mContextId);
PX_UNUSED(continuation);
PxU32 currentPass = mCCDContext->getCurrentCCDPass();
Cm::FlushPool& flushPool = mLLContext->getTaskPool();
mNumFastMovingShapes = 0;
//If we are on the 1st pass or we had some sweep hits previous CCD pass, we need to run CCD again
if(currentPass == 0 || mCCDContext->getNumSweepHits())
{
PxsTransformCache& transformCache = getLowLevelContext()->getTransformCache();
for(PxU32 i = 0; i < mCcdBodies.size(); i+= UpdateCCDBoundsTask::MaxPerTask)
{
const PxU32 nbToProcess = PxMin(UpdateCCDBoundsTask::MaxPerTask, mCcdBodies.size() - i);
UpdateCCDBoundsTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(UpdateCCDBoundsTask)), UpdateCCDBoundsTask)(mContextId, mBoundsArray, &transformCache, &mCcdBodies[i], nbToProcess, &mNumFastMovingShapes);
task->setContinuation(continuation);
task->removeReference();
}
}
}
void Sc::Scene::ccdBroadPhase(PxBaseTask* continuation)
{
PX_PROFILE_ZONE("Sim.ccdBroadPhase", mContextId);
PxU32 currentPass = mCCDContext->getCurrentCCDPass();
const PxU32 ccdMaxPasses = mCCDContext->getCCDMaxPasses();
mCCDPass = currentPass+1;
//If we are on the 1st pass or we had some sweep hits previous CCD pass, we need to run CCD again
if( (currentPass == 0 || mCCDContext->getNumSweepHits()) && mNumFastMovingShapes != 0)
{
const PxU32 currIndex = currentPass & 1;
const PxU32 nextIndex = 1 - currIndex;
//Initialize the CCD task chain unless this is the final pass
if(currentPass != (ccdMaxPasses - 1))
{
mCCDBroadPhase[nextIndex].setContinuation(continuation);
mCCDBroadPhaseAABB[nextIndex].setContinuation(&mCCDBroadPhase[nextIndex]);
}
mPostCCDPass[currIndex].setContinuation(currentPass == ccdMaxPasses-1 ? continuation : &mCCDBroadPhaseAABB[nextIndex]);
mUpdateCCDSinglePass3[currIndex].setContinuation(&mPostCCDPass[currIndex]);
mUpdateCCDSinglePass2[currIndex].setContinuation(&mUpdateCCDSinglePass3[currIndex]);
mUpdateCCDSinglePass[currIndex].setContinuation(&mUpdateCCDSinglePass2[currIndex]);
//Do the actual broad phase
PxBaseTask* continuationTask = &mUpdateCCDSinglePass[currIndex];
// const PxU32 numCpuTasks = continuationTask->getTaskManager()->getCpuDispatcher()->getWorkerCount();
mCCDBp = true;
setupBroadPhaseFirstAndSecondPassTasks(continuationTask);
//mAABBManager->updateAABBsAndBP(numCpuTasks, mLLContext->getTaskPool(), &mLLContext->getScratchAllocator(), false, continuationTask, NULL);
//Allow the CCD task chain to continue
mPostCCDPass[currIndex].removeReference();
mUpdateCCDSinglePass3[currIndex].removeReference();
mUpdateCCDSinglePass2[currIndex].removeReference();
mUpdateCCDSinglePass[currIndex].removeReference();
if(currentPass != (ccdMaxPasses - 1))
{
mCCDBroadPhase[nextIndex].removeReference();
mCCDBroadPhaseAABB[nextIndex].removeReference();
}
}
else if (currentPass == 0)
{
PX_PROFILE_STOP_CROSSTHREAD("Sim.ccdBroadPhaseComplete", mContextId);
mCCDContext->resetContactManagers();
}
}
void Sc::Scene::updateCCDSinglePass(PxBaseTask* continuation)
{
PX_PROFILE_ZONE("Sim.updateCCDSinglePass", mContextId);
mReportShapePairTimeStamp++; // This will makes sure that new report pairs will get created instead of re-using the existing ones.
mAABBManager->postBroadPhase(NULL, *getFlushPool());
finishBroadPhase(continuation);
const PxU32 currentPass = mCCDContext->getCurrentCCDPass() + 1; // 0 is reserved for discrete collision phase
if(currentPass == 1) // reset the handle map so we only update CCD objects from here on
{
PxBitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap();
//changedAABBMgrActorHandles.clear();
for(PxU32 i = 0; i < mCcdBodies.size();i++)
{
// PT: ### changedMap pattern #1
PxU32 nbElems = mCcdBodies[i]->getNbElements();
ElementSim** elems = mCcdBodies[i]->getElements();
while(nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
if(sim->getFlags()&PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE)) // TODO: need trigger shape here?
changedAABBMgrActorHandles.growAndSet(sim->getElementID());
}
}
}
}
void Sc::Scene::updateCCDSinglePassStage2(PxBaseTask* continuation)
{
PX_PROFILE_ZONE("Sim.updateCCDSinglePassStage2", mContextId);
postBroadPhaseStage2(continuation);
}
void Sc::Scene::updateCCDSinglePassStage3(PxBaseTask* continuation)
{
PX_PROFILE_ZONE("Sim.updateCCDSinglePassStage3", mContextId);
mReportShapePairTimeStamp++; // This will makes sure that new report pairs will get created instead of re-using the existing ones.
const PxU32 currentPass = mCCDContext->getCurrentCCDPass() + 1; // 0 is reserved for discrete collision phase
finishBroadPhaseStage2(currentPass);
PX_PROFILE_STOP_CROSSTHREAD("Sim.ccdBroadPhaseComplete", mContextId);
//reset thread context in a place we know all tasks possibly accessing it, are in sync with. (see US6664)
mLLContext->resetThreadContexts();
mCCDContext->updateCCD(mDt, continuation, mSimpleIslandManager->getAccurateIslandSim(), (mPublicFlags & PxSceneFlag::eDISABLE_CCD_RESWEEP), mNumFastMovingShapes);
}
static PX_FORCE_INLINE Sc::ShapeInteraction* getSI(PxvContactManagerTouchEvent& evt)
{
return reinterpret_cast<Sc::ShapeInteraction*>(evt.getCMTouchEventUserData());
}
void Sc::Scene::postCCDPass(PxBaseTask* /*continuation*/)
{
// - Performs sleep check
// - Updates touch flags
PxU32 currentPass = mCCDContext->getCurrentCCDPass();
PX_ASSERT(currentPass > 0); // to make sure changes to the CCD pass counting get noticed. For contact reports, 0 means discrete collision phase.
PxU32 newTouchCount, lostTouchCount, ccdTouchCount;
mLLContext->getManagerTouchEventCount(&newTouchCount, &lostTouchCount, &ccdTouchCount);
PX_ALLOCA(newTouches, PxvContactManagerTouchEvent, newTouchCount);
PX_ALLOCA(lostTouches, PxvContactManagerTouchEvent, lostTouchCount);
PX_ALLOCA(ccdTouches, PxvContactManagerTouchEvent, ccdTouchCount);
PxsContactManagerOutputIterator outputs = mLLContext->getNphaseImplementationContext()->getContactManagerOutputs();
// Note: For contact notifications it is important that the new touch pairs get processed before the lost touch pairs.
// This allows to know for sure if a pair of actors lost all touch (see eACTOR_PAIR_LOST_TOUCH).
mLLContext->fillManagerTouchEvents(newTouches, newTouchCount, lostTouches, lostTouchCount, ccdTouches, ccdTouchCount);
for(PxU32 i=0; i<newTouchCount; ++i)
{
ShapeInteraction* si = getSI(newTouches[i]);
PX_ASSERT(si);
mNPhaseCore->managerNewTouch(*si);
si->managerNewTouch(currentPass, outputs);
if (!si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED))
{
mSimpleIslandManager->setEdgeConnected(si->getEdgeIndex(), IG::Edge::eCONTACT_MANAGER);
}
}
for(PxU32 i=0; i<lostTouchCount; ++i)
{
ShapeInteraction* si = getSI(lostTouches[i]);
PX_ASSERT(si);
if (si->managerLostTouch(currentPass, outputs) && !si->readFlag(ShapeInteraction::CONTACTS_RESPONSE_DISABLED))
addToLostTouchList(si->getActor0(), si->getActor1());
mSimpleIslandManager->setEdgeDisconnected(si->getEdgeIndex());
}
for(PxU32 i=0; i<ccdTouchCount; ++i)
{
ShapeInteraction* si = getSI(ccdTouches[i]);
PX_ASSERT(si);
si->sendCCDRetouch(currentPass, outputs);
}
checkForceThresholdContactEvents(currentPass);
{
PxBitMapPinned& changedAABBMgrActorHandles = mAABBManager->getChangedAABBMgActorHandleMap();
for (PxU32 i = 0, s = mCcdBodies.size(); i < s; i++)
{
BodySim*const body = mCcdBodies[i];
if(i+8 < s)
PxPrefetch(mCcdBodies[i+8], 512);
PX_ASSERT(body->getBody2World().p.isFinite());
PX_ASSERT(body->getBody2World().q.isFinite());
body->updateCached(&changedAABBMgrActorHandles);
}
ArticulationCore* const* articList = mArticulations.getEntries();
for(PxU32 i=0;i<mArticulations.size();i++)
articList[i]->getSim()->updateCached(&changedAABBMgrActorHandles);
}
}

View File

@@ -0,0 +1,134 @@
// 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.
#include "ScScene.h"
#include "ScConstraintSim.h"
#include "ScConstraintCore.h"
#include "ScConstraintInteraction.h"
#include "common/PxProfileZone.h"
using namespace physx;
// PT: the breakable constraints are added to / removed from mActiveBreakableConstraints:
void Sc::Scene::addActiveBreakableConstraint(Sc::ConstraintSim* c, Sc::ConstraintInteraction* ci)
{
PX_ASSERT(ci && ci->readInteractionFlag(InteractionFlag::eIS_ACTIVE));
PX_UNUSED(ci);
PX_ASSERT(!mActiveBreakableConstraints.contains(c));
PX_ASSERT(!c->isBroken());
mActiveBreakableConstraints.insert(c);
c->setFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED);
}
void Sc::Scene::removeActiveBreakableConstraint(Sc::ConstraintSim* c)
{
const bool exists = mActiveBreakableConstraints.erase(c);
PX_ASSERT(exists);
PX_UNUSED(exists);
c->clearFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED);
}
// PT: then at runtime we parse mActiveBreakableConstraints, check for max force exceeded,
// and add broken constraints to mBrokenConstraints:
void Sc::Scene::checkConstraintBreakage()
{
PX_PROFILE_ZONE("Sim.checkConstraintBreakage", mContextId);
PxU32 count = mActiveBreakableConstraints.size();
if(!count)
return;
PxPinnedArray<Dy::ConstraintWriteback>& pool = mDynamicsContext->getConstraintWriteBackPool();
ConstraintSim* const* constraints = mActiveBreakableConstraints.getEntries();
while(count--)
{
ConstraintSim* sim = constraints[count]; // start from the back because broken constraints get removed from the list
PX_ASSERT(sim->readFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED));
const Dy::ConstraintWriteback& solverOutput = pool[sim->getLowLevelConstraint().index];
if(solverOutput.isBroken())
{
sim->setFlag(ConstraintSim::eBROKEN);
ConstraintCore& core = sim->getCore();
if(mSimulationEventCallback)
{
PX_ASSERT(mBrokenConstraints.find(&core) == mBrokenConstraints.end());
mBrokenConstraints.pushBack(&core);
}
core.breakApart();
ConstraintInteraction* interaction = const_cast<ConstraintInteraction*>(sim->getInteraction());
interaction->destroy(); // PT: this will call removeFromActiveBreakableList above
// update related SIPs
{
ActorSim& a0 = interaction->getActorSim0();
ActorSim& a1 = interaction->getActorSim1();
ActorSim& actor = (a0.getActorInteractionCount() < a1.getActorInteractionCount()) ? a0 : a1;
actor.setActorsInteractionsDirty(InteractionDirtyFlag::eFILTER_STATE, NULL, InteractionFlag::eRB_ELEMENT);
// because broken constraints can re-enable contact response between the two bodies
}
PX_ASSERT(!sim->readFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED));
}
}
}
// PT: finally mBrokenConstraints is parsed and callbacks issued:
void Sc::Scene::fireBrokenConstraintCallbacks()
{
if(!mSimulationEventCallback)
return;
const PxU32 count = mBrokenConstraints.size();
for(PxU32 i=0;i<count;i++)
{
Sc::ConstraintCore* c = mBrokenConstraints[i];
PX_ASSERT(c->getSim());
PxU32 typeID = 0xffffffff;
void* externalRef = c->getPxConnector()->getExternalReference(typeID);
PX_CHECK_MSG(typeID != 0xffffffff, "onConstraintBreak: Invalid constraint type ID.");
PxConstraintInfo constraintInfo(c->getPxConstraint(), externalRef, typeID);
{
// PT: TODO: batch data and call this only once
PX_PROFILE_ZONE("USERCODE - PxSimulationEventCallback::onConstraintBreak", mContextId);
mSimulationEventCallback->onConstraintBreak(&constraintInfo, 1);
}
}
}

View File

@@ -0,0 +1,115 @@
// 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.
#include "ScConstraintCore.h"
#include "ScPhysics.h"
#include "ScConstraintSim.h"
using namespace physx;
Sc::ConstraintCore::ConstraintCore(PxConstraintConnector& connector, const PxConstraintShaderTable& shaders, PxU32 dataSize) :
mFlags (PxConstraintFlag::eDRIVE_LIMITS_ARE_FORCES),
mIsDirty (1),
mAppliedForce (PxVec3(0.0f)),
mAppliedTorque (PxVec3(0.0f)),
mConnector (&connector),
mSolverPrep (shaders.solverPrep),
mVisualize (shaders.visualize),
mDataSize (dataSize),
mLinearBreakForce (PX_MAX_F32),
mAngularBreakForce (PX_MAX_F32),
mMinResponseThreshold (0.0f),
mSim (NULL),
mResidual ()
{
}
void Sc::ConstraintCore::setFlags(PxConstraintFlags flags)
{
PxConstraintFlags old = mFlags;
flags = flags | (old & PxConstraintFlag::eGPU_COMPATIBLE); // eGPU_COMPATIBLE is for internal use only and should keep its initial state
if(flags != old)
{
mFlags = flags;
if(mSim)
mSim->postFlagChange(old, flags);
}
}
void Sc::ConstraintCore::getForce(PxVec3& force, PxVec3& torque) const
{
if(!mSim)
{
force = PxVec3(0.0f);
torque = PxVec3(0.0f);
}
else
mSim->getForce(force, torque);
}
void Sc::ConstraintCore::setBodies(RigidCore* r0v, RigidCore* r1v)
{
if(mSim)
mSim->setBodies(r0v, r1v);
}
void Sc::ConstraintCore::setBreakForce(PxReal linear, PxReal angular)
{
mLinearBreakForce = linear;
mAngularBreakForce = angular;
if(mSim)
mSim->setBreakForceLL(linear, angular);
}
void Sc::ConstraintCore::setMinResponseThreshold(PxReal threshold)
{
mMinResponseThreshold = threshold;
if(mSim)
mSim->setMinResponseThresholdLL(threshold);
}
PxConstraint* Sc::ConstraintCore::getPxConstraint()
{
return gOffsetTable.convertScConstraint2Px(this);
}
const PxConstraint* Sc::ConstraintCore::getPxConstraint() const
{
return gOffsetTable.convertScConstraint2Px(this);
}
void Sc::ConstraintCore::breakApart()
{
// TODO: probably want to do something with the interaction here
// as well as remove the constraint from LL.
mFlags |= PxConstraintFlag::eBROKEN;
}

View File

@@ -0,0 +1,171 @@
// 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.
#include "ScConstraintInteraction.h"
#include "ScConstraintSim.h"
#include "ScBodySim.h"
#include "ScScene.h"
#include "PxsRigidBody.h"
#include "PxsSimpleIslandManager.h"
using namespace physx;
using namespace Sc;
ConstraintInteraction::ConstraintInteraction(ConstraintSim* constraint, RigidSim& r0, RigidSim& r1) :
Interaction (r0, r1, InteractionType::eCONSTRAINTSHADER, InteractionFlag::eCONSTRAINT),
mConstraint (constraint)
{
{
onActivate();
registerInActors();
}
BodySim* b0 = mConstraint->getBody(0);
BodySim* b1 = mConstraint->getBody(1);
if(b0)
b0->onConstraintAttach();
if(b1)
b1->onConstraintAttach();
IG::SimpleIslandManager* simpleIslandManager = getScene().getSimpleIslandManager();
mEdgeIndex = simpleIslandManager->addConstraint(&mConstraint->getLowLevelConstraint(), b0 ? b0->getNodeIndex() : PxNodeIndex(), b1 ? b1->getNodeIndex() : PxNodeIndex(), this);
}
ConstraintInteraction::~ConstraintInteraction()
{
PX_ASSERT(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST));
PX_ASSERT(!getDirtyFlags());
PX_ASSERT(!mConstraint->readFlag(ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED));
}
static PX_FORCE_INLINE void removeFromActiveBreakableList(ConstraintSim* constraint, Scene& s)
{
if(constraint->readFlag(ConstraintSim::eBREAKABLE | ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED) == (ConstraintSim::eBREAKABLE | ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED))
s.removeActiveBreakableConstraint(constraint);
}
void ConstraintInteraction::destroy()
{
setClean(true); // removes the pair from the dirty interaction list etc.
Scene& scene = getScene();
removeFromActiveBreakableList(mConstraint, scene);
if(mEdgeIndex != IG_INVALID_EDGE)
scene.getSimpleIslandManager()->removeConnection(mEdgeIndex);
mEdgeIndex = IG_INVALID_EDGE;
unregisterFromActors();
BodySim* b0 = mConstraint->getBody(0);
BodySim* b1 = mConstraint->getBody(1);
if(b0)
b0->onConstraintDetach(); // Note: Has to be done AFTER the interaction has unregistered from the actors
if(b1)
b1->onConstraintDetach(); // Note: Has to be done AFTER the interaction has unregistered from the actors
clearInteractionFlag(InteractionFlag::eIS_ACTIVE); // ensures that broken constraints do not go into the list of active breakable constraints anymore
}
void ConstraintInteraction::updateState()
{
PX_ASSERT(!mConstraint->isBroken());
PX_ASSERT(getDirtyFlags() & InteractionDirtyFlag::eBODY_KINEMATIC); // at the moment this should be the only reason for this method being called
// at least one of the bodies got switched from kinematic to dynamic. This will not have changed the sleep state of the interactions, so the
// constraint interactions are just marked dirty and processed as part of the dirty interaction update system.
//
// -> need to check whether to activate the constraint and whether constraint break testing
// is now necessary
//
// the transition from dynamic to kinematic will always trigger an onDeactivate() (because the body gets deactivated)
// and thus there is no need to consider that case here.
//
onActivate(); // note: this will not activate if the necessary conditions are not met, so it can be called even if the pair has been deactivated again before the
// simulation step started
}
bool ConstraintInteraction::onActivate()
{
PX_ASSERT(!mConstraint->isBroken());
BodySim* b0 = mConstraint->getBody(0);
BodySim* b1 = mConstraint->getBody(1);
const bool b0Vote = !b0 || b0->isActive();
const bool b1Vote = !b1 || b1->isActive();
const bool b0Dynamic = b0 && (!b0->isKinematic());
const bool b1Dynamic = b1 && (!b1->isKinematic());
//
// note: constraints between kinematics and kinematics/statics are always inactive and must not be activated
//
if((b0Vote || b1Vote) && (b0Dynamic || b1Dynamic))
{
raiseInteractionFlag(InteractionFlag::eIS_ACTIVE);
if(mConstraint->readFlag(ConstraintSim::eBREAKABLE | ConstraintSim::eCHECK_MAX_FORCE_EXCEEDED) == ConstraintSim::eBREAKABLE)
getScene().addActiveBreakableConstraint(mConstraint, this);
return true;
}
else
return false;
}
bool ConstraintInteraction::onDeactivate()
{
const BodySim* b0 = mConstraint->getBody(0);
const BodySim* b1 = mConstraint->getBody(1);
const bool b0Dynamic = b0 && (!b0->isKinematic());
const bool b1Dynamic = b1 && (!b1->isKinematic());
PX_ASSERT( (!b0 && b1 && !b1->isActive()) ||
(!b1 && b0 && !b0->isActive()) ||
((b0 && b1 && (!b0->isActive() || !b1->isActive()))) );
//
// note: constraints between kinematics and kinematics/statics should always get deactivated
//
if(((!b0 || !b0->isActive()) && (!b1 || !b1->isActive())) || (!b0Dynamic && !b1Dynamic))
{
removeFromActiveBreakableList(mConstraint, getScene());
clearInteractionFlag(InteractionFlag::eIS_ACTIVE);
return true;
}
else
return false;
}

View File

@@ -0,0 +1,65 @@
// 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_CONSTRAINT_INTERACTION_H
#define SC_CONSTRAINT_INTERACTION_H
#include "ScInteraction.h"
namespace physx
{
namespace Sc
{
class ConstraintSim;
class RigidSim;
class ConstraintInteraction : public Interaction
{
public:
ConstraintInteraction(ConstraintSim* shader, RigidSim& r0, RigidSim& r1);
~ConstraintInteraction();
bool onActivate();
bool onDeactivate();
void updateState();
void destroy(); // disables the interaction and unregisters from the system. Does NOT delete the object. This is used on destruction but also when a constraint breaks.
PX_FORCE_INLINE ConstraintSim* getConstraint() { return mConstraint; }
PX_FORCE_INLINE IG::EdgeIndex getEdgeIndex() const { return mEdgeIndex; }
private:
ConstraintSim* mConstraint;
IG::EdgeIndex mEdgeIndex;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,226 @@
// 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.
#include "ScBodySim.h"
#include "ScStaticSim.h"
#include "ScConstraintCore.h"
#include "ScConstraintSim.h"
#include "ScConstraintInteraction.h"
#include "ScElementSimInteraction.h"
using namespace physx;
using namespace Sc;
static ConstraintInteraction* createInteraction(ConstraintSim* sim, RigidCore* r0, RigidCore* r1, Scene& scene)
{
return scene.getConstraintInteractionPool().construct( sim,
r0 ? *r0->getSim() : scene.getStaticAnchor(),
r1 ? *r1->getSim() : scene.getStaticAnchor());
}
static void releaseInteraction(ConstraintInteraction* interaction, const ConstraintSim* sim, Scene& scene)
{
if(!sim->isBroken())
interaction->destroy();
scene.getConstraintInteractionPool().destroy(interaction);
}
Sc::ConstraintSim::ConstraintSim(ConstraintCore& core, RigidCore* r0, RigidCore* r1, Scene& scene) :
mScene (scene),
mCore (core),
mInteraction(NULL),
mFlags (0)
{
mBodies[0] = (r0 && (r0->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r0->getSim()) : 0;
mBodies[1] = (r1 && (r1->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r1->getSim()) : 0;
const PxU32 id = scene.getConstraintIDTracker().createID();
mLowLevelConstraint.index = id;
PxPinnedArray<Dy::ConstraintWriteback>& writeBackPool = scene.getDynamicsContext()->getConstraintWriteBackPool();
if(id >= writeBackPool.capacity())
writeBackPool.reserve(writeBackPool.capacity() * 2);
writeBackPool.resize(PxMax(writeBackPool.size(), id + 1));
writeBackPool[id].initialize();
if(!createLLConstraint())
return;
PxReal linBreakForce, angBreakForce;
core.getBreakForce(linBreakForce, angBreakForce);
if ((linBreakForce < PX_MAX_F32) || (angBreakForce < PX_MAX_F32))
setFlag(eBREAKABLE);
core.setSim(this);
mInteraction = createInteraction(this, r0, r1, scene);
PX_ASSERT(!mInteraction->isRegistered()); // constraint interactions must not register in the scene, there is a list of Sc::ConstraintSim instead
}
Sc::ConstraintSim::~ConstraintSim()
{
PX_ASSERT(mInteraction); // This is fine now, a body which gets removed from the scene removes all constraints automatically
PX_ASSERT(!mInteraction->isRegistered()); // constraint interactions must not register in the scene, there is a list of Sc::ConstraintSim instead
releaseInteraction(mInteraction, this, mScene);
mScene.getConstraintIDTracker().releaseID(mLowLevelConstraint.index);
destroyLLConstraint();
mCore.setSim(NULL);
}
static PX_FORCE_INLINE void setLLBodies(Dy::Constraint& c, BodySim* b0, BodySim* b1)
{
PxsRigidBody* body0 = b0 ? &b0->getLowLevelBody() : NULL;
PxsRigidBody* body1 = b1 ? &b1->getLowLevelBody() : NULL;
c.body0 = body0;
c.body1 = body1;
c.bodyCore0 = body0 ? &body0->getCore() : NULL;
c.bodyCore1 = body1 ? &body1->getCore() : NULL;
}
bool Sc::ConstraintSim::createLLConstraint()
{
ConstraintCore& core = getCore();
const PxU32 constantBlockSize = core.getConstantBlockSize();
void* constantBlock = mScene.allocateConstraintBlock(constantBlockSize);
if(!constantBlock)
return PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Constraint: could not allocate low-level resources.");
//Ensure the constant block isn't just random data because some functions may attempt to use it before it is
//setup. Specifically pvd visualization of joints
//-CN
PxMemZero(constantBlock, constantBlockSize);
Dy::Constraint& llc = mLowLevelConstraint;
core.getBreakForce(llc.linBreakForce, llc.angBreakForce);
llc.flags = core.getFlags();
llc.constantBlockSize = PxU16(constantBlockSize);
llc.solverPrep = core.getSolverPrep();
llc.constantBlock = constantBlock;
llc.minResponseThreshold = core.getMinResponseThreshold();
//llc.index = mLowLevelConstraint.index;
setLLBodies(llc, mBodies[0], mBodies[1]);
return true;
}
void Sc::ConstraintSim::destroyLLConstraint()
{
if(mLowLevelConstraint.constantBlock)
mScene.deallocateConstraintBlock(mLowLevelConstraint.constantBlock, mLowLevelConstraint.constantBlockSize);
}
void Sc::ConstraintSim::setBodies(RigidCore* r0, RigidCore* r1)
{
PX_ASSERT(mInteraction);
mScene.removeConstraintFromMap(*mInteraction);
releaseInteraction(mInteraction, this, mScene);
BodySim* b0 = (r0 && (r0->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r0->getSim()) : 0;
BodySim* b1 = (r1 && (r1->getActorCoreType() != PxActorType::eRIGID_STATIC)) ? static_cast<BodySim*>(r1->getSim()) : 0;
setLLBodies(mLowLevelConstraint, b0, b1);
mBodies[0] = b0;
mBodies[1] = b1;
mInteraction = createInteraction(this, r0, r1, mScene);
mScene.addConstraintToMap(mCore, r0, r1);
}
void Sc::ConstraintSim::getForce(PxVec3& lin, PxVec3& ang)
{
const PxReal recipDt = mScene.getOneOverDt();
Dy::ConstraintWriteback& solverOutput = mScene.getDynamicsContext()->getConstraintWriteBackPool()[mLowLevelConstraint.index];
lin = solverOutput.linearImpulse * recipDt;
ang = solverOutput.angularImpulse * recipDt;
}
void Sc::ConstraintSim::setBreakForceLL(PxReal linear, PxReal angular)
{
PxU8 wasBreakable = readFlag(eBREAKABLE);
PxU8 isBreakable;
if ((linear < PX_MAX_F32) || (angular < PX_MAX_F32))
isBreakable = eBREAKABLE;
else
isBreakable = 0;
if (isBreakable != wasBreakable)
{
if (isBreakable)
{
PX_ASSERT(!readFlag(eCHECK_MAX_FORCE_EXCEEDED));
setFlag(eBREAKABLE);
if (mInteraction->readInteractionFlag(InteractionFlag::eIS_ACTIVE))
mScene.addActiveBreakableConstraint(this, mInteraction);
}
else
{
if (readFlag(eCHECK_MAX_FORCE_EXCEEDED))
mScene.removeActiveBreakableConstraint(this);
clearFlag(eBREAKABLE);
}
}
mLowLevelConstraint.linBreakForce = linear;
mLowLevelConstraint.angBreakForce = angular;
}
void Sc::ConstraintSim::postFlagChange(PxConstraintFlags /*oldFlags*/, PxConstraintFlags newFlags)
{
mLowLevelConstraint.flags = newFlags;
}
PxConstraintGPUIndex Sc::ConstraintSim::getGPUIndex() const
{
//
// The constraint ID is used as GPU index
//
if (mLowLevelConstraint.flags & PxConstraintFlag::eGPU_COMPATIBLE)
{
PX_COMPILE_TIME_ASSERT(sizeof(Dy::Constraint::index) <= sizeof(PxConstraintGPUIndex));
return static_cast<PxConstraintGPUIndex>(mLowLevelConstraint.index);
}
else
return PX_INVALID_CONSTRAINT_GPU_INDEX;
}

View File

@@ -0,0 +1,102 @@
// 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_CONSTRAINT_SIM_H
#define SC_CONSTRAINT_SIM_H
#include "foundation/PxArray.h"
#include "PxSimulationEventCallback.h"
#include "DyConstraint.h"
namespace physx
{
namespace Sc
{
class Scene;
class ConstraintInteraction;
class ConstraintCore;
class RigidCore;
class BodySim;
class RigidSim;
class ConstraintSim
{
PX_NOCOPY(ConstraintSim)
public:
enum Enum
{
eBREAKABLE = (1<<1), // The constraint can break
eCHECK_MAX_FORCE_EXCEEDED = (1<<2), // This constraint will get tested for breakage at the end of the sim step
eBROKEN = (1<<3)
};
ConstraintSim(ConstraintCore& core, RigidCore* r0, RigidCore* r1, Scene& scene);
~ConstraintSim();
void setBodies(RigidCore* r0, RigidCore* r1);
void setBreakForceLL(PxReal linear, PxReal angular);
PX_FORCE_INLINE void setMinResponseThresholdLL(PxReal threshold) { mLowLevelConstraint.minResponseThreshold = threshold; }
PX_FORCE_INLINE const void* getConstantsLL() const { return mLowLevelConstraint.constantBlock; }
void postFlagChange(PxConstraintFlags oldFlags, PxConstraintFlags newFlags);
PX_FORCE_INLINE const Dy::Constraint& getLowLevelConstraint() const { return mLowLevelConstraint; }
PX_FORCE_INLINE Dy::Constraint& getLowLevelConstraint() { return mLowLevelConstraint; }
PX_FORCE_INLINE ConstraintCore& getCore() const { return mCore; }
PX_FORCE_INLINE BodySim* getBody(PxU32 i) const // for static actors or world attached constraints NULL is returned
{
return mBodies[i];
}
void getForce(PxVec3& force, PxVec3& torque);
PX_FORCE_INLINE PxU8 readFlag(PxU8 flag) const { return PxU8(mFlags & flag); }
PX_FORCE_INLINE void setFlag(PxU8 flag) { mFlags |= flag; }
PX_FORCE_INLINE void clearFlag(PxU8 flag) { mFlags &= ~flag; }
PX_FORCE_INLINE PxU32 isBroken() const { return PxU32(mFlags) & ConstraintSim::eBROKEN; }
PX_FORCE_INLINE const ConstraintInteraction* getInteraction() const { return mInteraction; }
PxConstraintGPUIndex getGPUIndex() const;
private:
bool createLLConstraint();
void destroyLLConstraint();
Dy::Constraint mLowLevelConstraint;
Scene& mScene;
ConstraintCore& mCore;
ConstraintInteraction* mInteraction; // PT: why do we have an interaction object here?
BodySim* mBodies[2];
PxU8 mFlags;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,172 @@
// 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_CONTACT_REPORT_BUFFER_H
#define SC_CONTACT_REPORT_BUFFER_H
#include "common/PxProfileZone.h"
namespace physx
{
namespace Sc
{
class ContactReportBuffer
{
public:
PX_FORCE_INLINE ContactReportBuffer(PxU32 initialSize, bool noResizeAllowed)
: mBuffer(NULL)
,mCurrentBufferIndex(0)
,mCurrentBufferSize(initialSize)
,mDefaultBufferSize(initialSize)
,mLastBufferIndex(0)
,mAllocationLocked(noResizeAllowed)
{
mBuffer = allocateBuffer(initialSize);
PX_ASSERT(mBuffer);
}
~ContactReportBuffer()
{
PX_FREE(mBuffer);
}
PX_FORCE_INLINE void reset();
PX_FORCE_INLINE void flush();
PX_FORCE_INLINE PxU8* allocateNotThreadSafe(PxU32 size, PxU32& index, PxU32 alignment = 16);
PX_FORCE_INLINE PxU8* reallocateNotThreadSafe(PxU32 size, PxU32& index, PxU32 alignment = 16, PxU32 lastIndex = 0xFFFFFFFF);
PX_FORCE_INLINE PxU8* getData(const PxU32& index) const { return mBuffer+index; }
PX_FORCE_INLINE PxU32 getDefaultBufferSize() const {return mDefaultBufferSize;}
private:
PX_FORCE_INLINE PxU8* allocateBuffer(PxU32 size);
private:
PxU8* mBuffer;
PxU32 mCurrentBufferIndex;
PxU32 mCurrentBufferSize;
PxU32 mDefaultBufferSize;
PxU32 mLastBufferIndex;
bool mAllocationLocked;
};
} // namespace Sc
//////////////////////////////////////////////////////////////////////////
PX_FORCE_INLINE void Sc::ContactReportBuffer::reset()
{
mCurrentBufferIndex = 0;
mLastBufferIndex = 0xFFFFFFFF;
}
//////////////////////////////////////////////////////////////////////////
void Sc::ContactReportBuffer::flush()
{
mCurrentBufferIndex = 0;
mLastBufferIndex = 0xFFFFFFFF;
if(mCurrentBufferSize != mDefaultBufferSize)
{
PX_FREE(mBuffer);
mBuffer = allocateBuffer(mDefaultBufferSize);
PX_ASSERT(mBuffer);
mCurrentBufferSize = mDefaultBufferSize;
}
}
//////////////////////////////////////////////////////////////////////////
PxU8* Sc::ContactReportBuffer::allocateNotThreadSafe(PxU32 size, PxU32& index ,PxU32 alignment/* =16 */)
{
PX_ASSERT(PxIsPowerOfTwo(alignment));
// padding for alignment
PxU32 pad = ((mCurrentBufferIndex+alignment-1)&~(alignment-1)) - mCurrentBufferIndex;
index = mCurrentBufferIndex + pad;
if (index + size > mCurrentBufferSize)
{
PX_PROFILE_ZONE("ContactReportBuffer::Resize", 0);
if(mAllocationLocked)
return NULL;
PxU32 oldBufferSize = mCurrentBufferSize;
while(index + size > mCurrentBufferSize)
{
mCurrentBufferSize *= 2;
}
PxU8* tempBuffer = allocateBuffer(mCurrentBufferSize);
PxMemCopy(tempBuffer,mBuffer,oldBufferSize);
PX_FREE(mBuffer);
mBuffer = tempBuffer;
}
PxU8* ptr = mBuffer + index;
mLastBufferIndex = index;
PX_ASSERT((size_t(ptr)&(alignment-1)) == 0);
mCurrentBufferIndex += size + pad;
return ptr;
}
//////////////////////////////////////////////////////////////////////////
PxU8* Sc::ContactReportBuffer::reallocateNotThreadSafe(PxU32 size, PxU32& index ,PxU32 alignment/* =16 */, PxU32 lastIndex)
{
if(lastIndex != mLastBufferIndex)
{
return allocateNotThreadSafe(size,index,alignment);
}
else
{
mCurrentBufferIndex = mLastBufferIndex;
return allocateNotThreadSafe(size,index,alignment);
}
}
//////////////////////////////////////////////////////////////////////////
PX_FORCE_INLINE PxU8* Sc::ContactReportBuffer::allocateBuffer(PxU32 size)
{
return (static_cast<PxU8*>(PX_ALLOC(size, "ContactReportBuffer")));
}
} // namespace physx
#endif

View File

@@ -0,0 +1,401 @@
// 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_CONTACT_STREAM_H
#define SC_CONTACT_STREAM_H
#include "PxSimulationEventCallback.h"
#include "ScObjectIDTracker.h"
#include "ScRigidSim.h"
#include "ScStaticSim.h"
#include "ScBodySim.h"
namespace physx
{
class PxShape;
namespace Sc
{
class ActorPair;
// Internal counterpart of PxContactPair
struct ContactShapePair
{
public:
PxShape* shapes[2];
const PxU8* contactPatches;
const PxU8* contactPoints;
const PxReal* contactForces;
const PxU8* frictionPatches;
PxU32 requiredBufferSize;
PxU8 contactCount;
PxU8 patchCount;
PxU16 constraintStreamSize;
PxU16 flags;
PxU16 events;
PxU32 shapeID[2];
//38 on 64bit
};
PX_COMPILE_TIME_ASSERT(sizeof(ContactShapePair) == sizeof(PxContactPair));
struct ContactStreamManagerFlag
{
enum Enum
{
/**
\brief Need to test stream for shapes that were removed from the actor/scene
Usually this is the case when a shape gets removed from the scene, however, other operations that remove the
broadphase volume of a pair object have to be considered as well since the shape might get removed later after such an
operation. The scenarios to consider are:
\li shape gets removed (this includes raising PxActorFlag::eDISABLE_SIMULATION)
\li shape switches to eSCENE_QUERY_SHAPE only
\li shape switches to eTRIGGER_SHAPE
\li resetFiltering()
\li actor gets removed from an aggregate
*/
eTEST_FOR_REMOVED_SHAPES = (1<<0),
/**
\brief Invalid stream memory not allocated
*/
eINVALID_STREAM = (1<<1),
/**
\brief Incomplete stream will be reported
*/
eINCOMPLETE_STREAM = (1<<2),
/**
\brief The stream contains extra data with PxContactPairVelocity items where the post solver velocity needs to get written to.
Only valid for discrete collision (in CCD the post response velocity is available immediately).
*/
eNEEDS_POST_SOLVER_VELOCITY = (1<<3),
/**
\brief Marker for the next available free flag
*/
eNEXT_FREE_FLAG = (1<<4)
};
};
struct ContactStreamHeader
{
PxU16 contactPass; // marker for extra data to know when a new collison pass started (discrete collision -> CCD pass 1 -> CCD pass 2 -> ...)
PxU16 pad; // to keep the stream 4byte aligned
};
/**
\brief Contact report logic and data management.
The internal contact report stream has the following format:
ContactStreamHeader | PxContactPairIndex0 | (PxContactPairPose0, PxContactPairVelocity0) | ... | PxContactPairIndexN | (PxContactPairPoseN, PxContactPairVelocityN) | (unused memory up to maxExtraDataSize ) |
PxContactPair0 | ... | PxContactPairM | (unsued pairs up to maxPairCount)
*/
class ContactStreamManager
{
public:
PX_FORCE_INLINE ContactStreamManager() : maxPairCount(0), flags_and_maxExtraDataBlocks(0) {}
PX_FORCE_INLINE ~ContactStreamManager() {}
PX_FORCE_INLINE void reset();
PX_FORCE_INLINE PxU16 getFlags() const;
PX_FORCE_INLINE void raiseFlags(PxU16 flags);
PX_FORCE_INLINE void clearFlags(PxU16 flags);
PX_FORCE_INLINE PxU32 getMaxExtraDataSize() const;
PX_FORCE_INLINE void setMaxExtraDataSize(PxU32 size); // size in bytes (will translate into blocks internally)
PX_FORCE_INLINE Sc::ContactShapePair* getShapePairs(PxU8* contactReportPairData) const;
PX_FORCE_INLINE static void convertDeletedShapesInContactStream(ContactShapePair*, PxU32 pairCount, const ObjectIDTracker&);
PX_FORCE_INLINE static PxU32 computeExtraDataBlockCount(PxU32 extraDataSize);
PX_FORCE_INLINE static PxU32 computeExtraDataBlockSize(PxU32 extraDataSize);
PX_FORCE_INLINE static PxU16 computeContactReportExtraDataSize(PxU32 extraDataFlags, bool addHeader);
PX_FORCE_INLINE static void fillInContactReportExtraData(PxContactPairVelocity*, PxU32 index, const ActorSim&, bool isCCDPass);
PX_FORCE_INLINE static void fillInContactReportExtraData(PxContactPairPose*, PxU32 index, const ActorSim&, bool isCCDPass, const bool useCurrentTransform);
PX_FORCE_INLINE void fillInContactReportExtraData(PxU8* stream, PxU32 extraDataFlags, const ActorSim&, const ActorSim&, PxU32 ccdPass, const bool useCurrentTransform, PxU32 pairIndex, PxU32 sizeOffset);
PX_FORCE_INLINE void setContactReportPostSolverVelocity(PxU8* stream, const ActorSim&, const ActorSim&);
PxU32 bufferIndex; // marks the start of the shape pair stream of the actor pair (byte offset with respect to global contact buffer stream)
PxU32 maxPairCount; // used to reserve the same amount of memory as in the last frame (as an initial guess)
PxU32 currentPairCount; // number of shape pairs stored in the buffer
PxU16 extraDataSize; // size of the extra data section in the stream
private:
PxU16 flags_and_maxExtraDataBlocks; // used to reserve the same amount of memory as in the last frame (as an initial guess)
public:
static const PxU32 sExtraDataBlockSizePow2 = 4; // extra data gets allocated as a multiple of 2^sExtraDataBlockSizePow2 to keep memory low of this struct.
static const PxU32 sFlagMask = (ContactStreamManagerFlag::eNEXT_FREE_FLAG - 1);
static const PxU32 sMaxExtraDataShift = 4; // shift necessary to extract the maximum number of blocks allocated for extra data
PX_COMPILE_TIME_ASSERT(ContactStreamManagerFlag::eNEXT_FREE_FLAG == (1 << sMaxExtraDataShift));
};
} // namespace Sc
PX_FORCE_INLINE void Sc::ContactStreamManager::reset()
{
currentPairCount = 0;
extraDataSize = 0;
flags_and_maxExtraDataBlocks &= ~sFlagMask;
}
PX_FORCE_INLINE PxU16 Sc::ContactStreamManager::getFlags() const
{
return (flags_and_maxExtraDataBlocks & sFlagMask);
}
PX_FORCE_INLINE void Sc::ContactStreamManager::raiseFlags(PxU16 flags)
{
PX_ASSERT(flags < ContactStreamManagerFlag::eNEXT_FREE_FLAG);
flags_and_maxExtraDataBlocks |= flags;
}
PX_FORCE_INLINE void Sc::ContactStreamManager::clearFlags(PxU16 flags)
{
PX_ASSERT(flags < ContactStreamManagerFlag::eNEXT_FREE_FLAG);
PxU16 tmpFlags = getFlags();
tmpFlags &= ~flags;
flags_and_maxExtraDataBlocks &= ~sFlagMask;
raiseFlags(tmpFlags);
}
PX_FORCE_INLINE PxU32 Sc::ContactStreamManager::getMaxExtraDataSize() const
{
return PxU32((flags_and_maxExtraDataBlocks >> sMaxExtraDataShift) << sExtraDataBlockSizePow2);
}
PX_FORCE_INLINE void Sc::ContactStreamManager::setMaxExtraDataSize(PxU32 size)
{
const PxU32 nbBlocks = computeExtraDataBlockCount(size);
flags_and_maxExtraDataBlocks = PxTo16((flags_and_maxExtraDataBlocks & sFlagMask) | (nbBlocks << sMaxExtraDataShift));
}
PX_FORCE_INLINE Sc::ContactShapePair* Sc::ContactStreamManager::getShapePairs(PxU8* contactReportPairData) const
{
return reinterpret_cast<Sc::ContactShapePair*>(contactReportPairData + getMaxExtraDataSize());
}
PX_FORCE_INLINE void Sc::ContactStreamManager::convertDeletedShapesInContactStream(ContactShapePair* shapePairs, PxU32 pairCount, const ObjectIDTracker& tracker)
{
for(PxU32 i=0; i < pairCount; i++)
{
ContactShapePair& csp = shapePairs[i];
PxU32 shape0ID = csp.shapeID[0];
PxU32 shape1ID = csp.shapeID[1];
PxU16 flags = csp.flags;
PX_COMPILE_TIME_ASSERT(sizeof(flags) == sizeof((reinterpret_cast<ContactShapePair*>(0))->flags));
if (tracker.isDeletedID(shape0ID))
flags |= PxContactPairFlag::eREMOVED_SHAPE_0;
if (tracker.isDeletedID(shape1ID))
flags |= PxContactPairFlag::eREMOVED_SHAPE_1;
csp.flags = flags;
}
}
PX_FORCE_INLINE PxU32 Sc::ContactStreamManager::computeExtraDataBlockCount(PxU32 extraDataSize_)
{
PxU32 nbBlocks;
if (extraDataSize_ & ((1 << sExtraDataBlockSizePow2) - 1)) // not a multiple of block size -> need one block more
nbBlocks = (extraDataSize_ >> sExtraDataBlockSizePow2) + 1;
else
nbBlocks = (extraDataSize_ >> sExtraDataBlockSizePow2);
return nbBlocks;
}
PX_FORCE_INLINE PxU32 Sc::ContactStreamManager::computeExtraDataBlockSize(PxU32 extraDataSize_)
{
return (computeExtraDataBlockCount(extraDataSize_) << sExtraDataBlockSizePow2);
}
PX_FORCE_INLINE PxU16 Sc::ContactStreamManager::computeContactReportExtraDataSize(PxU32 extraDataFlags, bool addHeader)
{
PX_ASSERT(extraDataFlags);
PxU16 extraDataSize_ = sizeof(PxContactPairIndex);
if (extraDataFlags & PxPairFlag::ePRE_SOLVER_VELOCITY)
extraDataSize_ += sizeof(PxContactPairVelocity);
if (extraDataFlags & PxPairFlag::ePOST_SOLVER_VELOCITY)
extraDataSize_ += sizeof(PxContactPairVelocity);
if (extraDataFlags & PxPairFlag::eCONTACT_EVENT_POSE)
extraDataSize_ += sizeof(PxContactPairPose);
if (addHeader)
extraDataSize_ += sizeof(ContactStreamHeader);
return extraDataSize_;
}
PX_FORCE_INLINE void Sc::ContactStreamManager::fillInContactReportExtraData(PxContactPairVelocity* cpVel, PxU32 index, const ActorSim& rs, bool isCCDPass)
{
if (rs.getActorType() != PxActorType::eRIGID_STATIC)
{
const BodySim& bs = static_cast<const BodySim&>(rs);
if ((!isCCDPass) || (cpVel->type == PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY))
{
const BodyCore& bc = bs.getBodyCore();
cpVel->linearVelocity[index] = bc.getLinearVelocity();
cpVel->angularVelocity[index] = bc.getAngularVelocity();
}
else
{
PX_ASSERT(cpVel->type == PxContactPairExtraDataType::ePRE_SOLVER_VELOCITY);
const Cm::SpatialVector& vel = bs.getLowLevelBody().getPreSolverVelocities();
cpVel->linearVelocity[index] = vel.linear;
cpVel->angularVelocity[index] = vel.angular;
}
}
else
{
cpVel->linearVelocity[index] = PxVec3(0.0f);
cpVel->angularVelocity[index] = PxVec3(0.0f);
}
}
PX_FORCE_INLINE void Sc::ContactStreamManager::fillInContactReportExtraData(PxContactPairPose* cpPose, PxU32 index, const ActorSim& rs, bool isCCDPass, const bool useCurrentTransform)
{
if(rs.getActorType() != PxActorType::eRIGID_STATIC)
{
const BodySim& bs = static_cast<const BodySim&>(rs);
const BodyCore& bc = bs.getBodyCore();
const PxTransform& src = (!isCCDPass && useCurrentTransform) ? bc.getBody2World() : bs.getLowLevelBody().getLastCCDTransform();
// PT:: tag: scalar transform*transform
cpPose->globalPose[index] = src * bc.getBody2Actor().getInverse();
}
else
{
const StaticSim& ss = static_cast<const StaticSim&>(rs);
const StaticCore& sc = ss.getStaticCore();
cpPose->globalPose[index] = sc.getActor2World();
}
}
PX_FORCE_INLINE void Sc::ContactStreamManager::fillInContactReportExtraData(PxU8* stream, PxU32 extraDataFlags, const ActorSim& rs0, const ActorSim& rs1, PxU32 ccdPass, const bool useCurrentTransform,
PxU32 pairIndex, PxU32 sizeOffset)
{
ContactStreamHeader* strHeader = reinterpret_cast<ContactStreamHeader*>(stream);
strHeader->contactPass = PxTo16(ccdPass);
stream += sizeOffset;
PxU8* edStream = stream;
bool isCCDPass = (ccdPass != 0);
{
PxContactPairIndex* cpIndex = reinterpret_cast<PxContactPairIndex*>(edStream);
cpIndex->type = PxContactPairExtraDataType::eCONTACT_PAIR_INDEX;
cpIndex->index = PxTo16(pairIndex);
edStream += sizeof(PxContactPairIndex);
PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream)));
}
// Important: make sure this one is the first after the PxContactPairIndex item for discrete contacts as it needs to get filled in before the reports get sent
// (post solver velocity is not available when it gets created)
if (extraDataFlags & PxPairFlag::ePOST_SOLVER_VELOCITY)
{
PxContactPairVelocity* cpVel = reinterpret_cast<PxContactPairVelocity*>(edStream);
cpVel->type = PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY;
edStream += sizeof(PxContactPairVelocity);
if (!isCCDPass)
raiseFlags(ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY); // don't know the post solver velocity yet
else
{
ContactStreamManager::fillInContactReportExtraData(cpVel, 0, rs0, true);
ContactStreamManager::fillInContactReportExtraData(cpVel, 1, rs1, true);
}
PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream)));
}
if (extraDataFlags & PxPairFlag::ePRE_SOLVER_VELOCITY)
{
PxContactPairVelocity* cpVel = reinterpret_cast<PxContactPairVelocity*>(edStream);
cpVel->type = PxContactPairExtraDataType::ePRE_SOLVER_VELOCITY;
ContactStreamManager::fillInContactReportExtraData(cpVel, 0, rs0, isCCDPass);
ContactStreamManager::fillInContactReportExtraData(cpVel, 1, rs1, isCCDPass);
edStream += sizeof(PxContactPairVelocity);
PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream)));
}
if (extraDataFlags & PxPairFlag::eCONTACT_EVENT_POSE)
{
PxContactPairPose* cpPose = reinterpret_cast<PxContactPairPose*>(edStream);
cpPose->type = PxContactPairExtraDataType::eCONTACT_EVENT_POSE;
ContactStreamManager::fillInContactReportExtraData(cpPose, 0, rs0, isCCDPass, useCurrentTransform);
ContactStreamManager::fillInContactReportExtraData(cpPose, 1, rs1, isCCDPass, useCurrentTransform);
edStream += sizeof(PxContactPairPose);
PX_ASSERT(edStream <= reinterpret_cast<PxU8*>(getShapePairs(stream)));
}
extraDataSize = PxTo16(sizeOffset + PxU32(edStream - stream));
}
PX_FORCE_INLINE void Sc::ContactStreamManager::setContactReportPostSolverVelocity(PxU8* stream, const ActorSim& rs0, const ActorSim& rs1)
{
PX_ASSERT(extraDataSize > (sizeof(ContactStreamHeader) + sizeof(PxContactPairIndex)));
PxContactPairVelocity* cpVel = reinterpret_cast<PxContactPairVelocity*>(stream + sizeof(ContactStreamHeader) + sizeof(PxContactPairIndex));
PX_ASSERT(cpVel->type == PxContactPairExtraDataType::ePOST_SOLVER_VELOCITY);
fillInContactReportExtraData(cpVel, 0, rs0, false);
fillInContactReportExtraData(cpVel, 1, rs1, false);
clearFlags(ContactStreamManagerFlag::eNEEDS_POST_SOLVER_VELOCITY);
}
}
#endif

View File

@@ -0,0 +1,323 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScDeformableSurfaceCore.h"
#include "ScPhysics.h"
#include "ScDeformableSurfaceSim.h"
#include "DyDeformableSurface.h"
#include "GuTetrahedronMesh.h"
#include "GuBV4.h"
#include "geometry/PxTetrahedronMesh.h"
#include "cudamanager/PxCudaContextManager.h"
using namespace physx;
Sc::DeformableSurfaceCore::DeformableSurfaceCore() :
ActorCore(PxActorType::eDEFORMABLE_SURFACE, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0),
mGpuMemStat(0)
{
const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale();
// Dy::DeformableCore
mCore.sleepThreshold = 5e-5f * scale.speed * scale.speed;
mCore.solverIterationCounts = (1 << 8) | 4;
mCore.wakeCounter = Physics::sWakeCounterOnCreation;
mCore.dirty = true;
}
Sc::DeformableSurfaceCore::~DeformableSurfaceCore() { }
/////////////////////////////////////////////////////////////////////////////////////////
// PxActor API
/////////////////////////////////////////////////////////////////////////////////////////
void Sc::DeformableSurfaceCore::setActorFlags(PxActorFlags flags)
{
mCore.actorFlags = flags;
mCore.dirty = true;
}
/////////////////////////////////////////////////////////////////////////////////////////
// PxDeformableBody API
/////////////////////////////////////////////////////////////////////////////////////////
void Sc::DeformableSurfaceCore::setBodyFlags(PxDeformableBodyFlags flags)
{
mCore.bodyFlags = flags;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setLinearDamping(const PxReal v)
{
mCore.linearDamping = v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setMaxLinearVelocity(const PxReal v)
{
mCore.maxLinearVelocity = (v > 1e15f) ? PX_MAX_REAL : v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setMaxPenetrationBias(const PxReal v)
{
mCore.maxPenetrationBias = v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setSolverIterationCounts(const PxU16 c)
{
mCore.solverIterationCounts = c;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setSleepThreshold(const PxReal v)
{
mCore.sleepThreshold = v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setSettlingThreshold(const PxReal v)
{
mCore.settlingThreshold = v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setSettlingDamping(const PxReal v)
{
mCore.settlingDamping = v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setSelfCollisionFilterDistance(const PxReal v)
{
mCore.selfCollisionFilterDistance = v;
mCore.dirty = true;
}
//deprecated
void Sc::DeformableSurfaceCore::setSelfCollisionStressTolerance(const PxReal v)
{
mCore.selfCollisionStressTolerance = v;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setWakeCounter(const PxReal v)
{
setWakeCounterInternal(v);
}
void Sc::DeformableSurfaceCore::setWakeCounterInternal(const PxReal v)
{
mCore.wakeCounter = v;
mCore.dirty = true;
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
{
sim->onSetWakeCounter();
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// PxDeformableSurface API
/////////////////////////////////////////////////////////////////////////////////////////
void Sc::DeformableSurfaceCore::setSurfaceFlags(PxDeformableSurfaceFlags flags)
{
mCore.surfaceFlags = flags;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setNbCollisionPairUpdatesPerTimestep(const PxU32 frequency)
{
mCore.nbCollisionPairUpdatesPerTimestep = frequency;
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::setNbCollisionSubsteps(const PxU32 frequency)
{
mCore.nbCollisionSubsteps = frequency;
mCore.dirty = true;
}
/////////////////////////////////////////////////////////////////////////////////////////
// Internal API
/////////////////////////////////////////////////////////////////////////////////////////
PxU32 Sc::DeformableSurfaceCore::addRigidAttachment(Sc::BodyCore* core, PxU32 particleId, const PxVec3& actorSpacePose, PxConeLimitedConstraint* params)
{
Sc::DeformableSurfaceSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
{
handle = sim->getScene().addRigidAttachment(core, *sim, particleId, actorSpacePose, params);
}
return handle;
}
void Sc::DeformableSurfaceCore::removeRigidAttachment(Sc::BodyCore* core, PxU32 handle)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
{
sim->getScene().removeRigidAttachment(core, *sim, handle);
setWakeCounterInternal(ScInternalWakeCounterResetValue);
}
}
void Sc::DeformableSurfaceCore::addTriRigidFilter(Sc::BodyCore* core, PxU32 triIdx)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
sim->getScene().addTriRigidFilter(core, *sim, triIdx);
}
void Sc::DeformableSurfaceCore::removeTriRigidFilter(Sc::BodyCore* core, PxU32 triIdx)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
sim->getScene().removeTriRigidFilter(core, *sim, triIdx);
}
PxU32 Sc::DeformableSurfaceCore::addTriRigidAttachment(Sc::BodyCore* core, PxU32 triIdx, const PxVec4& barycentric, const PxVec3& actorSpacePose, PxConeLimitedConstraint* constraint)
{
Sc::DeformableSurfaceSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
handle = sim->getScene().addTriRigidAttachment(core, *sim, triIdx, barycentric, actorSpacePose, constraint);
return handle;
}
void Sc::DeformableSurfaceCore::removeTriRigidAttachment(Sc::BodyCore* core, PxU32 handle)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
{
sim->getScene().removeTriRigidAttachment(core, *sim, handle);
setWakeCounterInternal(ScInternalWakeCounterResetValue);
}
}
void Sc::DeformableSurfaceCore::addClothFilter(Sc::DeformableSurfaceCore* otherCore, PxU32 otherTriIdx, PxU32 triIdx)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
sim->getScene().addClothFilter(*otherCore, otherTriIdx, *sim, triIdx);
}
void Sc::DeformableSurfaceCore::removeClothFilter(Sc::DeformableSurfaceCore* otherCore, PxU32 otherTriIdx, PxU32 triIdx)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
sim->getScene().removeClothFilter(*otherCore, otherTriIdx, *sim, triIdx);
}
PxU32 Sc::DeformableSurfaceCore::addClothAttachment(Sc::DeformableSurfaceCore* otherCore, PxU32 otherTriIdx, const PxVec4& otherTriBarycentric, PxU32 triIdx, const PxVec4& triBarycentric)
{
Sc::DeformableSurfaceSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
handle = sim->getScene().addTriClothAttachment(*otherCore, otherTriIdx, otherTriBarycentric, *sim, triIdx, triBarycentric);
return handle;
}
void Sc::DeformableSurfaceCore::removeClothAttachment(Sc::DeformableSurfaceCore* otherCore, PxU32 handle)
{
Sc::DeformableSurfaceSim* sim = getSim();
setWakeCounterInternal(ScInternalWakeCounterResetValue);
otherCore->setWakeCounterInternal(ScInternalWakeCounterResetValue);
if (sim)
sim->getScene().removeTriClothAttachment(*otherCore, *sim, handle);
}
void Sc::DeformableSurfaceCore::addMaterial(const PxU16 handle)
{
mCore.materialHandles.pushBack(handle);
mCore.dirty = true;
}
void Sc::DeformableSurfaceCore::clearMaterials()
{
mCore.materialHandles.clear();
mCore.dirty = true;
}
PxActor* Sc::DeformableSurfaceCore::getPxActor() const
{
return PxPointerOffset<PxActor*>(const_cast<DeformableSurfaceCore*>(this), gOffsetTable.scCore2PxActor[getActorCoreType()]);
}
void Sc::DeformableSurfaceCore::attachShapeCore(ShapeCore* shapeCore)
{
Sc::DeformableSurfaceSim* sim = getSim();
if (sim)
sim->attachShapeCore(shapeCore);
}
void Sc::DeformableSurfaceCore::onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags)
{
PX_UNUSED(shape);
DeformableSurfaceSim* sim = getSim();
if (!sim)
return;
ShapeSimBase& s = sim->getShapeSim();
if (notifyFlags & ShapeChangeNotifyFlag::eGEOMETRY)
s.onVolumeOrTransformChange();
if (notifyFlags & ShapeChangeNotifyFlag::eRESET_FILTERING)
s.onResetFiltering();
if (notifyFlags & ShapeChangeNotifyFlag::eSHAPE2BODY)
s.onVolumeOrTransformChange();
if (notifyFlags & ShapeChangeNotifyFlag::eFILTERDATA)
s.onFilterDataChange();
if (notifyFlags & ShapeChangeNotifyFlag::eCONTACTOFFSET)
s.onContactOffsetChange();
if (notifyFlags & ShapeChangeNotifyFlag::eRESTOFFSET)
s.onRestOffsetChange();
}
Sc::DeformableSurfaceSim* Sc::DeformableSurfaceCore::getSim() const
{
return static_cast<Sc::DeformableSurfaceSim*>(ActorCore::getSim());
}
#endif //PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,102 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScDeformableSurfaceSim.h"
#include "geometry/PxTriangleMesh.h"
using namespace physx;
using namespace Dy;
Sc::DeformableSurfaceSim::DeformableSurfaceSim(DeformableSurfaceCore& core, Scene& scene) :
GPUActorSim(scene, core, NULL)
{
mLLDeformableSurface = scene.createLLDeformableSurface(this);
mNodeIndex = scene.getSimpleIslandManager()->addNode(false, false, IG::Node::eDEFORMABLE_SURFACE_TYPE, mLLDeformableSurface);
scene.getSimpleIslandManager()->activateNode(mNodeIndex);
mLLDeformableSurface->setElementId(mShapeSim.getElementID());
}
Sc::DeformableSurfaceSim::~DeformableSurfaceSim()
{
if (!mLLDeformableSurface)
return;
mScene.destroyLLDeformableSurface(*mLLDeformableSurface);
mScene.getSimpleIslandManager()->removeNode(mNodeIndex);
mCore.setSim(NULL);
}
bool Sc::DeformableSurfaceSim::isSleeping() const
{
IG::IslandSim& sim = mScene.getSimpleIslandManager()->getAccurateIslandSim();
return sim.getActiveNodeIndex(mNodeIndex) == PX_INVALID_NODE;
}
void Sc::DeformableSurfaceSim::onSetWakeCounter()
{
mScene.getSimulationController()->setClothWakeCounter(mLLDeformableSurface);
if (mLLDeformableSurface->getCore().wakeCounter > 0.f)
mScene.getSimpleIslandManager()->activateNode(mNodeIndex);
else
mScene.getSimpleIslandManager()->deactivateNode(mNodeIndex);
}
void Sc::DeformableSurfaceSim::attachShapeCore(ShapeCore* core)
{
mShapeSim.setCore(core);
{
PX_ASSERT(getWorldBounds().isFinite());
const PxU32 index = mShapeSim.getElementID();
mScene.getBoundsArray().setBounds(getWorldBounds(), index);
addToAABBMgr(Bp::FilterType::DEFORMABLE_SURFACE);
}
PxsShapeCore* shapeCore = const_cast<PxsShapeCore*>(&core->getCore());
mLLDeformableSurface->setShapeCore(shapeCore);
}
PxBounds3 Sc::DeformableSurfaceSim::getWorldBounds() const
{
const PxTriangleMeshGeometry& triGeom = static_cast<const PxTriangleMeshGeometry&>(mShapeSim.getCore().getGeometry());
// PT: are you sure you want to go through the Px API here?
return triGeom.triangleMesh->getLocalBounds();
}
#endif //PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,78 @@
// 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.
#ifndef SC_DEFORMABLE_SURFACE_SIM_H
#define SC_DEFORMABLE_SURFACE_SIM_H
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "foundation/PxUserAllocated.h"
#include "DyDeformableSurface.h"
#include "ScDeformableSurfaceCore.h"
#include "ScGpuActorSim.h"
namespace physx
{
namespace Sc
{
class Scene;
class DeformableSurfaceSim : public GPUActorSim
{
PX_NOCOPY(DeformableSurfaceSim)
public:
DeformableSurfaceSim(DeformableSurfaceCore& core, Scene& scene);
~DeformableSurfaceSim();
PX_INLINE Dy::DeformableSurface* getLowLevelDeformableSurface() const { return mLLDeformableSurface; }
PX_INLINE DeformableSurfaceCore& getCore() const { return static_cast<DeformableSurfaceCore&>(mCore); }
virtual PxActor* getPxActor() const { return getCore().getPxActor(); }
bool isSleeping() const;
PX_FORCE_INLINE bool isActive() const { return !isSleeping(); }
void setActive(bool active, bool asPartOfCreation=false);
void onSetWakeCounter();
void attachShapeCore(ShapeCore* core);
PxBounds3 getWorldBounds() const;
private:
Dy::DeformableSurface* mLLDeformableSurface;
PxU32 mIslandNodeIndex;
void activate();
void deactivate();
};
} // namespace Sc
} // namespace physx
#endif // PX_SUPPORT_GPU_PHYSX
#endif // SC_DEFORMABLE_SURFACE_SIM_H

View File

@@ -0,0 +1,447 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScDeformableSurfaceCore.h"
#include "ScDeformableVolumeCore.h"
#include "ScPhysics.h"
#include "ScDeformableVolumeSim.h"
#include "DyDeformableVolume.h"
#include "GuTetrahedronMesh.h"
#include "GuBV4.h"
#include "geometry/PxTetrahedronMesh.h"
using namespace physx;
Sc::DeformableVolumeCore::DeformableVolumeCore() :
ActorCore(PxActorType::eDEFORMABLE_VOLUME, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0),
mGpuMemStat(0)
{
const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale();
// Dy::DeformableCore
mCore.sleepThreshold = 5e-5f * scale.speed * scale.speed;
mCore.solverIterationCounts = (1 << 8) | 4;
mCore.wakeCounter = Physics::sWakeCounterOnCreation;
mCore.dirty = true;
// Dy::DeformableVolumeCore
mCore.freezeThreshold = 5e-6f * scale.speed * scale.speed;
}
Sc::DeformableVolumeCore::~DeformableVolumeCore() { }
/////////////////////////////////////////////////////////////////////////////////////////
// PxActor API
/////////////////////////////////////////////////////////////////////////////////////////
void Sc::DeformableVolumeCore::setActorFlags(PxActorFlags flags)
{
mCore.actorFlags = flags;
mCore.dirty = true;
}
/////////////////////////////////////////////////////////////////////////////////////////
// PxDeformableBody API
/////////////////////////////////////////////////////////////////////////////////////////
void Sc::DeformableVolumeCore::setBodyFlags(PxDeformableBodyFlags flags)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
const bool wasDisabledSelfCollision = mCore.bodyFlags & PxDeformableBodyFlag::eDISABLE_SELF_COLLISION;
const bool isDisabledSelfCollision = flags & PxDeformableBodyFlag::eDISABLE_SELF_COLLISION;
if (wasDisabledSelfCollision != isDisabledSelfCollision)
{
if (isDisabledSelfCollision)
sim->disableSelfCollision();
else
sim->enableSelfCollision();
}
}
mCore.bodyFlags = flags;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setLinearDamping(const PxReal v)
{
mCore.linearDamping = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setMaxLinearVelocity(const PxReal v)
{
mCore.maxLinearVelocity = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setMaxPenetrationBias(const PxReal v)
{
mCore.maxPenetrationBias = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setSolverIterationCounts(const PxU16 c)
{
mCore.solverIterationCounts = c;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setSleepThreshold(const PxReal v)
{
mCore.sleepThreshold = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setSettlingThreshold(const PxReal v)
{
mCore.settlingThreshold = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setSettlingDamping(const PxReal v)
{
mCore.settlingDamping = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setSelfCollisionFilterDistance(const PxReal v)
{
mCore.selfCollisionFilterDistance = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setWakeCounter(const PxReal v)
{
setWakeCounterInternal(v);
}
void Sc::DeformableVolumeCore::setWakeCounterInternal(const PxReal v)
{
mCore.wakeCounter = v;
mCore.dirty = true;
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
sim->onSetWakeCounter();
}
}
/////////////////////////////////////////////////////////////////////////////////////////
// PxDeformableVolume API
/////////////////////////////////////////////////////////////////////////////////////////
void Sc::DeformableVolumeCore::setVolumeFlags(PxDeformableVolumeFlags flags)
{
mCore.volumeFlags = flags;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setSelfCollisionStressTolerance(const PxReal v)
{
mCore.selfCollisionStressTolerance = v;
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::setKinematicTargets(const PxVec4* positions)
{
mCore.kinematicTarget = positions;
mCore.dirty = true;
}
PxU32 Sc::DeformableVolumeCore::getGpuIndex() const
{
const Sc::DeformableVolumeSim* sim = getSim();
return sim ? sim->getGpuIndex() : 0xffffffff;
}
void Sc::DeformableVolumeCore::addParticleFilter(Sc::ParticleSystemCore* core, PxU32 particleId, PxU32 userBufferId, PxU32 tetId)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().addParticleFilter(core, *sim, particleId, userBufferId, tetId);
}
void Sc::DeformableVolumeCore::removeParticleFilter(Sc::ParticleSystemCore* core, PxU32 particleId, PxU32 userBufferId, PxU32 tetId)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().removeParticleFilter(core, *sim, particleId, userBufferId, tetId);
}
PxU32 Sc::DeformableVolumeCore::addParticleAttachment(Sc::ParticleSystemCore* core, PxU32 particleId, PxU32 userBufferId, PxU32 tetId, const PxVec4& barycentric)
{
Sc::DeformableVolumeSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
handle = sim->getScene().addParticleAttachment(core, *sim, particleId, userBufferId, tetId, barycentric);
return handle;
}
void Sc::DeformableVolumeCore::removeParticleAttachment(Sc::ParticleSystemCore* core, PxU32 handle)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
sim->getScene().removeParticleAttachment(core, *sim, handle);
setWakeCounterInternal(ScInternalWakeCounterResetValue);
}
}
void Sc::DeformableVolumeCore::addRigidFilter(Sc::BodyCore* core, PxU32 vertId)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().addRigidFilter(core, *sim, vertId);
}
void Sc::DeformableVolumeCore::removeRigidFilter(Sc::BodyCore* core, PxU32 vertId)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().removeRigidFilter(core, *sim, vertId);
}
PxU32 Sc::DeformableVolumeCore::addRigidAttachment(Sc::BodyCore* core, PxU32 particleId, const PxVec3& actorSpacePose, PxConeLimitedConstraint* constraint, bool doConversion)
{
Sc::DeformableVolumeSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if(sim)
handle = sim->getScene().addRigidAttachment(core, *sim, particleId, actorSpacePose, constraint, doConversion);
return handle;
}
void Sc::DeformableVolumeCore::removeRigidAttachment(Sc::BodyCore* core, PxU32 handle)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
sim->getScene().removeRigidAttachment(core, *sim, handle);
setWakeCounterInternal(ScInternalWakeCounterResetValue);
}
}
void Sc::DeformableVolumeCore::addTetRigidFilter(Sc::BodyCore* core, PxU32 tetIdx)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().addTetRigidFilter(core, *sim, tetIdx);
}
void Sc::DeformableVolumeCore::removeTetRigidFilter(Sc::BodyCore* core, PxU32 tetIdx)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
sim->getScene().removeTetRigidFilter(core, *sim, tetIdx);
}
}
PxU32 Sc::DeformableVolumeCore::addTetRigidAttachment(Sc::BodyCore* core, PxU32 tetIdx, const PxVec4& barycentric,
const PxVec3& actorSpacePose, PxConeLimitedConstraint* constraint, bool doConversion)
{
Sc::DeformableVolumeSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
handle = sim->getScene().addTetRigidAttachment(core, *sim, tetIdx, barycentric, actorSpacePose, constraint, doConversion);
return handle;
}
void Sc::DeformableVolumeCore::addSoftBodyFilter(Sc::DeformableVolumeCore& core, PxU32 tetIdx0, PxU32 tetIdx1)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().addSoftBodyFilter(core, tetIdx0, *sim, tetIdx1);
}
void Sc::DeformableVolumeCore::removeSoftBodyFilter(Sc::DeformableVolumeCore& core, PxU32 tetIdx0, PxU32 tetIdx1)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().removeSoftBodyFilter(core, tetIdx0, *sim, tetIdx1);
}
void Sc::DeformableVolumeCore::addSoftBodyFilters(Sc::DeformableVolumeCore& core, PxU32* tetIndices0, PxU32* tetIndices1, PxU32 tetIndicesSize)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().addSoftBodyFilters(core, *sim, tetIndices0, tetIndices1, tetIndicesSize);
}
void Sc::DeformableVolumeCore::removeSoftBodyFilters(Sc::DeformableVolumeCore& core, PxU32* tetIndices0, PxU32* tetIndices1, PxU32 tetIndicesSize)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().removeSoftBodyFilters(core, *sim, tetIndices0, tetIndices1, tetIndicesSize);
}
PxU32 Sc::DeformableVolumeCore::addSoftBodyAttachment(Sc::DeformableVolumeCore& core, PxU32 tetIdx0, const PxVec4& triBarycentric0, PxU32 tetIdx1, const PxVec4& tetBarycentric1,
PxConeLimitedConstraint* constraint, PxReal constraintOffset, bool doConversion)
{
Sc::DeformableVolumeSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
handle = sim->getScene().addSoftBodyAttachment(core, tetIdx0, triBarycentric0, *sim, tetIdx1, tetBarycentric1, constraint, constraintOffset, doConversion);
return handle;
}
void Sc::DeformableVolumeCore::removeSoftBodyAttachment(Sc::DeformableVolumeCore& core, PxU32 handle)
{
Sc::DeformableVolumeSim* sim = getSim();
setWakeCounterInternal(ScInternalWakeCounterResetValue);
core.setWakeCounterInternal(ScInternalWakeCounterResetValue);
if (sim)
sim->getScene().removeSoftBodyAttachment(core, *sim, handle);
}
void Sc::DeformableVolumeCore::addClothFilter(Sc::DeformableSurfaceCore& core, PxU32 triIdx, PxU32 tetIdx)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().addClothFilter(core, triIdx, *sim, tetIdx);
}
void Sc::DeformableVolumeCore::removeClothFilter(Sc::DeformableSurfaceCore& core, PxU32 triIdx, PxU32 tetIdx)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
sim->getScene().removeClothFilter(core, triIdx, *sim, tetIdx);
}
PxU32 Sc::DeformableVolumeCore::addClothAttachment(Sc::DeformableSurfaceCore& core, PxU32 triIdx, const PxVec4& triBarycentric, PxU32 tetIdx, const PxVec4& tetBarycentric,
PxConeLimitedConstraint* constraint, PxReal constraintOffset, bool doConversion)
{
Sc::DeformableVolumeSim* sim = getSim();
PxU32 handle = 0xFFFFFFFF;
if (sim)
handle = sim->getScene().addClothAttachment(core, triIdx, triBarycentric, *sim, tetIdx, tetBarycentric, constraint, constraintOffset, doConversion);
return handle;
}
void Sc::DeformableVolumeCore::removeClothAttachment(Sc::DeformableSurfaceCore& core, PxU32 handle)
{
Sc::DeformableVolumeSim* sim = getSim();
setWakeCounterInternal(ScInternalWakeCounterResetValue);
core.setWakeCounterInternal(ScInternalWakeCounterResetValue);
if (sim)
sim->getScene().removeClothAttachment(core, *sim, handle);
}
//---------------------------------------------------------------------------------
// Internal API
//---------------------------------------------------------------------------------
void Sc::DeformableVolumeCore::addMaterial(const PxU16 handle)
{
mCore.materialHandles.pushBack(handle);
mCore.dirty = true;
}
void Sc::DeformableVolumeCore::clearMaterials()
{
mCore.materialHandles.clear();
mCore.dirty = true;
}
PxActor* Sc::DeformableVolumeCore::getPxActor() const
{
return PxPointerOffset<PxActor*>(const_cast<DeformableVolumeCore*>(this), gOffsetTable.scCore2PxActor[getActorCoreType()]);
}
void Sc::DeformableVolumeCore::attachShapeCore(ShapeCore* shapeCore)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
sim->attachShapeCore(shapeCore);
mCore.dirty = true;
}
}
void Sc::DeformableVolumeCore::attachSimulationMesh(PxTetrahedronMesh* simulationMesh, PxDeformableVolumeAuxData* simulationState)
{
Sc::DeformableVolumeSim* sim = getSim();
if (sim)
{
sim->attachSimulationMesh(simulationMesh, simulationState);
mCore.dirty = true;
}
}
void Sc::DeformableVolumeCore::onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags)
{
PX_UNUSED(shape);
DeformableVolumeSim* sim = getSim();
if (!sim)
return;
ShapeSimBase& s = sim->getShapeSim();
if (notifyFlags & ShapeChangeNotifyFlag::eGEOMETRY)
s.onVolumeOrTransformChange();
if (notifyFlags & ShapeChangeNotifyFlag::eRESET_FILTERING)
s.onResetFiltering();
if (notifyFlags & ShapeChangeNotifyFlag::eSHAPE2BODY)
s.onVolumeOrTransformChange();
if (notifyFlags & ShapeChangeNotifyFlag::eFILTERDATA)
s.onFilterDataChange();
if (notifyFlags & ShapeChangeNotifyFlag::eCONTACTOFFSET)
s.onContactOffsetChange();
if (notifyFlags & ShapeChangeNotifyFlag::eRESTOFFSET)
s.onRestOffsetChange();
}
Sc::DeformableVolumeSim* Sc::DeformableVolumeCore::getSim() const
{
return static_cast<Sc::DeformableVolumeSim*>(ActorCore::getSim());
}
#endif //PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,199 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScDeformableVolumeSim.h"
#include "geometry/PxTetrahedronMesh.h"
using namespace physx;
using namespace Dy;
Sc::DeformableVolumeSim::DeformableVolumeSim(DeformableVolumeCore& core, Scene& scene) :
GPUActorSim(scene, core, NULL)
{
mLLDeformableVolume = scene.createLLDeformableVolume(this);
mNodeIndex = scene.getSimpleIslandManager()->addNode(false, false, IG::Node::eDEFORMABLE_VOLUME_TYPE, mLLDeformableVolume);
scene.getSimpleIslandManager()->activateNode(mNodeIndex);
mLLDeformableVolume->setElementId(mShapeSim.getElementID());
}
Sc::DeformableVolumeSim::~DeformableVolumeSim()
{
if (!mLLDeformableVolume)
return;
mScene.destroyLLDeformableVolume(*mLLDeformableVolume);
mScene.getSimpleIslandManager()->removeNode(mNodeIndex);
mCore.setSim(NULL);
}
bool Sc::DeformableVolumeSim::isSleeping() const
{
IG::IslandSim& sim = mScene.getSimpleIslandManager()->getAccurateIslandSim();
return sim.getActiveNodeIndex(mNodeIndex) == PX_INVALID_NODE;
}
void Sc::DeformableVolumeSim::onSetWakeCounter()
{
mScene.getSimulationController()->setSoftBodyWakeCounter(mLLDeformableVolume);
if (mLLDeformableVolume->getCore().wakeCounter > 0.f)
mScene.getSimpleIslandManager()->activateNode(mNodeIndex);
else
mScene.getSimpleIslandManager()->deactivateNode(mNodeIndex);
}
void Sc::DeformableVolumeSim::attachShapeCore(ShapeCore* core)
{
mShapeSim.setCore(core);
{
PX_ASSERT(getWorldBounds().isFinite());
const PxU32 index = mShapeSim.getElementID();
mScene.getBoundsArray().setBounds(getWorldBounds(), index);
addToAABBMgr(Bp::FilterType::DEFORMABLE_VOLUME);
}
PxsShapeCore* shapeCore = const_cast<PxsShapeCore*>(&core->getCore());
mLLDeformableVolume->setShapeCore(shapeCore);
}
PxBounds3 Sc::DeformableVolumeSim::getWorldBounds() const
{
const PxTetrahedronMeshGeometry& tetGeom = static_cast<const PxTetrahedronMeshGeometry&>(mShapeSim.getCore().getGeometry());
return tetGeom.tetrahedronMesh->getLocalBounds();
}
void Sc::DeformableVolumeSim::attachSimulationMesh(PxTetrahedronMesh* simulationMesh, PxDeformableVolumeAuxData* simulationState)
{
mLLDeformableVolume->setSimShapeCore(simulationMesh, simulationState);
}
PxTetrahedronMesh* Sc::DeformableVolumeSim::getSimulationMesh()
{
return mLLDeformableVolume->getSimulationMesh();
}
PxDeformableVolumeAuxData* Sc::DeformableVolumeSim::getAuxData()
{
return mLLDeformableVolume->getAuxData();
}
PxTetrahedronMesh* Sc::DeformableVolumeSim::getCollisionMesh()
{
return mLLDeformableVolume->getCollisionMesh();
}
void Sc::DeformableVolumeSim::enableSelfCollision()
{
if (isActive())
{
mScene.getSimulationController()->activateSoftbodySelfCollision(mLLDeformableVolume);
}
}
void Sc::DeformableVolumeSim::disableSelfCollision()
{
if (isActive())
{
mScene.getSimulationController()->deactivateSoftbodySelfCollision(mLLDeformableVolume);
}
}
/*void Sc::DeformableVolumeSim::activate()
{
// Activate body
//{
// PX_ASSERT((!isKinematic()) || notInScene() || readInternalFlag(InternalFlags(BF_KINEMATIC_MOVED | BF_KINEMATIC_SURFACE_VELOCITY))); // kinematics should only get activated when a target is set.
// // exception: object gets newly added, then the state change will happen later
// if (!isArticulationLink())
// {
// mLLBody.mInternalFlags &= (~PxsRigidBody::eFROZEN);
// // Put in list of activated bodies. The list gets cleared at the end of a sim step after the sleep callbacks have been fired.
// getScene().onBodyWakeUp(this);
// }
// BodyCore& core = getBodyCore();
// if (core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW)
// {
// PX_ASSERT(!getScene().isInPosePreviewList(*this));
// getScene().addToPosePreviewList(*this);
// }
// createSqBounds();
//}
activateInteractions(*this);
}
void Sc::DeformableVolumeSim::deactivate()
{
deactivateInteractions(*this);
// Deactivate body
//{
// PX_ASSERT((!isKinematic()) || notInScene() || !readInternalFlag(BF_KINEMATIC_MOVED)); // kinematics should only get deactivated when no target is set.
// // exception: object gets newly added, then the state change will happen later
// BodyCore& core = getBodyCore();
// if (!readInternalFlag(BF_ON_DEATHROW))
// {
// // Set velocity to 0.
// // Note: this is also fine if the method gets called because the user puts something to sleep (this behavior is documented in the API)
// PX_ASSERT(core.getWakeCounter() == 0.0f);
// const PxVec3 zero(0.0f);
// core.setLinearVelocityInternal(zero);
// core.setAngularVelocityInternal(zero);
// setForcesToDefaults(!(mLLBody.mInternalFlags & PxsRigidBody::eDISABLE_GRAVITY));
// }
// if (!isArticulationLink()) // Articulations have their own sleep logic.
// getScene().onBodySleep(this);
// if (core.getFlags() & PxRigidBodyFlag::eENABLE_POSE_INTEGRATION_PREVIEW)
// {
// PX_ASSERT(getScene().isInPosePreviewList(*this));
// getScene().removeFromPosePreviewList(*this);
// }
// destroySqBounds();
//}
}*/
PxU32 Sc::DeformableVolumeSim::getGpuIndex() const
{
return mLLDeformableVolume->getGpuIndex();
}
#endif //PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,89 @@
// 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.
#ifndef SC_DEFORMABLE_VOLUME_SIM_H
#define SC_DEFORMABLE_VOLUME_SIM_H
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "foundation/PxUserAllocated.h"
#include "DyDeformableVolume.h"
#include "ScDeformableVolumeCore.h"
#include "ScGpuActorSim.h"
namespace physx
{
namespace Sc
{
class Scene;
class DeformableVolumeSim : public GPUActorSim
{
PX_NOCOPY(DeformableVolumeSim)
public:
DeformableVolumeSim(DeformableVolumeCore& core, Scene& scene);
~DeformableVolumeSim();
PX_INLINE Dy::DeformableVolume* getLowLevelDeformableVolume() const { return mLLDeformableVolume; }
PX_INLINE DeformableVolumeCore& getCore() const { return static_cast<DeformableVolumeCore&>(mCore); }
virtual PxActor* getPxActor() const { return getCore().getPxActor(); }
bool isSleeping() const;
bool isActive() const { return !isSleeping(); }
void setActive(bool active, bool asPartOfCreation=false);
void enableSelfCollision();
void disableSelfCollision();
void onSetWakeCounter();
PxBounds3 getWorldBounds() const;
void attachShapeCore(ShapeCore* core);
void attachSimulationMesh(PxTetrahedronMesh* simulationMesh, PxDeformableVolumeAuxData* simulationState);
PxTetrahedronMesh* getSimulationMesh();
PxDeformableVolumeAuxData* getAuxData();
PxTetrahedronMesh* getCollisionMesh();
PxU32 getGpuIndex() const;
private:
Dy::DeformableVolume* mLLDeformableVolume;
PxU32 mIslandNodeIndex;
// PT: as far as I can tell these are never actually called
// void activate();
// void deactivate();
};
} // namespace Sc
} // namespace physx
#endif // PX_SUPPORT_GPU_PHYSX
#endif // SC_DEFORMABLE_VOLUME_SIM_H

View File

@@ -0,0 +1,41 @@
// 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.
#include "ScElementInteractionMarker.h"
#include "ScNPhaseCore.h"
using namespace physx;
Sc::ElementInteractionMarker::~ElementInteractionMarker()
{
if(isRegistered())
getScene().unregisterInteraction(this);
unregisterFromActors();
}

View File

@@ -0,0 +1,64 @@
// 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_ELEMENT_INTERACTION_MARKER_H
#define SC_ELEMENT_INTERACTION_MARKER_H
#include "ScElementSimInteraction.h"
#include "ScNPhaseCore.h"
namespace physx
{
namespace Sc
{
class ElementInteractionMarker : public ElementSimInteraction
{
public:
PX_INLINE ElementInteractionMarker(ElementSim& element0, ElementSim& element1, bool createParallel/* = false*/);
~ElementInteractionMarker();
};
} // namespace Sc
PX_INLINE Sc::ElementInteractionMarker::ElementInteractionMarker(ElementSim& element0, ElementSim& element1, bool createParallel) :
ElementSimInteraction(element0, element1, InteractionType::eMARKER, InteractionFlag::eRB_ELEMENT|InteractionFlag::eFILTERABLE)
{
if(!createParallel)
{
// PT: no call to onActivate() here, interaction markers are always inactive
registerInActors();
Scene& scene = getScene();
scene.registerInteraction(this, false);
}
}
}
#endif

View File

@@ -0,0 +1,178 @@
// 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.
#include "ScElementSim.h"
#include "ScElementSimInteraction.h"
#include "ScSimStats.h"
using namespace physx;
using namespace Sc;
static PX_FORCE_INLINE bool interactionHasElement(const Interaction* it, const ElementSim* elem)
{
if(it->readInteractionFlag(InteractionFlag::eRB_ELEMENT))
{
PX_ASSERT( (it->getType() == InteractionType::eMARKER) ||
(it->getType() == InteractionType::eOVERLAP) ||
(it->getType() == InteractionType::eTRIGGER) );
const ElementSimInteraction* ei = static_cast<const ElementSimInteraction*>(it);
if((&ei->getElement0() == elem) || (&ei->getElement1() == elem))
return true;
}
return false;
}
Sc::ElementSimInteraction* Sc::ElementSim::ElementInteractionIterator::getNext()
{
while(mInteractions!=mInteractionsLast)
{
Interaction* it = *mInteractions++;
if(interactionHasElement(it, mElement))
return static_cast<ElementSimInteraction*>(it);
}
return NULL;
}
Sc::ElementSimInteraction* Sc::ElementSim::ElementInteractionReverseIterator::getNext()
{
while(mInteractions!=mInteractionsLast)
{
Interaction* it = *--mInteractionsLast;
if(interactionHasElement(it, mElement))
return static_cast<ElementSimInteraction*>(it);
}
return NULL;
}
namespace
{
class ElemSimPtrTableStorageManager : public Cm::PtrTableStorageManager, public PxUserAllocated
{
PX_NOCOPY(ElemSimPtrTableStorageManager)
public:
ElemSimPtrTableStorageManager() {}
~ElemSimPtrTableStorageManager() {}
// PtrTableStorageManager
virtual void** allocate(PxU32 capacity) PX_OVERRIDE
{
return PX_ALLOCATE(void*, capacity, "CmPtrTable pointer array");
}
virtual void deallocate(void** addr, PxU32 /*capacity*/) PX_OVERRIDE
{
PX_FREE(addr);
}
virtual bool canReuse(PxU32 /*originalCapacity*/, PxU32 /*newCapacity*/) PX_OVERRIDE
{
return false;
}
//~PtrTableStorageManager
};
ElemSimPtrTableStorageManager gElemSimTableStorageManager;
}
static PX_FORCE_INLINE void onElementAttach(ElementSim& element, ShapeManager& manager)
{
PX_ASSERT(element.mShapeArrayIndex == 0xffffffff);
element.mShapeArrayIndex = manager.mShapes.getCount();
manager.mShapes.add(&element, gElemSimTableStorageManager);
}
void Sc::ShapeManager::onElementDetach(ElementSim& element)
{
const PxU32 index = element.mShapeArrayIndex;
PX_ASSERT(index != 0xffffffff);
PX_ASSERT(mShapes.getCount());
void** ptrs = mShapes.getPtrs();
PX_ASSERT(reinterpret_cast<ElementSim*>(ptrs[index]) == &element);
const PxU32 last = mShapes.getCount() - 1;
if (index != last)
{
ElementSim* moved = reinterpret_cast<ElementSim*>(ptrs[last]);
PX_ASSERT(moved->mShapeArrayIndex == last);
moved->mShapeArrayIndex = index;
}
mShapes.replaceWithLast(index, gElemSimTableStorageManager);
element.mShapeArrayIndex = 0xffffffff;
}
Sc::ElementSim::ElementSim(ActorSim& actor) :
mActor (actor),
mInBroadPhase (false),
mShapeArrayIndex(0xffffffff)
{
initID();
onElementAttach(*this, actor);
}
Sc::ElementSim::~ElementSim()
{
PX_ASSERT(!mInBroadPhase);
releaseID();
mActor.onElementDetach(*this);
}
void Sc::ElementSim::addToAABBMgr(PxReal contactDistance, Bp::FilterGroup::Enum group, Bp::ElementType::Enum type)
{
const ActorCore& actorCore = mActor.getActorCore();
const PxU32 aggregateID = actorCore.getAggregateID();
const PxU32 envID = actorCore.getEnvID();
Sc::Scene& scene = getScene();
if(!scene.getAABBManager()->addBounds(mElementID, contactDistance, group, this, aggregateID, type, envID))
return;
mInBroadPhase = true;
#if PX_ENABLE_SIM_STATS
scene.getStatsInternal().incBroadphaseAdds();
#else
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
#endif
}
bool Sc::ElementSim::removeFromAABBMgr()
{
PX_ASSERT(mInBroadPhase);
Sc::Scene& scene = getScene();
bool res = scene.getAABBManager()->removeBounds(mElementID);
scene.getAABBManager()->getChangedAABBMgActorHandleMap().growAndReset(mElementID);
mInBroadPhase = false;
#if PX_ENABLE_SIM_STATS
scene.getStatsInternal().incBroadphaseRemoves();
#else
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
#endif
return res;
}

View File

@@ -0,0 +1,136 @@
// 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_ELEMENT_SIM_H
#define SC_ELEMENT_SIM_H
#include "PxFiltering.h"
#include "PxvConfig.h"
#include "ScActorSim.h"
#include "ScInteraction.h"
#include "BpAABBManager.h"
#include "ScObjectIDTracker.h"
#include "ScScene.h"
namespace physx
{
namespace Sc
{
class ElementSimInteraction;
// A ElementSim is a part of a ActorSim. It contributes to the activation framework by adding its interactions to the actor.
class ElementSim
{
PX_NOCOPY(ElementSim)
public:
class ElementInteractionIterator
{
public:
PX_FORCE_INLINE ElementInteractionIterator(const ElementSim& e, PxU32 nbInteractions, Interaction** interactions) :
mInteractions(interactions), mInteractionsLast(interactions + nbInteractions), mElement(&e) {}
ElementSimInteraction* getNext();
private:
Interaction** mInteractions;
Interaction** mInteractionsLast;
const ElementSim* mElement;
};
class ElementInteractionReverseIterator
{
public:
PX_FORCE_INLINE ElementInteractionReverseIterator(const ElementSim& e, PxU32 nbInteractions, Interaction** interactions) :
mInteractions(interactions), mInteractionsLast(interactions + nbInteractions), mElement(&e) {}
ElementSimInteraction* getNext();
private:
Interaction** mInteractions;
Interaction** mInteractionsLast;
const ElementSim* mElement;
};
ElementSim(ActorSim& actor);
protected:
~ElementSim();
public:
// Get an iterator to the interactions connected to the element
// PT: this may seem strange at first glance since the "element interactions" appear to use the "actor interactions". The thing that makes this work is hidden
// inside the iterator implementation: it does parse all the actor interactions indeed, but filters out the ones that do not contain "this", i.e. the desired element.
// So this is inefficient (parsing potentially many more interactions than needed, imagine in a large compound) but it works, and the iterator has a point - it isn't
// just the same as parsing the actor's array.
PX_FORCE_INLINE ElementInteractionIterator getElemInteractions() const { return ElementInteractionIterator(*this, mActor.getActorInteractionCount(), mActor.getActorInteractions()); }
PX_FORCE_INLINE ElementInteractionReverseIterator getElemInteractionsReverse() const { return ElementInteractionReverseIterator(*this, mActor.getActorInteractionCount(), mActor.getActorInteractions()); }
PX_FORCE_INLINE ActorSim& getActor() const { return mActor; }
PX_FORCE_INLINE Scene& getScene() const { return mActor.getScene(); }
PX_FORCE_INLINE PxU32 getElementID() const { return mElementID; }
PX_FORCE_INLINE bool isInBroadPhase() const { return mInBroadPhase; }
PX_FORCE_INLINE void setInBroadPhase() { mInBroadPhase = true; }
void addToAABBMgr(PxReal contactDistance, Bp::FilterGroup::Enum group, Bp::ElementType::Enum type);
PX_FORCE_INLINE void addToAABBMgr(PxReal contactOffset, Bp::FilterType::Enum type)
{
const PxU32 group = Bp::FilterGroup::eDYNAMICS_BASE + mActor.getActorID();
addToAABBMgr(contactOffset, Bp::FilterGroup::Enum((group << BP_FILTERING_TYPE_SHIFT_BIT) | type), Bp::ElementType::eSHAPE);
}
bool removeFromAABBMgr();
PX_FORCE_INLINE void initID()
{
Scene& scene = getScene();
mElementID = scene.getElementIDPool().createID();
scene.getBoundsArray().initEntry(mElementID);
}
PX_FORCE_INLINE void releaseID()
{
getScene().getElementIDPool().releaseID(mElementID);
}
protected:
ActorSim& mActor;
PxU32 mElementID : 31; // PT: ID provided by Sc::Scene::mElementIDPool
PxU32 mInBroadPhase : 1;
public:
PxU32 mShapeArrayIndex;
};
PX_FORCE_INLINE void setFilterObjectAttributeType(PxFilterObjectAttributes& attr, PxFilterObjectType::Enum type)
{
PX_ASSERT((attr & (PxFilterObjectType::eMAX_TYPE_COUNT-1)) == 0);
attr |= type;
}
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,72 @@
// 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_ELEMENT_SIM_INTERACTION_H
#define SC_ELEMENT_SIM_INTERACTION_H
#include "ScInteraction.h"
#include "ScElementSim.h"
namespace physx
{
namespace Sc
{
class ElementSimInteraction : public Interaction
{
public:
PX_FORCE_INLINE ElementSim& getElement0() const { return mElement0; }
PX_FORCE_INLINE ElementSim& getElement1() const { return mElement1; }
protected:
PX_INLINE ElementSimInteraction(ElementSim& element0, ElementSim& element1, InteractionType::Enum type, PxU8 flags);
~ElementSimInteraction() {}
ElementSimInteraction& operator=(const ElementSimInteraction&);
ElementSim& mElement0;
ElementSim& mElement1;
PxU32 mFlags; // PT: moved there in padding bytes, from ShapeInteraction
public:
IG::EdgeIndex mEdgeIndex; // PT: moved there in padding bytes, from ShapeInteraction
};
} // namespace Sc
//////////////////////////////////////////////////////////////////////////
PX_INLINE Sc::ElementSimInteraction::ElementSimInteraction(ElementSim& element0, ElementSim& element1, InteractionType::Enum type, PxU8 flags) :
Interaction (element0.getActor(), element1.getActor(), type, flags),
mElement0 (element0),
mElement1 (element1)
{
}
}
#endif

View File

@@ -0,0 +1,875 @@
// 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.
#include "ScFiltering.h"
#include "ScShapeInteraction.h"
#include "ScTriggerInteraction.h"
#include "ScConstraintCore.h"
#include "ScArticulationSim.h"
#include "geometry/PxTriangleMesh.h"
using namespace physx;
using namespace Sc;
///////////////////////////////////////////////////////////////////////////////
PX_IMPLEMENT_OUTPUT_ERROR
///////////////////////////////////////////////////////////////////////////////
static PX_FORCE_INLINE PxU64 getPairID(const ShapeSimBase& s0, const ShapeSimBase& s1)
{
PxU64 id0 = PxU64(s0.getElementID());
PxU64 id1 = PxU64(s1.getElementID());
if(id1<id0)
PxSwap(id0, id1);
const PxU64 pairID = (id0<<32)|id1;
return pairID;
}
///////////////////////////////////////////////////////////////////////////////
template<const bool supportTriggers>
static PxFilterObjectAttributes getFilterObjectAttributes(const ShapeSimBase& shape)
{
const ActorSim& actorSim = shape.getActor();
PxFilterObjectAttributes filterAttr = actorSim.getFilterAttributes();
if(supportTriggers && (shape.getCore().getFlags() & PxShapeFlag::eTRIGGER_SHAPE))
filterAttr |= PxFilterObjectFlag::eTRIGGER;
if (shape.getGeometryType() == PxGeometryType::eCUSTOM)
filterAttr |= PxFilterObjectFlag::eCUSTOM_GEOMETRY;
#if PX_DEBUG
BodySim* b = shape.getBodySim();
if(b)
{
if(!b->isArticulationLink())
{
if(b->isKinematic())
PX_ASSERT(filterAttr & PxFilterObjectFlag::eKINEMATIC);
PX_ASSERT(PxGetFilterObjectType(filterAttr)==PxFilterObjectType::eRIGID_DYNAMIC);
}
else
{
PX_ASSERT(PxGetFilterObjectType(filterAttr)==PxFilterObjectType::eARTICULATION);
}
}
else
{
#if PX_SUPPORT_GPU_PHYSX
// For deformables and particle system, the bodySim is set to null
if(actorSim.isDeformableSurface())
{
PX_ASSERT(PxGetFilterObjectType(filterAttr)==PxFilterObjectType::eDEFORMABLE_SURFACE);
}
else if(actorSim.isDeformableVolume())
{
PX_ASSERT(PxGetFilterObjectType(filterAttr)==PxFilterObjectType::eDEFORMABLE_VOLUME);
}
else if(actorSim.isParticleSystem())
{
PX_ASSERT(PxGetFilterObjectType(filterAttr)==PxFilterObjectType::ePARTICLESYSTEM);
}
else
#endif
{
PX_ASSERT(PxGetFilterObjectType(filterAttr)==PxFilterObjectType::eRIGID_STATIC);
}
}
#endif
return filterAttr;
}
///////////////////////////////////////////////////////////////////////////////
// PT: checks that the kill & suppress flags are not both set, disable kill flag if they are.
static PX_INLINE void checkFilterFlags(PxFilterFlags& filterFlags)
{
if((filterFlags & (PxFilterFlag::eKILL | PxFilterFlag::eSUPPRESS)) == (PxFilterFlag::eKILL | PxFilterFlag::eSUPPRESS))
{
#if PX_CHECKED
outputError<PxErrorCode::eDEBUG_WARNING>(__LINE__, "Filtering: eKILL and eSUPPRESS must not be set simultaneously. eSUPPRESS will be used.");
#endif
filterFlags.clear(PxFilterFlag::eKILL);
}
}
///////////////////////////////////////////////////////////////////////////////
static const PxPairFlags disableReportsFlags = PxPairFlag::eNOTIFY_CONTACT_POINTS |
PxPairFlag::eNOTIFY_TOUCH_FOUND |
PxPairFlag::eNOTIFY_TOUCH_LOST |
PxPairFlag::eNOTIFY_TOUCH_PERSISTS |
PxPairFlag::eNOTIFY_TOUCH_CCD |
PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND |
PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST |
PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS;
static PX_INLINE PxPairFlags checkRbPairFlags( const ShapeSimBase& s0, const ShapeSimBase& s1, bool isKinePair,
PxPairFlags pairFlags, PxFilterFlags filterFlags, bool isNonRigid, bool isDirectGPU)
{
if(filterFlags & (PxFilterFlag::eSUPPRESS | PxFilterFlag::eKILL))
return pairFlags;
if (isDirectGPU)
{
pairFlags &= ~(disableReportsFlags);
}
if(isKinePair && (pairFlags & PxPairFlag::eSOLVE_CONTACT))
{
#if PX_CHECKED
outputError<PxErrorCode::eDEBUG_WARNING>(__LINE__, "Filtering: Resolving contacts between two kinematic objects is invalid. Contacts will not get resolved.");
#endif
pairFlags.clear(PxPairFlag::eSOLVE_CONTACT);
}
if(isNonRigid && (pairFlags & PxPairFlag::eDETECT_CCD_CONTACT))
pairFlags.clear(PxPairFlag::eDETECT_CCD_CONTACT);
#if PX_CHECKED
// we want to avoid to run contact generation for pairs that should not get resolved or have no contact/trigger reports
if (!(PxU32(pairFlags) & (PxPairFlag::eSOLVE_CONTACT | ShapeInteraction::CONTACT_REPORT_EVENTS)))
outputError<PxErrorCode::eDEBUG_WARNING>(__LINE__, "Filtering: Pair with no contact/trigger reports detected, nor is PxPairFlag::eSOLVE_CONTACT set. It is recommended to suppress/kill such pairs for performance reasons.");
else if(!(pairFlags & (PxPairFlag::eDETECT_DISCRETE_CONTACT | PxPairFlag::eDETECT_CCD_CONTACT)))
outputError<PxErrorCode::eDEBUG_WARNING>(__LINE__, "Filtering: Pair did not request either eDETECT_DISCRETE_CONTACT or eDETECT_CCD_CONTACT. It is recommended to suppress/kill such pairs for performance reasons.");
if(((s0.getFlags() & PxShapeFlag::eTRIGGER_SHAPE)!=0 || (s1.getFlags() & PxShapeFlag::eTRIGGER_SHAPE)!=0) &&
(pairFlags & PxPairFlag::eTRIGGER_DEFAULT) && (pairFlags & PxPairFlag::eDETECT_CCD_CONTACT))
outputError<PxErrorCode::eDEBUG_WARNING>(__LINE__, "Filtering: CCD isn't supported on Triggers yet");
#else
PX_UNUSED(s0);
PX_UNUSED(s1);
#endif
return pairFlags;
}
///////////////////////////////////////////////////////////////////////////////
static PX_FORCE_INLINE bool createFilterInfo(FilterInfo& filterInfo, const PxFilterFlags filterFlags)
{
filterInfo = FilterInfo(filterFlags);
return true;
}
static void filterRbCollisionPairSecondStage(FilterInfo& filterInfo, const FilteringContext& context, const ShapeSimBase& s0, const ShapeSimBase& s1, bool isKinePair,
const PxFilterObjectAttributes fa0, const PxFilterObjectAttributes fa1, bool runCallbacks, bool isNonRigid, PxU64 contextID)
{
PX_UNUSED(contextID);
// Run filter shader
const PxFilterData& fd0 = s0.getCore().getSimulationFilterData();
const PxFilterData& fd1 = s1.getCore().getSimulationFilterData();
filterInfo.setFilterFlags(context.mFilterShader(fa0, fd0, fa1, fd1, filterInfo.mPairFlags, context.mFilterShaderData, context.mFilterShaderDataSize));
if(filterInfo.getFilterFlags() & PxFilterFlag::eCALLBACK)
{
if(context.mFilterCallback)
{
if(!runCallbacks)
{
return;
}
else
{
// If a FilterPair is provided, then we use it, else we create a new one
// (A FilterPair is provided in the case for a pairLost()-pairFound() sequence after refiltering)
struct Local
{
static PX_FORCE_INLINE PxShape* fetchActorAndShape(const ShapeSimBase& sim, const PxFilterObjectAttributes fa, PxActor*& a)
{
a = sim.getActor().getPxActor();
#if PX_SUPPORT_GPU_PHYSX
if(PxGetFilterObjectType(fa)==PxFilterObjectType::ePARTICLESYSTEM)
return NULL; // Particle system does not have a valid shape so set it to null
#endif
PX_UNUSED(fa);
return sim.getPxShape();
}
};
PxActor* a0, *a1;
PxShape* shape0 = Local::fetchActorAndShape(s0, fa0, a0);
PxShape* shape1 = Local::fetchActorAndShape(s1, fa1, a1);
{
// PT: TODO: should be called "onPairFound"
PX_PROFILE_ZONE("USERCODE - PxSimulationFilterCallback::pairFound", contextID);
filterInfo.setFilterFlags(context.mFilterCallback->pairFound(getPairID(s0, s1), fa0, fd0, a0, shape0, fa1, fd1, a1, shape1, filterInfo.mPairFlags));
}
filterInfo.mHasPairID = true;
}
}
else
{
filterInfo.clearFilterFlags(PxFilterFlag::eNOTIFY);
outputError<PxErrorCode::eDEBUG_WARNING>(__LINE__, "Filtering: eCALLBACK set but no filter callback defined.");
}
}
PxFilterFlags flags = filterInfo.getFilterFlags();
checkFilterFlags(flags);
filterInfo.setFilterFlags(flags);
const bool hasNotify = (filterInfo.getFilterFlags() & PxFilterFlag::eNOTIFY) == PxFilterFlag::eNOTIFY;
const bool hasKill = filterInfo.getFilterFlags() & PxFilterFlag::eKILL;
{
if(filterInfo.mHasPairID && (hasKill || !hasNotify))
{
if(hasKill && hasNotify)
{
// PT: TODO: should be called "onPairLost"
PX_PROFILE_ZONE("USERCODE - PxSimulationFilterCallback::pairLost", contextID);
context.mFilterCallback->pairLost(getPairID(s0, s1), fa0, fd0, fa1, fd1, false);
}
if(!hasNotify)
{
// No notification, hence we don't need to treat it as a filter callback pair anymore.
// Make sure that eCALLBACK gets removed as well
filterInfo.clearFilterFlags(PxFilterFlag::eNOTIFY);
}
filterInfo.mHasPairID = false;
}
}
// Sanity checks
PX_ASSERT((!hasKill) || (hasKill && (!filterInfo.mHasPairID)));
PX_ASSERT((!hasNotify) || (hasNotify && filterInfo.mHasPairID));
if(runCallbacks || (!(filterInfo.getFilterFlags() & PxFilterFlag::eCALLBACK)))
filterInfo.mPairFlags = checkRbPairFlags(s0, s1, isKinePair, filterInfo.mPairFlags, filterInfo.getFilterFlags(), isNonRigid, context.mIsDirectGPU);
}
static bool filterArticulationLinks(const BodySim* bs0, const BodySim* bs1)
{
//It's the same articulation, so we can filter based on flags...
const ArticulationSim* articulationSim0 = bs0->getArticulation();
const ArticulationSim* articulationSim1 = bs1->getArticulation();
if(articulationSim0 == articulationSim1)
{
if(articulationSim0->getCore().getArticulationFlags() & PxArticulationFlag::eDISABLE_SELF_COLLISION)
return true;
//check to see if one link is the parent of the other link, if so disable collision
const PxU32 linkId0 = bs0->getNodeIndex().articulationLinkId();
const PxU32 linkId1 = bs1->getNodeIndex().articulationLinkId();
if(linkId1 < linkId0)
return articulationSim0->getLink(linkId0).parent == linkId1;
else
return articulationSim1->getLink(linkId1).parent == linkId0;
}
return false;
}
static PX_FORCE_INLINE bool filterJointedBodies(const ActorSim& rbActor0, const ActorSim& rbActor1)
{
// If the bodies of the shape pair are connected by a joint, we need to check whether this connection disables the collision.
// Note: As an optimization, the dynamic bodies have a flag which specifies whether they have any constraints at all. That works
// because a constraint has at least one dynamic body and an interaction is tracked by both objects.
// PT: the BF_HAS_CONSTRAINTS flag is only raised on dynamic actors in the BodySim class, but it's not raised on static actors.
// Thus the only reliable way to use the flag (without casting to BodySim etc) is when both actors don't have the flag set, in
// which case we're sure we're not dealing with a jointed pair.
if(!rbActor0.readInternalFlag(ActorSim::BF_HAS_CONSTRAINTS) && !rbActor1.readInternalFlag(ActorSim::BF_HAS_CONSTRAINTS))
return false;
ConstraintCore* core = rbActor0.getScene().findConstraintCore(&rbActor0, &rbActor1);
return core ? !(core->getFlags() & PxConstraintFlag::eCOLLISION_ENABLED) : false;
}
static PX_FORCE_INLINE bool hasForceNotifEnabled(const BodySim* bs, PxRigidBodyFlag::Enum flag)
{
if(!bs)
return false;
const PxsRigidCore& core = bs->getBodyCore().getCore();
return core.mFlags.isSet(flag);
}
static PX_FORCE_INLINE bool validateSuppress(const BodySim* b0, const BodySim* b1, PxRigidBodyFlag::Enum flag)
{
if(hasForceNotifEnabled(b0, flag))
return false;
if(hasForceNotifEnabled(b1, flag))
return false;
return true;
}
static PX_FORCE_INLINE bool filterKinematics(const BodySim* b0, const BodySim* b1, bool kine0, bool kine1,
PxPairFilteringMode::Enum kineKineFilteringMode, PxPairFilteringMode::Enum staticKineFilteringMode)
{
const bool kinematicPair = kine0 | kine1;
if(kinematicPair)
{
if(staticKineFilteringMode != PxPairFilteringMode::eKEEP)
{
if(!b0 || !b1)
return validateSuppress(b0, b1, PxRigidBodyFlag::eFORCE_STATIC_KINE_NOTIFICATIONS);
}
if(kineKineFilteringMode != PxPairFilteringMode::eKEEP)
{
if(kine0 && kine1)
return validateSuppress(b0, b1, PxRigidBodyFlag::eFORCE_KINE_KINE_NOTIFICATIONS);
}
}
return false;
}
template<const bool runAllTests>
static bool filterRbCollisionPairShared( FilterInfo& filterInfo, bool& isNonRigid, bool& isKinePair,
const FilteringContext& context,
const ShapeSimBase& s0, const ShapeSimBase& s1,
const PxFilterObjectAttributes filterAttr0, const PxFilterObjectAttributes filterAttr1)
{
const bool kine0 = PxFilterObjectIsKinematic(filterAttr0);
const bool kine1 = PxFilterObjectIsKinematic(filterAttr1);
const ActorSim& rbActor0 = s0.getActor();
const BodySim* bs0 = NULL;
if(filterAttr0 & PxFilterObjectFlagEx::eRIGID_DYNAMIC)
bs0 = static_cast<const BodySim*>(&rbActor0);
else if (filterAttr0 & PxFilterObjectFlagEx::eNON_RIGID)
{
if (filterAttr1 & PxFilterObjectFlag::eCUSTOM_GEOMETRY)
{
return createFilterInfo(filterInfo, PxFilterFlag::eKILL);
}
isNonRigid = true;
}
const ActorSim& rbActor1 = s1.getActor();
const BodySim* bs1 = NULL;
if(filterAttr1 & PxFilterObjectFlagEx::eRIGID_DYNAMIC)
bs1 = static_cast<const BodySim*>(&rbActor1);
else if (filterAttr1 & PxFilterObjectFlagEx::eNON_RIGID)
{
if (filterAttr0 & PxFilterObjectFlag::eCUSTOM_GEOMETRY)
{
return createFilterInfo(filterInfo, PxFilterFlag::eKILL);
}
isNonRigid = true;
}
if(!isNonRigid && filterKinematics(bs0, bs1, kine0, kine1, context.mKineKineFilteringMode, context.mStaticKineFilteringMode))
return createFilterInfo(filterInfo, PxFilterFlag::eSUPPRESS);
if(filterJointedBodies(rbActor0, rbActor1))
return createFilterInfo(filterInfo, PxFilterFlag::eSUPPRESS);
if (!isNonRigid)
{
if (s0.getGeometryType() == PxGeometryType::eTRIANGLEMESH &&
s1.getGeometryType() == PxGeometryType::eTRIANGLEMESH)
{
const PxTriangleMeshGeometry& m0 = static_cast<const PxTriangleMeshGeometry&>(s0.getCore().getGeometry());
const PxTriangleMeshGeometry& m1 = static_cast<const PxTriangleMeshGeometry&>(s1.getCore().getGeometry());
if (m0.triangleMesh->getSDF() == NULL && m1.triangleMesh->getSDF() == NULL)
return createFilterInfo(filterInfo, PxFilterFlag::eKILL);
}
}
const PxFilterObjectType::Enum filterType0 = PxGetFilterObjectType(filterAttr0);
const PxFilterObjectType::Enum filterType1 = PxGetFilterObjectType(filterAttr1);
// PT: For unknown reasons the filtering code was not the same for triggers/refiltered pairs and for regular "shape sim" pairs
// out of the BP. The tests on "runAllTests" below capture that. I did not change what the code
// was doing, although it might very well be wrong - we might want to run all these tests in both codepaths.
if(runAllTests)
{
#if PX_SUPPORT_GPU_PHYSX
if(filterType0==PxFilterObjectType::ePARTICLESYSTEM && filterType1==PxFilterObjectType::ePARTICLESYSTEM)
return createFilterInfo(filterInfo, PxFilterFlag::eKILL);
#endif
}
const bool link0 = filterType0==PxFilterObjectType::eARTICULATION;
const bool link1 = filterType1==PxFilterObjectType::eARTICULATION;
if(runAllTests)
{
if(link0 ^ link1)
{
if(link0)
{
const PxU8 fixedBaseLink = bs0->getLowLevelBody().mCore->fixedBaseLink;
const bool isStaticOrKinematic = (filterType1 == PxFilterObjectType::eRIGID_STATIC) || kine1;
if(fixedBaseLink && isStaticOrKinematic)
return createFilterInfo(filterInfo, PxFilterFlag::eSUPPRESS);
}
if(link1)
{
const PxU8 fixedBaseLink = bs1->getLowLevelBody().mCore->fixedBaseLink;
const bool isStaticOrKinematic = (filterType0 == PxFilterObjectType::eRIGID_STATIC) || kine0;
if(fixedBaseLink && isStaticOrKinematic)
return createFilterInfo(filterInfo, PxFilterFlag::eSUPPRESS);
}
}
}
if(link0 && link1)
{
if(runAllTests)
{
const PxU8 fixedBaseLink0 = bs0->getLowLevelBody().mCore->fixedBaseLink;
const PxU8 fixedBaseLink1 = bs1->getLowLevelBody().mCore->fixedBaseLink;
if(fixedBaseLink0 && fixedBaseLink1)
return createFilterInfo(filterInfo, PxFilterFlag::eSUPPRESS);
}
if(filterArticulationLinks(bs0, bs1))
return createFilterInfo(filterInfo, PxFilterFlag::eKILL);
}
isKinePair = kine0 && kine1;
return false;
}
static void filterRbCollisionPair(FilterInfo& filterInfo, const FilteringContext& context, const ShapeSimBase& s0, const ShapeSimBase& s1, bool& isTriggerPair, bool runCallbacks, PxU64 contextID)
{
const PxFilterObjectAttributes filterAttr0 = getFilterObjectAttributes<true>(s0);
const PxFilterObjectAttributes filterAttr1 = getFilterObjectAttributes<true>(s1);
const bool trigger0 = PxFilterObjectIsTrigger(filterAttr0);
const bool trigger1 = PxFilterObjectIsTrigger(filterAttr1);
isTriggerPair = trigger0 || trigger1;
bool isNonRigid = false;
bool isKinePair = false;
if(isTriggerPair)
{
if(trigger0 && trigger1) // trigger-trigger pairs are not supported
{
createFilterInfo(filterInfo, PxFilterFlag::eKILL);
return;
}
// PT: I think we need to do this here to properly handle kinematic triggers.
const bool kine0 = PxFilterObjectIsKinematic(filterAttr0);
const bool kine1 = PxFilterObjectIsKinematic(filterAttr1);
isKinePair = kine0 && kine1;
}
else
{
if(filterRbCollisionPairShared<false>(filterInfo, isNonRigid, isKinePair, context, s0, s1, filterAttr0, filterAttr1))
return;
}
filterRbCollisionPairSecondStage(filterInfo, context, s0, s1, isKinePair, filterAttr0, filterAttr1, runCallbacks, isNonRigid, contextID);
}
static PX_FORCE_INLINE void filterRbCollisionPairAllTests(FilterInfo& filterInfo, const FilteringContext& context, const ShapeSimBase& s0, const ShapeSimBase& s1, PxU64 contextID)
{
PX_ASSERT(!(s0.getFlags() & PxShapeFlag::eTRIGGER_SHAPE));
PX_ASSERT(!(s1.getFlags() & PxShapeFlag::eTRIGGER_SHAPE));
const PxFilterObjectAttributes filterAttr0 = getFilterObjectAttributes<false>(s0);
const PxFilterObjectAttributes filterAttr1 = getFilterObjectAttributes<false>(s1);
bool isNonRigid = false;
bool isKinePair = false;
if(filterRbCollisionPairShared<true>(filterInfo, isNonRigid, isKinePair, context, s0, s1, filterAttr0, filterAttr1))
return;
filterRbCollisionPairSecondStage(filterInfo, context, s0, s1, isKinePair, filterAttr0, filterAttr1, true, isNonRigid, contextID);
}
static PX_FORCE_INLINE bool testElementSimPointers(const ElementSim* e0, const ElementSim* e1)
{
PX_ASSERT(e0);
PX_ASSERT(e1);
// PT: a bit of defensive coding added for OM-74224 / PX-3571. In theory this should not be needed, as the broadphase is not
// supposed to return null pointers here. But there seems to be an issue somewhere, most probably in the GPU BP kernels,
// and this is an attempt at preventing a crash. We could/should remove this eventually.
// ### DEFENSIVE
if(!e0 || !e1)
return outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "NPhaseCore::runOverlapFilters: found null elements!");
return true;
}
static PX_FORCE_INLINE bool testShapeSimCorePointers(const ShapeSimBase* s0, const ShapeSimBase* s1)
{
bool isValid0 = s0->isPxsCoreValid();
bool isValid1 = s1->isPxsCoreValid();
PX_ASSERT(isValid0);
PX_ASSERT(isValid1);
// GW: further defensive coding added for OM-111249 / PX-4478.
// This is only a temporary / immediate solution to mitigate crashes
// Still need to root-cause what is causing null pointers here
//
// AD: TODO what are we doing about this now that there is a fix? Can we "deprecate" this test?
//
// ### DEFENSIVE
if(!isValid0 || !isValid1)
return outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "NPhaseCore::runOverlapFilters: found null PxsShapeCore pointers!");
return true;
}
// PT: called from OverlapFilterTask. This revisited implementation does not use a bitmap anymore.
void NPhaseCore::runOverlapFilters( PxU32 nbToProcess, Bp::AABBOverlap* PX_RESTRICT pairs, FilterInfo* PX_RESTRICT filterInfo,
PxU32& nbToKeep_, PxU32& nbToSuppress_) const
{
PxU32 nbToKeep = 0;
PxU32 nbToSuppress = 0;
const PxU64 contextID = mOwnerScene.getContextId();
const FilteringContext context(mOwnerScene);
// PT: in this version we write out not just the filter info but also the pairs, and we skip the bitmap entirely. We just do
// a local compaction of surviving pairs, similar to what happens later in Scene::preallocateContactManagers(), but only for a single task.
PxU32 offset = 0;
for(PxU32 i=0; i<nbToProcess; i++)
{
const Bp::AABBOverlap& pair = pairs[i];
const ElementSim* e0 = reinterpret_cast<const ElementSim*>(pair.mUserData0);
const ElementSim* e1 = reinterpret_cast<const ElementSim*>(pair.mUserData1);
if(!testElementSimPointers(e0, e1))
continue;
PX_ASSERT(!findInteraction(e0, e1));
const ShapeSimBase* s0 = static_cast<const ShapeSimBase*>(e0);
const ShapeSimBase* s1 = static_cast<const ShapeSimBase*>(e1);
if(!testShapeSimCorePointers(s0, s1))
continue;
PX_ASSERT(&s0->getActor() != &s1->getActor()); // No actor internal interactions
FilterInfo& filters = filterInfo[offset];
filters.setFilterFlags(PxFilterFlags(0));
filters.mPairFlags = PxPairFlags(0);
filters.mHasPairID = false;
filterRbCollisionPairAllTests(filters, context, *s0, *s1, contextID);
const PxFilterFlags filterFlags = filters.getFilterFlags();
if(!(filterFlags & PxFilterFlag::eKILL))
{
if(!(filterFlags & PxFilterFlag::eSUPPRESS))
nbToKeep++;
else
nbToSuppress++;
pairs[offset++] = pair;
}
}
nbToKeep_ = nbToKeep;
nbToSuppress_ = nbToSuppress;
}
ElementSimInteraction* NPhaseCore::createTriggerElementInteraction(ShapeSimBase& s0, ShapeSimBase& s1)
{
PX_ASSERT((s0.getFlags() & PxShapeFlag::eTRIGGER_SHAPE) || (s1.getFlags() & PxShapeFlag::eTRIGGER_SHAPE));
const FilteringContext context(mOwnerScene);
bool isTriggerPair;
FilterInfo filterInfo;
filterRbCollisionPair(filterInfo, context, s0, s1, isTriggerPair, false, mOwnerScene.getContextId());
PX_ASSERT(isTriggerPair);
if(filterInfo.getFilterFlags() & PxFilterFlag::eKILL)
{
PX_ASSERT(!filterInfo.mHasPairID); // No filter callback pair info for killed pairs
return NULL;
}
return createRbElementInteraction(filterInfo, s0, s1, NULL, NULL, NULL, isTriggerPair);
}
void NPhaseCore::onTriggerOverlapCreated(const Bp::AABBOverlap* PX_RESTRICT pairs, PxU32 pairCount)
{
for(PxU32 i=0; i<pairCount; i++)
{
ElementSim* volume0 = reinterpret_cast<ElementSim*>(pairs[i].mUserData0);
ElementSim* volume1 = reinterpret_cast<ElementSim*>(pairs[i].mUserData1);
if(!testElementSimPointers(volume0, volume1))
continue;
PX_ASSERT(!findInteraction(volume0, volume1));
ShapeSimBase* shapeHi = static_cast<ShapeSimBase*>(volume1);
ShapeSimBase* shapeLo = static_cast<ShapeSimBase*>(volume0);
// No actor internal interactions
PX_ASSERT(&shapeHi->getActor() != &shapeLo->getActor());
// PT: this case is only for triggers these days
PX_ASSERT((shapeLo->getFlags() & PxShapeFlag::eTRIGGER_SHAPE) || (shapeHi->getFlags() & PxShapeFlag::eTRIGGER_SHAPE));
createTriggerElementInteraction(*shapeHi, *shapeLo);
}
}
void NPhaseCore::callPairLost(const ShapeSimBase& s0, const ShapeSimBase& s1, bool objVolumeRemoved)
{
const PxFilterObjectAttributes fa0 = getFilterObjectAttributes<true>(s0);
const PxFilterObjectAttributes fa1 = getFilterObjectAttributes<true>(s1);
const PxFilterData& fd0 = s0.getCore().getSimulationFilterData();
const PxFilterData& fd1 = s1.getCore().getSimulationFilterData();
{
// PT: TODO: should be called "onPairLost"
PX_PROFILE_ZONE("USERCODE - PxSimulationFilterCallback::pairLost", mOwnerScene.getContextId());
mOwnerScene.getFilterCallbackFast()->pairLost(getPairID(s0, s1), fa0, fd0, fa1, fd1, objVolumeRemoved);
}
}
ElementSimInteraction* NPhaseCore::refilterInteraction(ElementSimInteraction* pair, const FilterInfo* filterInfo, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs)
{
const InteractionType::Enum oldType = pair->getType();
switch (oldType)
{
case InteractionType::eTRIGGER:
case InteractionType::eMARKER:
case InteractionType::eOVERLAP:
{
ShapeSimBase& s0 = static_cast<ShapeSimBase&>(pair->getElement0());
ShapeSimBase& s1 = static_cast<ShapeSimBase&>(pair->getElement1());
FilterInfo finfo;
if(filterInfo)
{
// The filter changes are provided by an outside source (the user filter callback)
finfo = *filterInfo;
PX_ASSERT(finfo.mHasPairID);
if((finfo.getFilterFlags() & PxFilterFlag::eKILL) &&
((finfo.getFilterFlags() & PxFilterFlag::eNOTIFY) == PxFilterFlag::eNOTIFY) )
{
callPairLost(s0, s1, false);
finfo.mHasPairID = false;
}
ActorSim& bs0 = s0.getActor();
ActorSim& bs1 = s1.getActor();
const bool isKinePair = PxFilterObjectIsKinematic(bs0.getFilterAttributes()) && PxFilterObjectIsKinematic(bs1.getFilterAttributes());
finfo.mPairFlags = checkRbPairFlags(s0, s1, isKinePair, finfo.mPairFlags, finfo.getFilterFlags(), bs0.isNonRigid() || bs1.isNonRigid(), mOwnerScene.getFlags() & PxSceneFlag::eENABLE_DIRECT_GPU_API);
}
else
{
if(pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR))
callPairLost(s0, s1, false);
const FilteringContext context(mOwnerScene);
bool isTriggerPair;
filterRbCollisionPair(finfo, context, s0, s1, isTriggerPair, true, mOwnerScene.getContextId());
PX_UNUSED(isTriggerPair);
}
if(pair->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR) &&
((finfo.getFilterFlags() & PxFilterFlag::eNOTIFY) != PxFilterFlag::eNOTIFY) )
{
// The pair was a filter callback pair but not any longer
pair->clearInteractionFlag(InteractionFlag::eIS_FILTER_PAIR);
finfo.mHasPairID = false;
}
struct Local
{
static InteractionType::Enum getRbElementInteractionType(const ShapeSimBase* primitive0, const ShapeSimBase* primitive1, PxFilterFlags filterFlag)
{
if(filterFlag & PxFilterFlag::eKILL)
return InteractionType::eINVALID;
if(filterFlag & PxFilterFlag::eSUPPRESS)
return InteractionType::eMARKER;
if(primitive0->getFlags() & PxShapeFlag::eTRIGGER_SHAPE
|| primitive1->getFlags() & PxShapeFlag::eTRIGGER_SHAPE)
return InteractionType::eTRIGGER;
PX_ASSERT( (primitive0->getGeometryType() != PxGeometryType::eTRIANGLEMESH) ||
(primitive1->getGeometryType() != PxGeometryType::eTRIANGLEMESH));
return InteractionType::eOVERLAP;
}
};
const InteractionType::Enum newType = Local::getRbElementInteractionType(&s0, &s1, finfo.getFilterFlags());
if(pair->getType() != newType) //Only convert interaction type if the type has changed
{
return convert(pair, newType, finfo, removeFromDirtyList, outputs);
}
else
{
//The pair flags might have changed, we need to forward the new ones
if(oldType == InteractionType::eOVERLAP)
{
ShapeInteraction* si = static_cast<ShapeInteraction*>(pair);
const PxU32 newPairFlags = finfo.mPairFlags;
const PxU32 oldPairFlags = si->getPairFlags();
PX_ASSERT((newPairFlags & ShapeInteraction::PAIR_FLAGS_MASK) == newPairFlags);
PX_ASSERT((oldPairFlags & ShapeInteraction::PAIR_FLAGS_MASK) == oldPairFlags);
if(newPairFlags != oldPairFlags)
{
if(!(oldPairFlags & ShapeInteraction::CONTACT_REPORT_EVENTS) && (newPairFlags & ShapeInteraction::CONTACT_REPORT_EVENTS) && (si->getActorPair() == NULL || !si->getActorPair()->isReportPair()))
{
// for this actor pair there was no shape pair that requested contact reports but now there is one
// -> all the existing shape pairs need to get re-adjusted to point to an ActorPairReport instance instead.
ActorPair* actorPair = findActorPair(&s0, &s1, PxIntTrue);
if (si->getActorPair() == NULL)
{
actorPair->incRefCount();
si->setActorPair(*actorPair);
}
}
if(si->readFlag(ShapeInteraction::IN_PERSISTENT_EVENT_LIST) && (!(newPairFlags & PxPairFlag::eNOTIFY_TOUCH_PERSISTS)))
{
// the new report pair flags don't require persistent checks anymore -> remove from persistent list
// Note: The pair might get added to the force threshold list later
if(si->readFlag(ShapeInteraction::IS_IN_PERSISTENT_EVENT_LIST))
removeFromPersistentContactEventPairs(si);
else
si->clearFlag(ShapeInteraction::WAS_IN_PERSISTENT_EVENT_LIST);
}
if(newPairFlags & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS)
{
PX_ASSERT((si->mReportPairIndex == INVALID_REPORT_PAIR_ID) || (!si->readFlag(ShapeInteraction::WAS_IN_PERSISTENT_EVENT_LIST)));
if(si->mReportPairIndex == INVALID_REPORT_PAIR_ID && si->readInteractionFlag(InteractionFlag::eIS_ACTIVE))
{
PX_ASSERT(!si->readFlag(ShapeInteraction::WAS_IN_PERSISTENT_EVENT_LIST)); // sanity check: an active pair should never have this flag set
if(si->hasTouch())
addToForceThresholdContactEventPairs(si);
}
}
else if((oldPairFlags & ShapeInteraction::CONTACT_FORCE_THRESHOLD_PAIRS))
{
// no force threshold events needed any longer -> clear flags
si->clearFlag(ShapeInteraction::FORCE_THRESHOLD_EXCEEDED_FLAGS);
if(si->readFlag(ShapeInteraction::IS_IN_FORCE_THRESHOLD_EVENT_LIST))
removeFromForceThresholdContactEventPairs(si);
}
}
si->setPairFlags(finfo.mPairFlags);
}
else if(oldType == InteractionType::eTRIGGER)
static_cast<TriggerInteraction*>(pair)->setTriggerFlags(finfo.mPairFlags);
return pair;
}
}
case InteractionType::eCONSTRAINTSHADER:
case InteractionType::eARTICULATION:
case InteractionType::eTRACKED_IN_SCENE_COUNT:
case InteractionType::eINVALID:
PX_ASSERT(0);
break;
}
return NULL;
}
static bool callStatusChange(PxSimulationFilterCallback* callback, PxU64& pairID, PxPairFlags& pairFlags, PxFilterFlags& filterFlags, PxU64 contextID)
{
PX_UNUSED(contextID);
// PT: TODO: should be called "onStatusChange"
PX_PROFILE_ZONE("USERCODE - PxSimulationFilterCallback::statusChange", contextID);
return callback->statusChange(pairID, pairFlags, filterFlags);
}
void NPhaseCore::fireCustomFilteringCallbacks(PxsContactManagerOutputIterator& outputs)
{
PX_PROFILE_ZONE("Sim.fireCustomFilteringCallbacks", mOwnerScene.getContextId());
PxSimulationFilterCallback* callback = mOwnerScene.getFilterCallbackFast();
if(callback)
{
const PxU64 contextID = mOwnerScene.getContextId();
// Ask user for pair filter status changes
PxU64 pairID;
PxFilterFlags filterFlags;
PxPairFlags pairFlags;
while(callStatusChange(callback, pairID, pairFlags, filterFlags, contextID))
{
const PxU32 id0 = PxU32(pairID);
const PxU32 id1 = PxU32(pairID>>32);
const PxHashMap<ElementSimKey, ElementSimInteraction*>::Entry* pair = mElementSimMap.find(ElementSimKey(id0, id1));
ElementSimInteraction* ei = pair ? pair->second : NULL;
PX_ASSERT(ei);
// Check if the user tries to update a pair even though he deleted it earlier in the same frame
checkFilterFlags(filterFlags);
PX_ASSERT(ei->readInteractionFlag(InteractionFlag::eIS_FILTER_PAIR));
FilterInfo finfo;
finfo.setFilterFlags(filterFlags);
finfo.mPairFlags = pairFlags;
finfo.mHasPairID = true;
ElementSimInteraction* refInt = refilterInteraction(ei, &finfo, true, outputs);
// this gets called at the end of the simulation -> there should be no dirty interactions around
PX_ASSERT(!refInt->readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST));
PX_ASSERT(!refInt->getDirtyFlags());
if((refInt == ei) && (refInt->getType() == InteractionType::eOVERLAP)) // No interaction conversion happened, the pairFlags were just updated
static_cast<ShapeInteraction*>(refInt)->updateState(InteractionDirtyFlag::eFILTER_STATE);
}
}
}

View File

@@ -0,0 +1,60 @@
// 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_FILTERING_H
#define SC_FILTERING_H
#include "PxFiltering.h"
#include "foundation/PxUtilities.h"
namespace physx
{
namespace Sc
{
struct FilterInfo
{
PX_FORCE_INLINE FilterInfo() : mPairFlags(0), mFilterFlags8(0), mHasPairID(false) {}
PX_FORCE_INLINE FilterInfo(PxFilterFlags filterFlags) : mPairFlags(0), mFilterFlags8(filterFlags), mHasPairID(false) {}
PX_FORCE_INLINE PxFilterFlags getFilterFlags() const { return PxFilterFlags(mFilterFlags8); }
PX_FORCE_INLINE void setFilterFlags(PxFilterFlags flags) { mFilterFlags8 = PxTo8(PxU16(flags)); }
PX_FORCE_INLINE void clearFilterFlags(PxFilterFlag::Enum flag)
{
PxFilterFlags flags = getFilterFlags();
flags.clear(flag);
setFilterFlags(flags);
}
PxPairFlags mPairFlags;
PxU8 mFilterFlags8; // PT: PxFilterFlags but only using 8 bits
PxU8 mHasPairID;
};
}
}
#endif

View File

@@ -0,0 +1,69 @@
// 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.
#include "ScGpuActorSim.h"
#include "ScNPhaseCore.h"
using namespace physx;
using namespace Sc;
Sc::GPUActorSim::GPUActorSim(Scene& scene, ActorCore& core, const ShapeCore* shapeCore) :
ActorSim (scene, core),
mShapeSim (*this, shapeCore)
{
}
Sc::GPUActorSim::~GPUActorSim()
{
destroyLowLevelVolume();
}
void Sc::GPUActorSim::addToAABBMgr(Bp::FilterType::Enum type)
{
const PxReal contactOffset = mShapeSim.getContactOffset();
mShapeSim.addToAABBMgr(contactOffset, type);
const PxU32 index = mShapeSim.getElementID();
mScene.updateContactDistance(index, contactOffset);
PxsTransformCache& cache = mScene.getLowLevelContext()->getTransformCache();
cache.initEntry(index);
cache.setTransformCache(PxTransform(PxIdentity), 0, index, index);
}
void Sc::GPUActorSim::destroyLowLevelVolume()
{
if(mShapeSim.isInBroadPhase())
{
PxsContactManagerOutputIterator outputs = mScene.getLowLevelContext()->getNphaseImplementationContext()->getContactManagerOutputs();
mScene.getNPhaseCore()->onVolumeRemoved(&mShapeSim, 0, outputs);
mShapeSim.removeFromAABBMgr();
}
PX_ASSERT(!mShapeSim.isInBroadPhase());
}

View File

@@ -0,0 +1,56 @@
// 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_GPU_ACTOR_SIM_H
#define SC_GPU_ACTOR_SIM_H
#include "ScActorSim.h"
#include "ScShapeSimBase.h"
namespace physx
{
namespace Sc
{
class GPUActorSim : public ActorSim
{
public:
ShapeSimBase mShapeSim;
GPUActorSim(Scene& scene, ActorCore& core, const ShapeCore* shapeCore);
virtual ~GPUActorSim();
const ShapeSimBase& getShapeSim() const { return mShapeSim; }
ShapeSimBase& getShapeSim() { return mShapeSim; }
void addToAABBMgr(Bp::FilterType::Enum type);
void destroyLowLevelVolume();
};
}
}
#endif

View File

@@ -0,0 +1,69 @@
// 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.
#include "ScInteraction.h"
#include "ScNPhaseCore.h"
using namespace physx;
Sc::Interaction::Interaction(ActorSim& actor0, ActorSim& actor1, InteractionType::Enum type, PxU8 flags) :
mActor0 (actor0),
mActor1 (actor1),
mSceneId (PX_INVALID_INTERACTION_SCENE_ID),
mActorId0 (PX_INVALID_INTERACTION_ACTOR_ID),
mActorId1 (PX_INVALID_INTERACTION_ACTOR_ID),
mInteractionType (PxTo8(type)),
mInteractionFlags (flags),
mDirtyFlags (0)
{
PX_ASSERT_WITH_MESSAGE(&actor0.getScene() == &actor1.getScene(),"Cannot create an interaction between actors belonging to different scenes.");
PX_ASSERT(PxU32(type)<256); // PT: type is now stored on a byte
}
void Sc::Interaction::addToDirtyList()
{
getActorSim0().getScene().getNPhaseCore()->addToDirtyInteractionList(this);
}
void Sc::Interaction::removeFromDirtyList()
{
getActorSim0().getScene().getNPhaseCore()->removeFromDirtyInteractionList(this);
}
void Sc::Interaction::setClean(bool removeFromList)
{
if (readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST))
{
if (removeFromList) // if we process all dirty interactions anyway, then we can just clear the list at the end and save the work here.
removeFromDirtyList();
clearInteractionFlag(InteractionFlag::eIN_DIRTY_LIST);
}
mDirtyFlags = 0;
}

View File

@@ -0,0 +1,205 @@
// 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_INTERACTION_H
#define SC_INTERACTION_H
#include "ScInteractionFlags.h"
#include "ScActorSim.h"
#include "foundation/PxUserAllocated.h"
#include "foundation/PxUtilities.h"
namespace physx
{
#define PX_INVALID_INTERACTION_ACTOR_ID 0xffffffff
#define PX_INVALID_INTERACTION_SCENE_ID 0xffffffff
namespace Sc
{
struct InteractionType
{
enum Enum
{
eOVERLAP = 0, // corresponds to ShapeInteraction
eTRIGGER, // corresponds to TriggerInteraction
eMARKER, // corresponds to ElementInteractionMarker
eTRACKED_IN_SCENE_COUNT, // not a real type, interactions above this limit are tracked in the scene
eCONSTRAINTSHADER, // corresponds to ConstraintInteraction
eARTICULATION, // corresponds to ArticulationJointSim
eINVALID
};
};
// Interactions are used for connecting actors into activation groups. An interaction always connects exactly two actors.
// An interaction is implicitly active if at least one of the two actors it connects is active.
class Interaction
{
PX_NOCOPY(Interaction)
Interaction(ActorSim& actor0, ActorSim& actor1, InteractionType::Enum interactionType, PxU8 flags);
~Interaction() { PX_ASSERT(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST)); }
public:
// Interactions automatically register themselves in the actors here
PX_FORCE_INLINE void registerInActors();
// Interactions automatically unregister themselves from the actors here
PX_FORCE_INLINE void unregisterFromActors();
PX_FORCE_INLINE ActorSim& getActorSim0() const { return mActor0; }
PX_FORCE_INLINE ActorSim& getActorSim1() const { return mActor1; }
PX_FORCE_INLINE Scene& getScene() const { return mActor0.getScene(); }
PX_FORCE_INLINE InteractionType::Enum getType() const { return InteractionType::Enum(mInteractionType); }
PX_FORCE_INLINE PxU8 readInteractionFlag(PxU8 flag) const { return PxU8(mInteractionFlags & flag); }
PX_FORCE_INLINE void raiseInteractionFlag(InteractionFlag::Enum flag) { mInteractionFlags |= flag; }
PX_FORCE_INLINE void clearInteractionFlag(InteractionFlag::Enum flag) { mInteractionFlags &= ~flag; }
/**
\brief Mark the interaction as dirty. This will put the interaction into a list that is processed once per simulation step.
\see InteractionDirtyFlag
*/
PX_FORCE_INLINE void setDirty(PxU32 dirtyFlags);
/**
\brief Clear all flags that mark the interaction as dirty and optionally remove the interaction from the list of dirty interactions.
\see InteractionDirtyFlag
*/
/*PX_FORCE_INLINE*/ void setClean(bool removeFromList);
PX_FORCE_INLINE PxIntBool needsRefiltering() const { return (getDirtyFlags() & InteractionDirtyFlag::eFILTER_STATE); }
PX_FORCE_INLINE PxIntBool isElementInteraction() const;
PX_FORCE_INLINE void setInteractionId(PxU32 id) { mSceneId = id; }
PX_FORCE_INLINE PxU32 getInteractionId() const { return mSceneId; }
PX_FORCE_INLINE bool isRegistered() const { return mSceneId != PX_INVALID_INTERACTION_SCENE_ID; }
PX_FORCE_INLINE void setActorId(ActorSim* actor, PxU32 id);
PX_FORCE_INLINE PxU32 getActorId(const ActorSim* actor) const;
PX_FORCE_INLINE PxU8 getDirtyFlags() const { return mDirtyFlags; }
private:
void addToDirtyList();
void removeFromDirtyList();
ActorSim& mActor0;
ActorSim& mActor1;
// PT: TODO: merge the 6bits of the 3 PxU8s in the top bits of the 3 PxU32s
PxU32 mSceneId; // PT: TODO: merge this with mInteractionType
// PT: TODO: are those IDs even worth caching? Since the number of interactions per actor is (or should be) small,
// we could just do a linear search and save memory here...
PxU32 mActorId0; // PT: id of this interaction within mActor0's mInteractions array
PxU32 mActorId1; // PT: id of this interaction within mActor1's mInteractions array
protected:
const PxU8 mInteractionType; // PT: stored on a byte to save space, should be InteractionType enum, 5/6 bits needed here
PxU8 mInteractionFlags; // PT: 6 bits needed here, see InteractionFlag enum
PxU8 mDirtyFlags; // PT: 5 bits needed here, see InteractionDirtyFlag enum
PxU8 mPadding8;
};
} // namespace Sc
//////////////////////////////////////////////////////////////////////////
PX_FORCE_INLINE void Sc::Interaction::registerInActors()
{
mActor0.registerInteractionInActor(this);
mActor1.registerInteractionInActor(this);
}
PX_FORCE_INLINE void Sc::Interaction::unregisterFromActors()
{
mActor0.unregisterInteractionFromActor(this);
mActor1.unregisterInteractionFromActor(this);
}
PX_FORCE_INLINE void Sc::Interaction::setActorId(ActorSim* actor, PxU32 id)
{
PX_ASSERT(id != PX_INVALID_INTERACTION_ACTOR_ID);
PX_ASSERT(&mActor0 == actor || &mActor1 == actor);
if(&mActor0 == actor)
mActorId0 = id;
else
mActorId1 = id;
}
PX_FORCE_INLINE PxU32 Sc::Interaction::getActorId(const ActorSim* actor) const
{
PX_ASSERT(&mActor0 == actor || &mActor1 == actor);
return &mActor0 == actor ? mActorId0 : mActorId1;
}
PX_FORCE_INLINE PxIntBool Sc::Interaction::isElementInteraction() const
{
const PxIntBool res = readInteractionFlag(InteractionFlag::eRB_ELEMENT);
PX_ASSERT( (res &&
((getType() == InteractionType::eOVERLAP) ||
(getType() == InteractionType::eTRIGGER) ||
(getType() == InteractionType::eMARKER))) ||
(!res &&
((getType() == InteractionType::eCONSTRAINTSHADER) ||
(getType() == InteractionType::eARTICULATION))));
return res;
}
PX_FORCE_INLINE void Sc::Interaction::setDirty(PxU32 dirtyFlags)
{
PX_ASSERT(getType() != InteractionType::eARTICULATION);
mDirtyFlags |= PxTo8(dirtyFlags);
if(!readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST))
{
addToDirtyList();
raiseInteractionFlag(InteractionFlag::eIN_DIRTY_LIST);
}
}
//PX_FORCE_INLINE void Sc::Interaction::setClean(bool removeFromList)
//{
// if (readInteractionFlag(InteractionFlag::eIN_DIRTY_LIST))
// {
// if (removeFromList) // if we process all dirty interactions anyway, then we can just clear the list at the end and save the work here.
// removeFromDirtyList();
// clearInteractionFlag(InteractionFlag::eIN_DIRTY_LIST);
// }
//
// mDirtyFlags = 0;
//}
}
#endif

View File

@@ -0,0 +1,71 @@
// 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_INTERACTION_FLAGS_H
#define SC_INTERACTION_FLAGS_H
namespace physx
{
namespace Sc
{
struct InteractionFlag // PT: TODO: use PxFlags
{
enum Enum
{
eRB_ELEMENT = (1 << 0), // Interactions between rigid body shapes
eCONSTRAINT = (1 << 1),
eFILTERABLE = (1 << 2), // Interactions that go through the filter code
eIN_DIRTY_LIST = (1 << 3), // The interaction is in the dirty list
eIS_FILTER_PAIR = (1 << 4), // The interaction is tracked by the filter callback mechanism
eIS_ACTIVE = (1 << 5)
};
};
struct InteractionDirtyFlag
{
enum Enum
{
eFILTER_STATE = (1 << 0), // All changes filtering related
eBODY_KINEMATIC = (1 << 1) | eFILTER_STATE, // A transition between dynamic and kinematic (and vice versa) require a refiltering
eDOMINANCE = (1 << 2),
eREST_OFFSET = (1 << 3),
eVISUALIZATION = (1 << 4)
};
};
} // namespace Sc
} // namespace physx
#endif

View File

@@ -0,0 +1,129 @@
// 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.
#include "ScIterators.h"
#include "ScBodySim.h"
#include "ScShapeSim.h"
#include "ScShapeInteraction.h"
using namespace physx;
///////////////////////////////////////////////////////////////////////////////
Sc::ContactIterator::Pair::Pair(const void*& contactPatches, const void*& contactPoints, const void*& frictionPatches, PxU32 /*contactDataSize*/, const PxReal*& forces, PxU32 numContacts, PxU32 numPatches,
ShapeSimBase& shape0, ShapeSimBase& shape1, ActorSim* actor0, ActorSim* actor1)
: mIndex(0)
, mNumContacts(numContacts)
, mIter(reinterpret_cast<const PxU8*>(contactPatches), reinterpret_cast<const PxU8*>(contactPoints), reinterpret_cast<const PxU32*>(forces + numContacts), numPatches, numContacts)
, mAnchorIter(reinterpret_cast<const PxU8*>(contactPatches), reinterpret_cast<const PxU8*>(frictionPatches), numPatches)
, mForces(forces)
, mActor0(actor0->getPxActor())
, mActor1(actor1->getPxActor())
{
mCurrentContact.shape0 = shape0.getPxShape();
mCurrentContact.shape1 = shape1.getPxShape();
mCurrentContact.normalForceAvailable = (forces != NULL);
}
Sc::ContactIterator::Pair* Sc::ContactIterator::getNextPair()
{
PX_ASSERT(mCurrent || (mCurrent == mLast));
if(mCurrent < mLast)
{
ShapeInteraction* si = static_cast<ShapeInteraction*>(*mCurrent);
const void* contactPatches = NULL;
const void* contactPoints = NULL;
PxU32 contactDataSize = 0;
const PxReal* forces = NULL;
PxU32 numContacts = 0;
PxU32 numPatches = 0;
const void* frictionPatches = NULL;
PxU32 nextOffset = si->getContactPointData(contactPatches, contactPoints, contactDataSize, numContacts, numPatches, forces, mOffset, *mOutputs, frictionPatches);
if (nextOffset == mOffset)
++mCurrent;
else
mOffset = nextOffset;
mCurrentPair = Pair(contactPatches, contactPoints, frictionPatches, contactDataSize, forces, numContacts, numPatches, si->getShape0(), si->getShape1(), &si->getActorSim0(), &si->getActorSim1());
return &mCurrentPair;
}
else
return NULL;
}
Sc::Contact* Sc::ContactIterator::Pair::getNextContact()
{
if(mIndex < mNumContacts)
{
while (!mIter.hasNextContact())
{
if(!mIter.hasNextPatch())
return NULL;
mIter.nextPatch();
}
mIter.nextContact();
mCurrentContact.normal = mIter.getContactNormal();
mCurrentContact.point = mIter.getContactPoint();
mCurrentContact.separation = mIter.getSeparation();
mCurrentContact.normalForce = mForces ? mForces[mIndex] : 0;
mCurrentContact.faceIndex0 = mIter.getFaceIndex0();
mCurrentContact.faceIndex1 = mIter.getFaceIndex1();
mIndex++;
return &mCurrentContact;
}
return NULL;
}
Sc::FrictionAnchor* Sc::ContactIterator::Pair::getNextFrictionAnchor()
{
if(mAnchorIter.hasNextPatch())
{
while (!mAnchorIter.hasNextFrictionAnchor())
{
if(!mAnchorIter.hasNextPatch())
return NULL;
mAnchorIter.nextPatch();
}
mAnchorIter.nextFrictionAnchor();
mCurrentAnchor.normal = mAnchorIter.getNormal();
mCurrentAnchor.point = mAnchorIter.getPosition();
mCurrentAnchor.impulse = mAnchorIter.getImpulse();
return &mCurrentAnchor;
}
return NULL;
}
///////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,470 @@
// 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.
#include "common/PxProfileZone.h"
#include "ScScene.h"
#include "ScBodySim.h"
#include "ScShapeSim.h"
#include "PxsSimulationController.h"
#include "BpAABBManagerBase.h"
using namespace physx;
using namespace Sc;
//PX_IMPLEMENT_OUTPUT_ERROR
///////////////////////////////////////////////////////////////////////////////
// PT: TODO: consider using a non-member function for this one
void BodySim::calculateKinematicVelocity(PxReal oneOverDt)
{
PX_ASSERT(isKinematic());
/*------------------------------------------------\
| kinematic bodies are moved directly by the user and are not influenced by external forces
| we simply determine the distance moved since the last simulation frame and
| assign the appropriate delta to the velocity. This vel will be used to shove dynamic
| objects in the solver.
| We have to do this like so in a delayed way, because when the user sets the target pos the dt is not
| yet known.
\------------------------------------------------*/
PX_ASSERT(isActive());
BodyCore& core = getBodyCore();
if (readInternalFlag(BF_KINEMATIC_MOVED))
{
clearInternalFlag(InternalFlags(BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2));
const SimStateData* kData = getSimStateData(true);
PX_ASSERT(kData);
PX_ASSERT(kData->isKine());
PX_ASSERT(kData->getKinematicData()->targetValid);
PxVec3 linVelLL, angVelLL;
const PxTransform targetPose = kData->getKinematicData()->targetPose;
const PxTransform& currBody2World = getBody2World();
//the kinematic target pose is now the target of the body (CoM) and not the actor.
PxVec3 deltaPos = targetPose.p;
deltaPos -= currBody2World.p;
linVelLL = deltaPos * oneOverDt;
PxQuat q = targetPose.q * currBody2World.q.getConjugate();
if (q.w < 0) //shortest angle.
q = -q;
PxReal angle;
PxVec3 axis;
q.toRadiansAndUnitAxis(angle, axis);
angVelLL = axis * angle * oneOverDt;
core.getCore().linearVelocity = linVelLL;
core.getCore().angularVelocity = angVelLL;
// Moving a kinematic should trigger a wakeUp call on a higher level.
PX_ASSERT(core.getWakeCounter()>0);
PX_ASSERT(isActive());
}
else if (!readInternalFlag(BF_KINEMATIC_SURFACE_VELOCITY))
{
core.setLinearVelocity(PxVec3(0.0f), true);
core.setAngularVelocity(PxVec3(0.0f), true);
}
}
namespace
{
class ScKinematicUpdateTask : public Cm::Task
{
Sc::BodyCore*const* mKinematics;
const PxU32 mNbKinematics;
const PxReal mOneOverDt;
PX_NOCOPY(ScKinematicUpdateTask)
public:
static const PxU32 NbKinematicsPerTask = 1024;
ScKinematicUpdateTask(Sc::BodyCore*const* kinematics, PxU32 nbKinematics, PxReal oneOverDt, PxU64 contextID) :
Cm::Task(contextID), mKinematics(kinematics), mNbKinematics(nbKinematics), mOneOverDt(oneOverDt)
{
}
virtual void runInternal()
{
Sc::BodyCore*const* kinematics = mKinematics;
PxU32 nb = mNbKinematics;
const float oneOverDt = mOneOverDt;
while(nb--)
{
Sc::BodyCore* b = *kinematics++;
PX_ASSERT(b->getSim()->isKinematic());
PX_ASSERT(b->getSim()->isActive());
b->getSim()->calculateKinematicVelocity(oneOverDt);
}
}
virtual const char* getName() const
{
return "ScScene.KinematicUpdateTask";
}
};
}
void Sc::Scene::kinematicsSetup(PxBaseTask* continuation)
{
const PxU32 nbKinematics = getActiveKinematicBodiesCount();
if(!nbKinematics)
return;
BodyCore*const* kinematics = getActiveKinematicBodies();
// PT: create a copy of active bodies for the taks to operate on while the main array is
// potentially resized by operations running in parallel.
if(mActiveKinematicsCopyCapacity<nbKinematics)
{
PX_FREE(mActiveKinematicsCopy);
mActiveKinematicsCopy = PX_ALLOCATE(BodyCore*, nbKinematics, "Sc::Scene::mActiveKinematicsCopy");
mActiveKinematicsCopyCapacity = nbKinematics;
}
PxMemCopy(mActiveKinematicsCopy, kinematics, nbKinematics*sizeof(BodyCore*));
kinematics = mActiveKinematicsCopy;
Cm::FlushPool& flushPool = mLLContext->getTaskPool();
// PT: TASK-CREATION TAG
// PT: TODO: better load balancing? This will be single threaded for less than 1K kinematics
for(PxU32 i = 0; i < nbKinematics; i += ScKinematicUpdateTask::NbKinematicsPerTask)
{
ScKinematicUpdateTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScKinematicUpdateTask)), ScKinematicUpdateTask)
(kinematics + i, PxMin(ScKinematicUpdateTask::NbKinematicsPerTask, nbKinematics - i), mOneOverDt, mContextId);
task->setContinuation(continuation);
task->removeReference();
}
if((mPublicFlags & PxSceneFlag::eENABLE_GPU_DYNAMICS))
{
// PT: running this serially for now because it's unsafe: mNPhaseCore->updateDirtyInteractions() (called after this)
// can also call mSimulationController.updateDynamic() via BodySim::internalWakeUpBase
PxU32 nb = nbKinematics;
while(nb--)
{
Sc::BodyCore* b = *kinematics++;
Sc::BodySim* bodySim = b->getSim();
PX_ASSERT(!bodySim->getArticulation());
mSimulationController->updateDynamic(NULL, bodySim->getNodeIndex());
}
}
}
///////////////////////////////////////////////////////////////////////////////
// PT: TODO: consider using a non-member function for this one
void BodySim::updateKinematicPose()
{
/*------------------------------------------------\
| kinematic bodies are moved directly by the user and are not influenced by external forces
| we simply determine the distance moved since the last simulation frame and
| assign the appropriate delta to the velocity. This vel will be used to shove dynamic
| objects in the solver.
| We have to do this like so in a delayed way, because when the user sets the target pos the dt is not
| yet known.
\------------------------------------------------*/
PX_ASSERT(isKinematic());
PX_ASSERT(isActive());
if(readInternalFlag(BF_KINEMATIC_MOVED))
{
clearInternalFlag(InternalFlags(BF_KINEMATIC_SETTLING | BF_KINEMATIC_SETTLING_2));
const SimStateData* kData = getSimStateData(true);
PX_ASSERT(kData);
PX_ASSERT(kData->isKine());
PX_ASSERT(kData->getKinematicData()->targetValid);
const PxTransform targetPose = kData->getKinematicData()->targetPose;
getBodyCore().getCore().body2World = targetPose;
}
}
namespace
{
class ScKinematicPoseUpdateTask : public Cm::Task
{
Sc::BodyCore*const* mKinematics;
const PxU32 mNbKinematics;
PX_NOCOPY(ScKinematicPoseUpdateTask)
public:
static const PxU32 NbKinematicsPerTask = 1024;
ScKinematicPoseUpdateTask(Sc::BodyCore*const* kinematics, PxU32 nbKinematics, PxU64 contextID) :
Cm::Task(contextID), mKinematics(kinematics), mNbKinematics(nbKinematics)
{
}
virtual void runInternal()
{
const PxU32 nb = mNbKinematics;
for(PxU32 a=0; a<nb; ++a)
{
if ((a + 16) < nb)
{
PxPrefetchLine(static_cast<Sc::BodyCore* const>(mKinematics[a + 16]));
if ((a + 4) < nb)
{
PxPrefetchLine(static_cast<Sc::BodyCore* const>(mKinematics[a + 4])->getSim());
PxPrefetchLine(static_cast<Sc::BodyCore* const>(mKinematics[a + 4])->getSim()->getSimStateData_Unchecked());
}
}
Sc::BodyCore* b = static_cast<Sc::BodyCore* const>(mKinematics[a]);
PX_ASSERT(b->getSim()->isKinematic());
PX_ASSERT(b->getSim()->isActive());
b->getSim()->updateKinematicPose();
}
}
virtual const char* getName() const
{
return "ScScene.ScKinematicPoseUpdateTask";
}
};
}
void Sc::Scene::integrateKinematicPose()
{
PX_PROFILE_ZONE("Sim.integrateKinematicPose", mContextId);
const PxU32 nbKinematics = getActiveKinematicBodiesCount();
BodyCore*const* kinematics = getActiveKinematicBodies();
Cm::FlushPool& flushPool = mLLContext->getTaskPool();
// PT: TASK-CREATION TAG
for(PxU32 i=0; i<nbKinematics; i+= ScKinematicPoseUpdateTask::NbKinematicsPerTask)
{
ScKinematicPoseUpdateTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScKinematicPoseUpdateTask)), ScKinematicPoseUpdateTask)
(kinematics + i, PxMin(nbKinematics - i, ScKinematicPoseUpdateTask::NbKinematicsPerTask), mContextId);
task->setContinuation(&mAfterIntegration);
task->removeReference();
}
}
///////////////////////////////////////////////////////////////////////////////
namespace
{
class ScKinematicShapeUpdateTask : public Cm::Task
{
Sc::BodyCore*const* mKinematics;
const PxU32 mNbKinematics;
PxsTransformCache& mCache;
Bp::BoundsArray& mBoundsArray;
PX_NOCOPY(ScKinematicShapeUpdateTask)
public:
static const PxU32 NbKinematicsShapesPerTask = 1024;
ScKinematicShapeUpdateTask(Sc::BodyCore*const* kinematics, PxU32 nbKinematics, PxsTransformCache& cache, Bp::BoundsArray& boundsArray, PxU64 contextID) :
Cm::Task(contextID), mKinematics(kinematics), mNbKinematics(nbKinematics), mCache(cache), mBoundsArray(boundsArray)
{
}
virtual void runInternal()
{
const PxU32 nb = mNbKinematics;
for(PxU32 a=0; a<nb; ++a)
{
Sc::BodyCore* b = static_cast<Sc::BodyCore*>(mKinematics[a]);
PX_ASSERT(b->getSim()->isKinematic());
PX_ASSERT(b->getSim()->isActive());
b->getSim()->updateCached(mCache, mBoundsArray);
}
}
virtual const char* getName() const
{
return "ScScene.KinematicShapeUpdateTask";
}
};
}
void Sc::Scene::updateKinematicCached(PxBaseTask* continuation)
{
PX_PROFILE_ZONE("Sim.updateKinematicCached", mContextId);
const PxU32 nbKinematics = getActiveKinematicBodiesCount();
if(!nbKinematics)
return;
BodyCore*const* kinematics = getActiveKinematicBodies();
Cm::FlushPool& flushPool = mLLContext->getTaskPool();
PxU32 startIndex = 0;
PxU32 nbShapes = 0;
{
PX_PROFILE_ZONE("ShapeUpdate", mContextId);
// PT: TASK-CREATION TAG
for(PxU32 i=0; i<nbKinematics; i++)
{
Sc::BodySim* sim = static_cast<Sc::BodyCore*>(kinematics[i])->getSim();
PX_ASSERT(sim->isKinematic());
PX_ASSERT(sim->isActive());
nbShapes += sim->getNbShapes();
if (nbShapes >= ScKinematicShapeUpdateTask::NbKinematicsShapesPerTask)
{
ScKinematicShapeUpdateTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScKinematicShapeUpdateTask)), ScKinematicShapeUpdateTask)
(kinematics + startIndex, (i + 1) - startIndex, mLLContext->getTransformCache(), *mBoundsArray, mContextId);
task->setContinuation(continuation);
task->removeReference();
startIndex = i + 1;
nbShapes = 0;
}
}
if(nbShapes)
{
ScKinematicShapeUpdateTask* task = PX_PLACEMENT_NEW(flushPool.allocate(sizeof(ScKinematicShapeUpdateTask)), ScKinematicShapeUpdateTask)
(kinematics + startIndex, nbKinematics - startIndex, mLLContext->getTransformCache(), *mBoundsArray, mContextId);
task->setContinuation(continuation);
task->removeReference();
}
}
{
PxBitMapPinned& changedAABBMap = mAABBManager->getChangedAABBMgActorHandleMap();
mLLContext->getTransformCache().setChangedState();
mBoundsArray->setChangedState();
for (PxU32 i = 0; i < nbKinematics; ++i)
{
Sc::BodySim* bodySim = static_cast<Sc::BodyCore*>(kinematics[i])->getSim();
if ((i+16) < nbKinematics)
{
PxPrefetchLine(kinematics[i + 16]);
if ((i + 8) < nbKinematics)
{
PxPrefetchLine(kinematics[i + 8]->getSim());
}
}
// PT: ### changedMap pattern #1
PxU32 nbElems = bodySim->getNbElements();
Sc::ElementSim** elems = bodySim->getElements();
while (nbElems--)
{
Sc::ShapeSim* sim = static_cast<Sc::ShapeSim*>(*elems++);
//KS - TODO - can we parallelize this? The problem with parallelizing is that it's a bit operation,
//so we would either need to use atomic operations or have some high-level concept that guarantees
//that threads don't write to the same word in the map simultaneously
if (sim->getFlags()&PxU32(PxShapeFlag::eSIMULATION_SHAPE | PxShapeFlag::eTRIGGER_SHAPE))
changedAABBMap.set(sim->getElementID());
}
mSimulationController->updateDynamic(NULL, bodySim->getNodeIndex());
}
}
}
///////////////////////////////////////////////////////////////////////////////
// PT: TODO: consider using a non-member function for this one
bool BodySim::deactivateKinematic()
{
BodyCore& core = getBodyCore();
if(readInternalFlag(BF_KINEMATIC_SETTLING_2))
{
clearInternalFlag(BF_KINEMATIC_SETTLING_2);
core.setWakeCounterFromSim(0); // For sleeping objects the wake counter must be 0. This needs to hold for kinematics too.
notifyReadyForSleeping();
notifyPutToSleep();
setActive(false);
return true;
}
else if (readInternalFlag(BF_KINEMATIC_SETTLING))
{
clearInternalFlag(BF_KINEMATIC_SETTLING);
raiseInternalFlag(BF_KINEMATIC_SETTLING_2);
}
else if (!readInternalFlag(BF_KINEMATIC_SURFACE_VELOCITY))
{
clearInternalFlag(BF_KINEMATIC_MOVED);
raiseInternalFlag(BF_KINEMATIC_SETTLING);
}
return false;
}
// PT: called during fetchResults()
void Sc::Scene::postCallbacksPreSyncKinematics()
{
PX_PROFILE_ZONE("Sim.postCallbacksPreSyncKinematics", mContextId);
// Put/prepare kinematics to/for sleep and invalidate target pose
// note: this needs to get done after the contact callbacks because
// the target might get read there.
//
PxU32 nbKinematics = getActiveKinematicBodiesCount();
BodyCore*const* kinematics = getActiveKinematicBodies();
//KS - this method must run over the kinematic actors in reverse.
while(nbKinematics--)
{
if(nbKinematics > 16)
{
PxPrefetchLine(static_cast<BodyCore*>(kinematics[nbKinematics-16]));
}
if (nbKinematics > 4)
{
PxPrefetchLine((static_cast<BodyCore*>(kinematics[nbKinematics - 4]))->getSim());
PxPrefetchLine((static_cast<BodyCore*>(kinematics[nbKinematics - 4]))->getSim()->getSimStateData_Unchecked());
}
BodyCore* b = static_cast<BodyCore*>(kinematics[nbKinematics]);
//kinematics++;
PX_ASSERT(b->getSim()->isKinematic());
PX_ASSERT(b->getSim()->isActive());
b->invalidateKinematicTarget();
b->getSim()->deactivateKinematic();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,409 @@
// 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_NPHASE_CORE_H
#define SC_NPHASE_CORE_H
#include "PxSceneDesc.h"
#include "foundation/PxHash.h"
#include "foundation/PxUserAllocated.h"
#include "foundation/PxHashSet.h"
#include "foundation/PxHashMap.h"
#include "foundation/PxMutex.h"
#include "foundation/PxAtomic.h"
#include "PxPhysXConfig.h"
#include "foundation/PxPool.h"
#include "PxSimulationEventCallback.h"
#include "ScTriggerPairs.h"
#include "ScScene.h"
#include "ScContactReportBuffer.h"
namespace physx
{
namespace Bp
{
struct AABBOverlap;
}
namespace Sc
{
class ElementSim;
class ShapeSimBase;
class Interaction;
class ElementSimInteraction;
class ElementInteractionMarker;
class TriggerInteraction;
class ShapeInteraction;
class ActorPair;
class ActorPairReport;
class ActorPairContactReportData;
class ContactStreamManager;
class TriggerContactTask;
struct PairReleaseFlag
{
enum Enum
{
eRUN_LOST_TOUCH_LOGIC = (1 << 0), // run the lost-touch-logic for a pair that gets removed.
eWAKE_ON_LOST_TOUCH = (1 << 1) // a pair that lost touch should check whether the actors should get woken up
};
};
/*
NPhaseCore encapsulates the near phase processing to allow multiple implementations(eg threading and non threaded).
The broadphase inserts shape pairs into the NPhaseCore, which are then processed into contact point streams.
Pairs can then be processed into AxisConstraints by the GroupSolveCore.
*/
struct BodyPairKey
{
PX_FORCE_INLINE BodyPairKey(PxU32 sim0, PxU32 sim1) : mSim0(sim0), mSim1(sim1) {}
const PxU32 mSim0;
const PxU32 mSim1;
PX_FORCE_INLINE bool operator == (const BodyPairKey& pair) const { return mSim0 == pair.mSim0 && mSim1 == pair.mSim1; }
};
PX_INLINE PxU32 PxComputeHash(const BodyPairKey& key)
{
const PxU32 add0 = key.mSim0;
const PxU32 add1 = key.mSim1;
const PxU32 base = PxU32((add0 & 0xFFFF) | (add1 << 16));
return physx::PxComputeHash(base);
}
struct ElementSimKey
{
PxU32 mID0;
PxU32 mID1;
ElementSimKey() : mID0(0xffffffff), mID1(0xffffffff)
{}
ElementSimKey(PxU32 id0, PxU32 id1)
{
if(id0 > id1)
PxSwap(id0, id1);
mID0 = id0;
mID1 = id1;
}
PX_FORCE_INLINE bool operator == (const ElementSimKey& pair) const { return mID0 == pair.mID0 && mID1 == pair.mID1; }
};
PX_INLINE PxU32 PxComputeHash(const ElementSimKey& key)
{
const PxU64 base = PxU64(key.mID0) | (PxU64(key.mID1) << 32);
return physx::PxComputeHash(base);
}
class ContactReportAllocationManager
{
PxU8* mBuffer;
PxU32 mBufferSize;
PxU32 mCurrentBufferIndex;
PxU32 mCurrentOffset;
ContactReportBuffer& mReportBuffer;
PxMutex& mMutex;
const PxU32 mBuferBlockSize;
PX_NOCOPY(ContactReportAllocationManager)
public:
ContactReportAllocationManager(ContactReportBuffer& buffer, PxMutex& mutex, const PxU32 bufferBlockSize = 16384) : mBuffer(NULL), mBufferSize(0), mCurrentBufferIndex(0),
mCurrentOffset(0), mReportBuffer(buffer), mMutex(mutex), mBuferBlockSize(bufferBlockSize)
{
}
PxU8* allocate(PxU32 size, PxU32& index, PxU32 alignment = 16u)
{
//(1) fix up offsets...
const PxU32 pad = ((mCurrentBufferIndex + alignment - 1)&~(alignment - 1)) - mCurrentBufferIndex;
PxU32 currOffset = mCurrentOffset + pad;
if ((currOffset + size) > mBufferSize)
{
const PxU32 allocSize = PxMax(size, mBuferBlockSize);
mMutex.lock();
mBuffer = mReportBuffer.allocateNotThreadSafe(allocSize, mCurrentBufferIndex, alignment);
mCurrentOffset = currOffset = 0;
mBufferSize = allocSize;
mMutex.unlock();
}
PxU8* ret = mBuffer + currOffset;
index = mCurrentBufferIndex + currOffset;
mCurrentOffset = currOffset + size;
return ret;
}
};
class TriggerProcessingContext
{
public:
TriggerProcessingContext()
: mTmpTriggerProcessingBlock(NULL)
, mTmpTriggerPairCount(0)
{
}
bool initialize(TriggerInteraction**, PxU32 pairCount, PxcScratchAllocator&);
void deinitialize(PxcScratchAllocator&);
PX_FORCE_INLINE TriggerInteraction* const* getTriggerInteractions() const
{
return reinterpret_cast<TriggerInteraction**>(mTmpTriggerProcessingBlock);
}
PX_FORCE_INLINE PxU32 getTriggerInteractionCount() const
{
return mTmpTriggerPairCount;
}
PX_FORCE_INLINE TriggerContactTask* getTriggerContactTasks()
{
const PxU32 offset = mTmpTriggerPairCount * sizeof(TriggerInteraction*);
return reinterpret_cast<TriggerContactTask*>(mTmpTriggerProcessingBlock + offset);
}
PX_FORCE_INLINE PxMutex& getTriggerWriteBackLock()
{
return mTriggerWriteBackLock;
}
private:
PxU8* mTmpTriggerProcessingBlock; // temporary memory block to process trigger pairs in parallel
// (see comment in Sc::Scene::postIslandGen too)
PxU32 mTmpTriggerPairCount;
PxMutex mTriggerWriteBackLock;
};
typedef PxPool2<ElementInteractionMarker, 4096> ElementInteractionMarkerPool;
typedef PxPool2<ActorPairContactReportData, 4096> ActorPairContactReportDataPool;
typedef PxPool2<TriggerInteraction, 4096> TriggerInteractionPool;
typedef PxPool2<ActorPairReport, 4096> ActorPairReportPool;
typedef PxPool2<ActorPair, 4096> ActorPairPool;
class NPhaseCore : public PxUserAllocated
{
PX_NOCOPY(NPhaseCore)
public:
NPhaseCore(Scene& scene, const PxSceneDesc& desc);
~NPhaseCore();
ElementSimInteraction* findInteraction(const ElementSim* element0, const ElementSim* element1) const;
void onTriggerOverlapCreated(const Bp::AABBOverlap* PX_RESTRICT pairs, PxU32 pairCount);
void runOverlapFilters( PxU32 nbToProcess, Bp::AABBOverlap* PX_RESTRICT pairs, FilterInfo* PX_RESTRICT filterInfo,
PxU32& nbToKeep, PxU32& nbToSuppress) const;
void onOverlapRemoved(ElementSim* volume0, ElementSim* volume1, PxU32 ccdPass, void* elemSim, PxsContactManagerOutputIterator& outputs);
void onVolumeRemoved(ElementSim* volume, PxU32 flags, PxsContactManagerOutputIterator& outputs);
void managerNewTouch(ShapeInteraction& interaction);
PxU32 getDefaultContactReportStreamBufferSize() const;
void fireCustomFilteringCallbacks(PxsContactManagerOutputIterator& outputs);
void addToDirtyInteractionList(Interaction* interaction);
void removeFromDirtyInteractionList(Interaction* interaction);
void updateDirtyInteractions(PxsContactManagerOutputIterator& outputs);
/**
\brief Allocate buffers for trigger overlap test.
See comment in Sc::Scene::postIslandGen for why this is split up into multiple parts.
\param[in] continuation The task to run after trigger processing.
\return The concluding trigger processing task if there is work to do, else NULL.
*/
PxBaseTask* prepareForTriggerInteractionProcessing(PxBaseTask* continuation);
// Perform trigger overlap tests.
void processTriggerInteractions(PxBaseTask& continuation);
// Deactivate trigger interactions if possible, free buffers from overlap tests and clean up.
// See comment in Sc::Scene::postIslandGen for why this is split up into multiple parts.
void concludeTriggerInteractionProcessing(PxBaseTask* continuation);
// Check candidates for persistent touch contact events and create those events if necessary.
void processPersistentContactEvents(PxsContactManagerOutputIterator& outputs);
PX_FORCE_INLINE void addToContactReportActorPairSet(ActorPairReport* pair) { mContactReportActorPairSet.pushBack(pair); }
void clearContactReportActorPairs(bool shrinkToZero);
PX_FORCE_INLINE PxU32 getNbContactReportActorPairs() const { return mContactReportActorPairSet.size(); }
PX_FORCE_INLINE ActorPairReport* const* getContactReportActorPairs() const { return mContactReportActorPairSet.begin(); }
void addToPersistentContactEventPairs(ShapeInteraction*);
void addToPersistentContactEventPairsDelayed(ShapeInteraction*);
void removeFromPersistentContactEventPairs(ShapeInteraction*);
PX_FORCE_INLINE PxU32 getCurrentPersistentContactEventPairCount() const { return mNextFramePersistentContactEventPairIndex; }
PX_FORCE_INLINE ShapeInteraction* const* getCurrentPersistentContactEventPairs() const { return mPersistentContactEventPairList.begin(); }
PX_FORCE_INLINE PxU32 getAllPersistentContactEventPairCount() const { return mPersistentContactEventPairList.size(); }
PX_FORCE_INLINE ShapeInteraction* const* getAllPersistentContactEventPairs() const { return mPersistentContactEventPairList.begin(); }
PX_FORCE_INLINE void preparePersistentContactEventListForNextFrame()
{
// reports have been processed -> "activate" next frame candidates for persistent contact events
mNextFramePersistentContactEventPairIndex = mPersistentContactEventPairList.size();
}
void addToForceThresholdContactEventPairs(ShapeInteraction*);
void removeFromForceThresholdContactEventPairs(ShapeInteraction*);
PX_FORCE_INLINE PxU32 getForceThresholdContactEventPairCount() const { return mForceThresholdContactEventPairList.size(); }
PX_FORCE_INLINE ShapeInteraction* const* getForceThresholdContactEventPairs() const { return mForceThresholdContactEventPairList.begin(); }
PX_FORCE_INLINE PxU8* getContactReportPairData(const PxU32& bufferIndex) const { return mContactReportBuffer.getData(bufferIndex); }
PxU8* reserveContactReportPairData(PxU32 pairCount, PxU32 extraDataSize, PxU32& bufferIndex, ContactReportAllocationManager* alloc = NULL);
PxU8* resizeContactReportPairData(PxU32 pairCount, PxU32 extraDataSize, ContactStreamManager& csm);
PX_FORCE_INLINE void clearContactReportStream() { mContactReportBuffer.reset(); } // Do not free memory at all
PX_FORCE_INLINE void freeContactReportStreamMemory() { mContactReportBuffer.flush(); }
ActorPairContactReportData* createActorPairContactReportData();
void registerInteraction(ElementSimInteraction* interaction);
void unregisterInteraction(ElementSimInteraction* interaction);
ElementSimInteraction* createRbElementInteraction(const FilterInfo& fInfo, ShapeSimBase& s0, ShapeSimBase& s1, PxsContactManager* contactManager, ShapeInteraction* shapeInteraction,
ElementInteractionMarker* interactionMarker, bool isTriggerPair);
PX_FORCE_INLINE void lockReports() { mReportAllocLock.lock(); }
PX_FORCE_INLINE void unlockReports() { mReportAllocLock.unlock(); }
private:
void callPairLost(const ShapeSimBase& s0, const ShapeSimBase& s1, bool objVolumeRemoved);
ElementSimInteraction* createTriggerElementInteraction(ShapeSimBase& s0, ShapeSimBase& s1);
// removedElement: points to the removed element (that is, the BP volume wrapper), if a pair gets removed or loses touch due to a removed element.
// NULL if not triggered by a removed element.
//
void releaseElementPair(ElementSimInteraction* pair, PxU32 flags, ElementSim* removedElement, PxU32 ccdPass, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs);
void lostTouchReports(ShapeInteraction* pair, PxU32 flags, ElementSim* removedElement, PxU32 ccdPass, PxsContactManagerOutputIterator& outputs);
ShapeInteraction* createShapeInteraction(ShapeSimBase& s0, ShapeSimBase& s1, PxPairFlags pairFlags, PxsContactManager* contactManager, ShapeInteraction* shapeInteraction);
TriggerInteraction* createTriggerInteraction(ShapeSimBase& s0, ShapeSimBase& s1, PxPairFlags triggerFlags);
ElementInteractionMarker* createElementInteractionMarker(ElementSim& e0, ElementSim& e1, ElementInteractionMarker* marker);
//------------- Filtering -------------
ElementSimInteraction* refilterInteraction(ElementSimInteraction* pair, const FilterInfo* filterInfo, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs);
//-------------------------------------
ElementSimInteraction* convert(ElementSimInteraction* pair, InteractionType::Enum type, FilterInfo& filterInfo, bool removeFromDirtyList, PxsContactManagerOutputIterator& outputs);
ActorPair* findActorPair(ShapeSimBase* s0, ShapeSimBase* s1, PxIntBool isReportPair);
// Pooling
Scene& mOwnerScene;
PxArray<ActorPairReport*> mContactReportActorPairSet;
PxArray<ShapeInteraction*> mPersistentContactEventPairList; // Pairs which request events which do not get triggered by the sdk and thus need to be tested actively every frame.
// May also contain force threshold event pairs (see mForceThresholdContactEventPairList)
// This list is split in two, the elements in front are for the current frame, the elements at the
// back will get added next frame.
PxU32 mNextFramePersistentContactEventPairIndex; // start index of the pairs which need to get added to the persistent list for next frame
PxArray<ShapeInteraction*> mForceThresholdContactEventPairList; // Pairs which request force threshold contact events. A pair is only in this list if it does have contact.
// Note: If a pair additionally requests PxPairFlag::eNOTIFY_TOUCH_PERSISTS events, then it
// goes into mPersistentContactEventPairList instead. This allows to share the list index.
// data layout:
// ContactActorPair0_ExtraData, ContactShapePair0_0, ContactShapePair0_1, ... ContactShapePair0_N,
// ContactActorPair1_ExtraData, ContactShapePair1_0, ...
//
ContactReportBuffer mContactReportBuffer; // Shape pair information for contact reports
PxCoalescedHashSet<Interaction*> mDirtyInteractions;
// Pools
ActorPairPool mActorPairPool;
ActorPairReportPool mActorPairReportPool;
PxPool<ShapeInteraction> mShapeInteractionPool;
TriggerInteractionPool mTriggerInteractionPool;
ActorPairContactReportDataPool mActorPairContactReportDataPool;
ElementInteractionMarkerPool mInteractionMarkerPool;
Cm::DelegateTask<NPhaseCore, &NPhaseCore::concludeTriggerInteractionProcessing> mConcludeTriggerInteractionProcessingTask;
TriggerProcessingContext mTriggerProcessingContext;
PxHashMap<BodyPairKey, ActorPair*> mActorPairMap;
PxHashMap<ElementSimKey, ElementSimInteraction*> mElementSimMap;
PxMutex mBufferAllocLock;
PxMutex mReportAllocLock;
friend class Sc::Scene;
friend class Sc::ShapeInteraction;
};
struct FilteringContext
{
PX_NOCOPY(FilteringContext)
public:
FilteringContext(const Scene& scene) :
mFilterShader (scene.getFilterShaderFast()),
mFilterShaderData (scene.getFilterShaderDataFast()),
mFilterShaderDataSize (scene.getFilterShaderDataSizeFast()),
mFilterCallback (scene.getFilterCallbackFast()),
mKineKineFilteringMode (scene.getKineKineFilteringMode()),
mStaticKineFilteringMode(scene.getStaticKineFilteringMode()),
mIsDirectGPU (scene.getFlags() & PxSceneFlag::eENABLE_DIRECT_GPU_API)
{
}
PxSimulationFilterShader mFilterShader;
const void* mFilterShaderData;
PxU32 mFilterShaderDataSize;
PxSimulationFilterCallback* mFilterCallback;
const PxPairFilteringMode::Enum mKineKineFilteringMode;
const PxPairFilteringMode::Enum mStaticKineFilteringMode;
const bool mIsDirectGPU;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,100 @@
// 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_OBJECT_ID_TRACKER_H
#define SC_OBJECT_ID_TRACKER_H
#include "CmIDPool.h"
#include "foundation/PxBitMap.h"
#include "foundation/PxUserAllocated.h"
namespace physx
{
namespace Sc
{
// PT: TODO: this has no direct dependency on "Sc". It should really be a "Cm" class.
class ObjectIDTracker : public PxUserAllocated
{
PX_NOCOPY(ObjectIDTracker)
public:
ObjectIDTracker() : mPendingReleasedIDs("objectIDTrackerIDs") {}
PX_INLINE PxU32 createID() { return mIDPool.getNewID(); }
PX_INLINE void releaseID(PxU32 id)
{
markIDAsDeleted(id);
mPendingReleasedIDs.pushBack(id);
}
PX_INLINE PxIntBool isDeletedID(PxU32 id) const { return mDeletedIDsMap.boundedTest(id); }
PX_FORCE_INLINE PxU32 getDeletedIDCount() const { return mPendingReleasedIDs.size(); }
PX_INLINE void clearDeletedIDMap() { mDeletedIDsMap.clear(); }
PX_INLINE void resizeDeletedIDMap(PxU32 id, PxU32 numIds)
{
mDeletedIDsMap.resize(id);
mPendingReleasedIDs.reserve(numIds);
}
PX_INLINE void processPendingReleases()
{
for(PxU32 i=0; i < mPendingReleasedIDs.size(); i++)
mIDPool.freeID(mPendingReleasedIDs[i]);
mPendingReleasedIDs.clear();
}
PX_INLINE void reset()
{
processPendingReleases();
mPendingReleasedIDs.reset();
// Don't free stuff in IDPool, we still need the list of free IDs
// And it does not seem worth freeing the memory of the bitmap
}
PX_INLINE PxU32 getMaxID() const
{
return mIDPool.getMaxID();
}
private:
PX_INLINE void markIDAsDeleted(PxU32 id)
{
PX_ASSERT(!isDeletedID(id));
mDeletedIDsMap.growAndSet(id);
}
Cm::IDPool mIDPool;
PxBitMap mDeletedIDsMap;
PxArray<PxU32> mPendingReleasedIDs; // Buffer for released IDs to make sure newly created objects do not re-use these IDs immediately
};
}
}
#endif

View File

@@ -0,0 +1,268 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScParticleSystemCore.h"
#include "ScPhysics.h"
#include "ScParticleSystemSim.h"
#include "DyParticleSystem.h"
#include "PxvGlobals.h"
#include "PxPhysXGpu.h"
using namespace physx;
Sc::ParticleSystemCore::ParticleSystemCore(PxActorType::Enum actorType) :
ActorCore(actorType, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0)
{
}
Sc::ParticleSystemCore::~ParticleSystemCore()
{
}
Sc::ParticleSystemSim* Sc::ParticleSystemCore::getSim() const
{
return static_cast<ParticleSystemSim*>(ActorCore::getSim());
}
PxReal Sc::ParticleSystemCore::getSleepThreshold() const
{
return mShapeCore.getLLCore().sleepThreshold;//mCore.sleepThreshold;
}
void Sc::ParticleSystemCore::setSleepThreshold(const PxReal v)
{
mShapeCore.getLLCore().sleepThreshold = v;
}
PxReal Sc::ParticleSystemCore::getRestOffset() const
{
return mShapeCore.getLLCore().restOffset;
}
void Sc::ParticleSystemCore::setRestOffset(const PxReal v)
{
mShapeCore.getLLCore().restOffset = v;
}
PxReal Sc::ParticleSystemCore::getContactOffset() const
{
return mShapeCore.getContactOffset();
}
void Sc::ParticleSystemCore::setContactOffset(const PxReal v)
{
mShapeCore.setContactOffset(v);
Sc::ParticleSystemSim* sim = getSim();
if (sim)
{
sim->getScene().updateContactDistance(sim->getShapeSim().getElementID(), v);
}
}
PxReal Sc::ParticleSystemCore::getParticleContactOffset() const
{
return mShapeCore.getLLCore().particleContactOffset;
}
void Sc::ParticleSystemCore::setParticleContactOffset(const PxReal v)
{
mShapeCore.getLLCore().particleContactOffset = v;
}
PxReal Sc::ParticleSystemCore::getSolidRestOffset() const
{
return mShapeCore.getLLCore().solidRestOffset;
}
void Sc::ParticleSystemCore::setSolidRestOffset(const PxReal v)
{
mShapeCore.getLLCore().solidRestOffset = v;
}
PxReal Sc::ParticleSystemCore::getFluidRestOffset() const
{
return mShapeCore.getLLCore().fluidRestOffset;
}
void Sc::ParticleSystemCore::setFluidRestOffset(const PxReal v)
{
mShapeCore.getLLCore().fluidRestOffset = v;
}
void Sc::ParticleSystemCore::setMaxDepenetrationVelocity(const PxReal v)
{
mShapeCore.getLLCore().maxDepenetrationVelocity = v;
}
PxReal Sc::ParticleSystemCore::getMaxDepenetrationVelocity() const
{
return mShapeCore.getLLCore().maxDepenetrationVelocity;
}
void Sc::ParticleSystemCore::setMaxVelocity(const PxReal v)
{
mShapeCore.getLLCore().maxVelocity = v;
}
PxReal Sc::ParticleSystemCore::getMaxVelocity() const
{
return mShapeCore.getLLCore().maxVelocity;
}
PxParticleSystemCallback* Sc::ParticleSystemCore::getParticleSystemCallback() const
{
return mShapeCore.getLLCore().mCallback;
}
void Sc::ParticleSystemCore::setParticleSystemCallback(PxParticleSystemCallback* callback)
{
mShapeCore.getLLCore().mCallback = callback;
}
PxReal Sc::ParticleSystemCore::getFluidBoundaryDensityScale() const
{
return mShapeCore.getLLCore().fluidBoundaryDensityScale;
}
void Sc::ParticleSystemCore::setFluidBoundaryDensityScale(const PxReal v)
{
mShapeCore.getLLCore().fluidBoundaryDensityScale = v;
}
PxU32 Sc::ParticleSystemCore::getGridSizeX() const
{
return mShapeCore.getLLCore().gridSizeX;
}
void Sc::ParticleSystemCore::setGridSizeX(const PxU32 v)
{
mShapeCore.getLLCore().gridSizeX = v;
}
PxU32 Sc::ParticleSystemCore::getGridSizeY() const
{
return mShapeCore.getLLCore().gridSizeY;
}
void Sc::ParticleSystemCore::setGridSizeY(const PxU32 v)
{
mShapeCore.getLLCore().gridSizeY = v;
}
PxU32 Sc::ParticleSystemCore::getGridSizeZ() const
{
return mShapeCore.getLLCore().gridSizeZ;
}
void Sc::ParticleSystemCore::setGridSizeZ(const PxU32 v)
{
mShapeCore.getLLCore().gridSizeZ = v;
}
void Sc::ParticleSystemCore::setSolverIterationCounts(PxU16 c)
{
mShapeCore.getLLCore().solverIterationCounts = c;
}
PxReal Sc::ParticleSystemCore::getWakeCounter() const
{
return mShapeCore.getLLCore().wakeCounter;
}
void Sc::ParticleSystemCore::setWakeCounter(const PxReal v)
{
mShapeCore.getLLCore().wakeCounter = v;
}
void Sc::ParticleSystemCore::setWakeCounterInternal(const PxReal v)
{
mShapeCore.getLLCore().wakeCounter = v;
}
bool Sc::ParticleSystemCore::isSleeping() const
{
Sc::ParticleSystemSim* sim = getSim();
return sim ? sim->isSleeping() : (mShapeCore.getLLCore().wakeCounter == 0.0f);
}
void Sc::ParticleSystemCore::wakeUp(PxReal wakeCounter)
{
mShapeCore.getLLCore().wakeCounter = wakeCounter;
}
void Sc::ParticleSystemCore::putToSleep()
{
mShapeCore.getLLCore().wakeCounter = 0.0f;
}
PxActor* Sc::ParticleSystemCore::getPxActor() const
{
return PxPointerOffset<PxActor*>(const_cast<ParticleSystemCore*>(this), gOffsetTable.scCore2PxActor[getActorCoreType()]);
}
void Sc::ParticleSystemCore::addRigidAttachment(Sc::BodyCore* core)
{
Sc::ParticleSystemSim* sim = getSim();
if(sim)
sim->getScene().addRigidAttachment(core, *sim);
}
void Sc::ParticleSystemCore::removeRigidAttachment(Sc::BodyCore* core)
{
Sc::ParticleSystemSim* sim = getSim();
if (sim)
sim->getScene().removeRigidAttachment(core, *sim);
}
void Sc::ParticleSystemCore::setFlags(PxParticleFlags flags)
{
Sc::ParticleSystemSim* sim = getSim();
PxParticleFlags oldFlags = mShapeCore.getLLCore().mFlags;
mShapeCore.getLLCore().mFlags = flags;
if (sim)
{
bool wasRigidCollisionDisabled = oldFlags & PxParticleFlag::eDISABLE_RIGID_COLLISION;
bool isRigidCollisionDisabled = flags & PxParticleFlag::eDISABLE_RIGID_COLLISION;
if (wasRigidCollisionDisabled ^ isRigidCollisionDisabled)
{
if (wasRigidCollisionDisabled)
sim->createLowLevelVolume();
else
sim->destroyLowLevelVolume();
}
}
}
#endif //PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,118 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "foundation/PxErrorCallback.h"
#include "ScParticleSystemShapeCore.h"
#include "ScPhysics.h"
#include "PxvGlobals.h"
#include "PxPhysXGpu.h"
#include "cudamanager/PxCudaContextManager.h"
#include "CmVisualization.h"
using namespace physx;
using namespace Sc;
ParticleSystemShapeCore::ParticleSystemShapeCore()
: ShapeCore(PxEmpty)
, mGpuMemStat(0)
{
mSimulationFilterData = PxFilterData();
mCore = PxsShapeCore();
mCore.mShapeCoreFlags |= PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY;
const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale();
mCore.setTransform(PxTransform(PxIdentity));
mCore.mContactOffset = 0.01f * scale.length;
mCore.mShapeFlags = 0;
mCore.mMaterialIndex = 0;
mCore.mMinTorsionalPatchRadius = 0.f;
mCore.mTorsionalRadius = 0.f;
mLLCore.sleepThreshold = 5e-5f * scale.speed * scale.speed;
mLLCore.wakeCounter = Physics::sWakeCounterOnCreation;
mLLCore.freezeThreshold = 5e-6f * scale.speed * scale.speed;
//TODO, make this dependend on scale?
//also set contact offset accordingly
mLLCore.restOffset = 0.1f;
const PxReal contactOffset = mLLCore.restOffset + 0.001f;
setContactOffset(contactOffset);
mLLCore.particleContactOffset = contactOffset;
mLLCore.solidRestOffset = mLLCore.restOffset;
mLLCore.fluidRestOffset = mLLCore.restOffset * 0.6f;
mLLCore.particleContactOffset_prev = FLT_MIN;
mLLCore.fluidRestOffset_prev = FLT_MIN;
mLLCore.fluidBoundaryDensityScale = 0.0f;
mLLCore.gridSizeX = 128;
mLLCore.gridSizeY = 128;
mLLCore.gridSizeZ = 128;
mLLCore.mFlags = PxParticleFlags(0);
mLLCore.mLockFlags = PxParticleLockFlags(0);
mLLCore.solverIterationCounts = (1 << 8) | 4;
mLLCore.mWind = PxVec3(0.f);
// Sparse grid specific
mLLCore.sparseGridParams.setToDefault();
mLLCore.sparseGridParams.gridSpacing = 2.0f * mLLCore.particleContactOffset;
}
// PX_SERIALIZATION
ParticleSystemShapeCore::ParticleSystemShapeCore(const PxEMPTY)
: ShapeCore(PxEmpty)
{
}
ParticleSystemShapeCore::~ParticleSystemShapeCore()
{
}
void ParticleSystemShapeCore::initializeLLCoreData(PxU32 maxNeighborhood, PxReal neighborhoodScale)
{
const PxTolerancesScale& scale = Sc::Physics::getInstance().getTolerancesScale();
mLLCore.mMaxNeighborhood = maxNeighborhood;
mLLCore.mNeighborhoodScale = neighborhoodScale;
mLLCore.maxDepenetrationVelocity = 50.f * scale.length;
mLLCore.maxVelocity = 1e+6f;
}
#endif // PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,76 @@
// 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.
#ifndef SC_PARTICLESYSTEM_SHAPECORE_H
#define SC_PARTICLESYSTEM_SHAPECORE_H
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "foundation/PxUserAllocated.h"
#include "PxvGeometry.h"
#include "foundation/PxUtilities.h"
#include "PxFiltering.h"
#include "PxShape.h"
#include "ScShapeCore.h"
#include "DyParticleSystemCore.h"
#include "common/PxRenderOutput.h"
namespace physx
{
namespace Sc
{
class Scene;
class ParticleSystemCore;
class ParticleSystemSim;
class ParticleSystemShapeCore : public Sc::ShapeCore
{
public:
// PX_SERIALIZATION
ParticleSystemShapeCore(const PxEMPTY);
//~PX_SERIALIZATION
ParticleSystemShapeCore();
~ParticleSystemShapeCore();
PX_FORCE_INLINE const Dy::ParticleSystemCore& getLLCore() const { return mLLCore; }
PX_FORCE_INLINE Dy::ParticleSystemCore& getLLCore() { return mLLCore; }
void initializeLLCoreData(PxU32 maxNeighborhood, PxReal neighborhoodScale);
PxU64 getGpuMemStat() { return mGpuMemStat; }
protected:
Dy::ParticleSystemCore mLLCore;
PxU64 mGpuMemStat;
};
} // namespace Sc
}
#endif
#endif

View File

@@ -0,0 +1,109 @@
// 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.
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScParticleSystemSim.h"
using namespace physx;
using namespace Dy;
Sc::ParticleSystemSim::ParticleSystemSim(ParticleSystemCore& core, Scene& scene) :
GPUActorSim(scene, core, &core.getShapeCore())
{
createLowLevelVolume();
mLLParticleSystem = scene.createLLParticleSystem(this);
mNodeIndex = scene.getSimpleIslandManager()->addNode(false, false, IG::Node::ePARTICLESYSTEM_TYPE, mLLParticleSystem);
scene.getSimpleIslandManager()->activateNode(mNodeIndex);
//mCore.setSim(this);
mLLParticleSystem->setElementId(mShapeSim.getElementID());
PxParticleSystemGeometry geometry;
geometry.mSolverType = PxParticleSolverType::ePBD;
core.getShapeCore().setGeometry(geometry);
PxsShapeCore* shapeCore = const_cast<PxsShapeCore*>(&core.getShapeCore().getCore());
mLLParticleSystem->setShapeCore(shapeCore);
}
Sc::ParticleSystemSim::~ParticleSystemSim()
{
if (!mLLParticleSystem)
return;
mScene.destroyLLParticleSystem(*mLLParticleSystem);
mScene.getSimpleIslandManager()->removeNode(mNodeIndex);
mCore.setSim(NULL);
}
void Sc::ParticleSystemSim::createLowLevelVolume()
{
//PX_ASSERT(getWorldBounds().isFinite());
const PxU32 index = mShapeSim.getElementID();
if (!(static_cast<Sc::ParticleSystemSim&>(mShapeSim.getActor()).getCore().getFlags() & PxParticleFlag::eDISABLE_RIGID_COLLISION))
{
mScene.getBoundsArray().setBounds(PxBounds3(PxVec3(PX_MAX_BOUNDS_EXTENTS), PxVec3(-PX_MAX_BOUNDS_EXTENTS)), index);
mShapeSim.setInBroadPhase();
}
else
mScene.getAABBManager()->reserveSpaceForBounds(index);
addToAABBMgr(Bp::FilterType::PARTICLESYSTEM);
}
bool Sc::ParticleSystemSim::isSleeping() const
{
return false;
}
void Sc::ParticleSystemSim::sleepCheck(PxReal dt)
{
PX_UNUSED(dt);
}
/*void Sc::ParticleSystemSim::activate()
{
activateInteractions(*this);
}
void Sc::ParticleSystemSim::deactivate()
{
deactivateInteractions(*this);
}*/
#endif //PX_SUPPORT_GPU_PHYSX

View File

@@ -0,0 +1,74 @@
// 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.
#ifndef SC_PARTICLESYSTEM_SIM_H
#define SC_PARTICLESYSTEM_SIM_H
#include "foundation/PxPreprocessor.h"
#if PX_SUPPORT_GPU_PHYSX
#include "foundation/PxUserAllocated.h"
#include "ScGpuActorSim.h"
#include "ScParticleSystemCore.h"
namespace physx
{
namespace Sc
{
class Scene;
class ParticleSystemSim : public GPUActorSim
{
PX_NOCOPY(ParticleSystemSim)
public:
ParticleSystemSim(ParticleSystemCore& core, Scene& scene);
~ParticleSystemSim();
PX_INLINE Dy::ParticleSystem* getLowLevelParticleSystem() const { return mLLParticleSystem; }
PX_INLINE ParticleSystemCore& getCore() const { return static_cast<ParticleSystemCore&>(mCore); }
virtual PxActor* getPxActor() const { return getCore().getPxActor(); }
bool isSleeping() const;
bool isActive() const { return true; }
void sleepCheck(PxReal dt);
void setActive(bool active, bool asPartOfCreation=false);
void createLowLevelVolume();
private:
Dy::ParticleSystem* mLLParticleSystem;
// PT: as far as I can tell these are never actually called
// void activate();
// void deactivate();
};
} // namespace Sc
}
#endif
#endif

View File

@@ -0,0 +1,59 @@
// 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.
#include "common/PxTolerancesScale.h"
#include "ScPhysics.h"
#include "ScScene.h"
#include "PxvGlobals.h"
using namespace physx;
Sc::Physics* Sc::Physics::mInstance = NULL;
const PxReal Sc::Physics::sWakeCounterOnCreation = 20.0f*0.02f;
namespace physx
{
namespace Sc
{
OffsetTable gOffsetTable;
}
}
Sc::Physics::Physics(const PxTolerancesScale& scale, const PxvOffsetTable& pxvOffsetTable) : mScale(scale)
{
mInstance = this;
PxvInit(pxvOffsetTable);
}
Sc::Physics::~Physics()
{
PxvTerm();
mInstance = NULL;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,167 @@
// 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.
#include "ScRigidCore.h"
#include "ScRigidSim.h"
#include "ScShapeSim.h"
#include "ScScene.h"
using namespace physx;
using namespace Sc;
PX_IMPLEMENT_OUTPUT_ERROR
static ShapeSim* getSimForShape(const ShapeCore& core, const ActorSim& actorSim)
{
if(core.getExclusiveSim())
{
return core.getExclusiveSim();
}
//Must be a shared shape.
//Search backwards to emulate the behaviour of the previous linked list.
PxU32 nbElems = actorSim.getNbElements();
ElementSim*const* elems = actorSim.getElements() + (nbElems - 1);
while (nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems--);
if (&sim->getCore() == &core)
return sim;
}
// Defensive coding added for OM-118444.
// Switched this function to return a pointer rather than a reference.
// This allows callers to avoid a crash in case the ShapeSim is not found.
// The original use of a reference implies that this should never happen yet the crash in this ticket suggests that it's possible.
// We could/should revert this eventually and remove the checks for NULL pointers in all callers in this file.
// ### DEFENSIVE
outputError<PxErrorCode::eINTERNAL_ERROR>(__LINE__, "ScRigidCore::getSimForShape: ShapeSim not found!");
PX_ASSERT(0); // should never fail
return NULL;
}
RigidCore::RigidCore(const PxActorType::Enum type) : ActorCore(type, PxActorFlag::eVISUALIZATION, PX_DEFAULT_CLIENT, 0)
{
}
RigidCore::~RigidCore()
{
}
void RigidCore::addShapeToScene(ShapeCore& shapeCore)
{
RigidSim* sim = getSim();
PX_ASSERT(sim);
if(!sim)
return;
sim->getScene().addShape_(*sim, shapeCore);
}
void RigidCore::removeShapeFromScene(ShapeCore& shapeCore, bool wakeOnLostTouch)
{
RigidSim* sim = getSim();
if(!sim)
return;
ShapeSim* s = getSimForShape(shapeCore, *sim);
if(s)
sim->getScene().removeShape_(*s, wakeOnLostTouch);
}
void RigidCore::unregisterShapeFromNphase(Sc::ShapeCore& shapeCore)
{
RigidSim* sim = getSim();
if (!sim)
return;
ShapeSim* s = getSimForShape(shapeCore, *sim);
if(s)
s->getScene().unregisterShapeFromNphase(shapeCore, s->getElementID());
}
void RigidCore::registerShapeInNphase(Sc::ShapeCore& shapeCore)
{
RigidSim* sim = getSim();
if (!sim)
return;
ShapeSim* s = getSimForShape(shapeCore, *sim);
if(s)
s->getScene().registerShapeInNphase(this, shapeCore, s->getElementID());
}
void RigidCore::onShapeChange(ShapeCore& shape, ShapeChangeNotifyFlags notifyFlags)
{
RigidSim* sim = getSim();
if(!sim)
return;
ShapeSim* s = getSimForShape(shape, *sim);
if(!s)
return;
if(notifyFlags & ShapeChangeNotifyFlag::eGEOMETRY)
s->onVolumeOrTransformChange();
if(notifyFlags & ShapeChangeNotifyFlag::eRESET_FILTERING)
s->onResetFiltering();
if(notifyFlags & ShapeChangeNotifyFlag::eSHAPE2BODY)
s->onVolumeOrTransformChange();
if(notifyFlags & ShapeChangeNotifyFlag::eFILTERDATA)
s->onFilterDataChange();
if(notifyFlags & ShapeChangeNotifyFlag::eCONTACTOFFSET)
s->onContactOffsetChange();
if(notifyFlags & ShapeChangeNotifyFlag::eRESTOFFSET)
s->onRestOffsetChange();
}
void RigidCore::onShapeFlagsChange(ShapeCore& shape, PxShapeFlags oldShapeFlags)
{
// DS: We pass flags to avoid searching multiple times or exposing RigidSim outside SC.
//If we start hitting this a lot we should do it
// a different way, but shape modification after insertion is rare.
RigidSim* sim = getSim();
if(!sim)
return;
ShapeSim* s = getSimForShape(shape, *sim);
if(s)
s->onFlagChange(oldShapeFlags);
}
RigidSim* RigidCore::getSim() const
{
return static_cast<RigidSim*>(ActorCore::getSim());
}
PxU32 RigidCore::getRigidID() const
{
return static_cast<RigidSim*>(ActorCore::getSim())->getActorID();
}

View File

@@ -0,0 +1,71 @@
// 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.
#include "ScScene.h"
#include "ScRigidSim.h"
#include "ScShapeSim.h"
#include "PxsSimulationController.h"
using namespace physx;
using namespace Sc;
/*
PT:
The BP group ID comes from a Cm::IDPool, and ActorSim is the only class releasing the ID.
The rigid tracker ID comes from a Cm::IDPool internal to an ObjectIDTracker, and ActorSim
is the only class using it.
Thus we should:
- promote the BP group ID stuff to a "tracker" object
- use the BP group ID as a rigid ID
*/
RigidSim::RigidSim(Scene& scene, RigidCore& core) : ActorSim(scene, core)
{
}
RigidSim::~RigidSim()
{
}
void notifyActorInteractionsOfTransformChange(ActorSim& actor);
void RigidSim::notifyShapesOfTransformChange()
{
PxU32 nbElems = getNbElements();
ElementSim** elems = getElements();
while (nbElems--)
{
ShapeSim* sim = static_cast<ShapeSim*>(*elems++);
sim->markBoundsForUpdate();
}
notifyActorInteractionsOfTransformChange(*this);
}

View File

@@ -0,0 +1,58 @@
// 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_RIGID_SIM_H
#define SC_RIGID_SIM_H
#include "ScActorSim.h"
#include "ScRigidCore.h"
namespace physx
{
namespace Sc
{
class Scene;
class RigidSim : public ActorSim
{
public:
RigidSim(Scene&, RigidCore&);
virtual ~RigidSim();
PX_FORCE_INLINE RigidCore& getRigidCore() const { return static_cast<RigidCore&>(mCore); }
void notifyShapesOfTransformChange();
virtual PxActor* getPxActor() const { return getRigidCore().getPxActor(); }
};
} // namespace Sc
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,400 @@
// 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.
#include "foundation/PxErrorCallback.h"
#include "ScShapeSim.h"
#include "ScPhysics.h"
#include "GuConvexMesh.h"
#include "GuTriangleMesh.h"
#include "GuHeightField.h"
#include "GuTetrahedronMesh.h"
using namespace physx;
using namespace Gu;
using namespace Cm;
using namespace Sc;
static PX_FORCE_INLINE Gu::ConvexMesh& getConvexMesh(PxConvexMesh* pxcm)
{
return *static_cast<Gu::ConvexMesh*>(pxcm);
}
// PT: TODO: optimize all these data copies
void GeometryUnion::set(const PxGeometry& g)
{
// PT: preserve this field that can be used by higher-level code to store useful data
const float saved = reinterpret_cast<const PxGeometry&>(mGeometry).mTypePadding;
switch(g.getType())
{
case PxGeometryType::eBOX:
{
reinterpret_cast<PxBoxGeometry&>(mGeometry) = static_cast<const PxBoxGeometry&>(g);
}
break;
case PxGeometryType::eCAPSULE:
{
reinterpret_cast<PxCapsuleGeometry&>(mGeometry) = static_cast<const PxCapsuleGeometry&>(g);
}
break;
case PxGeometryType::eSPHERE:
{
reinterpret_cast<PxSphereGeometry&>(mGeometry) = static_cast<const PxSphereGeometry&>(g);
reinterpret_cast<PxCapsuleGeometry&>(mGeometry).halfHeight = 0.0f; //AM: make sphere geometry also castable as a zero height capsule.
}
break;
case PxGeometryType::ePLANE:
{
reinterpret_cast<PxPlaneGeometry&>(mGeometry) = static_cast<const PxPlaneGeometry&>(g);
}
break;
case PxGeometryType::eCONVEXCORE:
{
reinterpret_cast<PxConvexCoreGeometry&>(mGeometry) = static_cast<const PxConvexCoreGeometry&>(g);
}
break;
case PxGeometryType::eCONVEXMESH:
{
reinterpret_cast<PxConvexMeshGeometry&>(mGeometry) = static_cast<const PxConvexMeshGeometry&>(g);
reinterpret_cast<PxConvexMeshGeometryLL&>(mGeometry).gpuCompatible = ::getConvexMesh(get<PxConvexMeshGeometryLL>().convexMesh).isGpuCompatible();
}
break;
case PxGeometryType::ePARTICLESYSTEM:
{
reinterpret_cast<PxParticleSystemGeometry&>(mGeometry) = static_cast<const PxParticleSystemGeometry&>(g);
reinterpret_cast<PxParticleSystemGeometryLL&>(mGeometry).materialsLL = MaterialIndicesStruct();
}
break;
case PxGeometryType::eTRIANGLEMESH:
{
reinterpret_cast<PxTriangleMeshGeometry&>(mGeometry) = static_cast<const PxTriangleMeshGeometry&>(g);
reinterpret_cast<PxTriangleMeshGeometryLL&>(mGeometry).materialsLL = MaterialIndicesStruct();
}
break;
case PxGeometryType::eTETRAHEDRONMESH:
{
reinterpret_cast<PxTetrahedronMeshGeometry&>(mGeometry) = static_cast<const PxTetrahedronMeshGeometry&>(g);
reinterpret_cast<PxTetrahedronMeshGeometryLL&>(mGeometry).materialsLL = MaterialIndicesStruct();
}
break;
case PxGeometryType::eHEIGHTFIELD:
{
reinterpret_cast<PxHeightFieldGeometry&>(mGeometry) = static_cast<const PxHeightFieldGeometry&>(g);
reinterpret_cast<PxHeightFieldGeometryLL&>(mGeometry).materialsLL = MaterialIndicesStruct();
}
break;
case PxGeometryType::eCUSTOM:
{
reinterpret_cast<PxCustomGeometry&>(mGeometry) = static_cast<const PxCustomGeometry&>(g);
}
break;
case PxGeometryType::eGEOMETRY_COUNT:
case PxGeometryType::eINVALID:
PX_ALWAYS_ASSERT_MESSAGE("geometry type not handled");
break;
}
reinterpret_cast<PxGeometry&>(mGeometry).mTypePadding = saved;
}
static PxConvexMeshGeometryLL extendForLL(const PxConvexMeshGeometry& hlGeom)
{
PxConvexMeshGeometryLL llGeom;
static_cast<PxConvexMeshGeometry&>(llGeom) = hlGeom;
llGeom.gpuCompatible = hlGeom.convexMesh->isGpuCompatible();
return llGeom;
}
static PxTriangleMeshGeometryLL extendForLL(const PxTriangleMeshGeometry& hlGeom)
{
PxTriangleMeshGeometryLL llGeom;
static_cast<PxTriangleMeshGeometry&>(llGeom) = hlGeom;
llGeom.materialsLL = static_cast<const PxTriangleMeshGeometryLL&>(hlGeom).materialsLL;
return llGeom;
}
static PxHeightFieldGeometryLL extendForLL(const PxHeightFieldGeometry& hlGeom)
{
PxHeightFieldGeometryLL llGeom;
static_cast<PxHeightFieldGeometry&>(llGeom) = hlGeom;
llGeom.materialsLL = static_cast<const PxHeightFieldGeometryLL&>(hlGeom).materialsLL;
return llGeom;
}
ShapeCore::ShapeCore(const PxGeometry& geometry, PxShapeFlags shapeFlags, const PxU16* materialIndices, PxU16 materialCount, bool isExclusive, PxShapeCoreFlag::Enum coreFlags) :
mExclusiveSim(NULL)
{
mCore.mShapeCoreFlags |= PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY;
if(isExclusive)
mCore.mShapeCoreFlags |= PxShapeCoreFlag::eIS_EXCLUSIVE;
mCore.mShapeCoreFlags |= coreFlags;
PX_ASSERT(materialCount > 0);
const PxTolerancesScale& scale = Physics::getInstance().getTolerancesScale();
mCore.mGeometry.set(geometry);
mCore.setTransform(PxTransform(PxIdentity));
mCore.mContactOffset = 0.02f * scale.length;
mCore.mRestOffset = 0.0f;
mCore.mTorsionalRadius = 0.0f;
mCore.mMinTorsionalPatchRadius = 0.0f;
mCore.mShapeFlags = shapeFlags;
setMaterialIndices(materialIndices, materialCount);
}
// PX_SERIALIZATION
ShapeCore::ShapeCore(const PxEMPTY) :
mSimulationFilterData (PxEmpty),
mCore (PxEmpty),
mExclusiveSim (NULL)
{
mCore.mShapeCoreFlags.clear(PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY);
}
//~PX_SERIALIZATION
static PX_FORCE_INLINE const MaterialIndicesStruct* getMaterials(const GeometryUnion& gu)
{
const PxGeometryType::Enum type = gu.getType();
if(type == PxGeometryType::eTRIANGLEMESH)
return &gu.get<PxTriangleMeshGeometryLL>().materialsLL;
else if(type == PxGeometryType::eHEIGHTFIELD)
return &gu.get<PxHeightFieldGeometryLL>().materialsLL;
else if(type == PxGeometryType::eTETRAHEDRONMESH)
return &gu.get<PxTetrahedronMeshGeometryLL>().materialsLL;
else if(type == PxGeometryType::ePARTICLESYSTEM)
return &gu.get<PxParticleSystemGeometryLL>().materialsLL;
else
return NULL;
}
ShapeCore::~ShapeCore()
{
if(mCore.mShapeCoreFlags.isSet(PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY))
{
MaterialIndicesStruct* materialsLL = const_cast<MaterialIndicesStruct*>(getMaterials(mCore.mGeometry));
if(materialsLL)
materialsLL->deallocate();
}
}
PxU16 Sc::ShapeCore::getNbMaterialIndices() const
{
const MaterialIndicesStruct* materialsLL = getMaterials(mCore.mGeometry);
return materialsLL ? materialsLL->numIndices : 1;
}
const PxU16* Sc::ShapeCore::getMaterialIndices() const
{
const MaterialIndicesStruct* materialsLL = getMaterials(mCore.mGeometry);
return materialsLL ? materialsLL->indices : &mCore.mMaterialIndex;
}
PX_FORCE_INLINE void setMaterialsHelper(MaterialIndicesStruct& materials, const PxU16* materialIndices, PxU16 materialIndexCount, PxShapeCoreFlags& shapeCoreFlags)
{
if(materials.numIndices < materialIndexCount)
{
if(materials.indices && shapeCoreFlags.isSet(PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY))
materials.deallocate();
materials.allocate(materialIndexCount);
shapeCoreFlags |= PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY;
}
PxMemCopy(materials.indices, materialIndices, sizeof(PxU16)*materialIndexCount);
materials.numIndices = materialIndexCount;
}
void ShapeCore::setMaterialIndices(const PxU16* materialIndices, PxU16 materialIndexCount)
{
mCore.mMaterialIndex = materialIndices[0];
MaterialIndicesStruct* materialsLL = const_cast<MaterialIndicesStruct*>(getMaterials(mCore.mGeometry));
if(materialsLL)
setMaterialsHelper(*materialsLL, materialIndices, materialIndexCount, mCore.mShapeCoreFlags);
}
void ShapeCore::setGeometry(const PxGeometry& geom)
{
const PxGeometryType::Enum newGeomType = geom.getType();
// copy material related data to restore it after the new geometry has been set
MaterialIndicesStruct materials;
PX_ASSERT(materials.numIndices == 0);
const MaterialIndicesStruct* materialsLL = getMaterials(mCore.mGeometry);
if(materialsLL)
materials = *materialsLL;
mCore.mGeometry.set(geom);
if((newGeomType == PxGeometryType::eTRIANGLEMESH) || (newGeomType == PxGeometryType::eHEIGHTFIELD)
|| (newGeomType == PxGeometryType::eTETRAHEDRONMESH)|| (newGeomType == PxGeometryType::ePARTICLESYSTEM))
{
MaterialIndicesStruct* newMaterials = const_cast<MaterialIndicesStruct*>(getMaterials(mCore.mGeometry));
PX_ASSERT(newMaterials);
if(materials.numIndices != 0) // old type was mesh type
*newMaterials = materials;
else
{ // old type was non-mesh type
newMaterials->allocate(1);
*newMaterials->indices = mCore.mMaterialIndex;
mCore.mShapeCoreFlags |= PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY;
}
}
else if((materials.numIndices != 0) && mCore.mShapeCoreFlags.isSet(PxShapeCoreFlag::eOWNS_MATERIAL_IDX_MEMORY))
{
// geometry changed to non-mesh type
materials.deallocate();
}
}
PxShape* ShapeCore::getPxShape()
{
return Sc::gOffsetTable.convertScShape2Px(this);
}
const PxShape* ShapeCore::getPxShape() const
{
return Sc::gOffsetTable.convertScShape2Px(this);
}
void ShapeCore::setContactOffset(const PxReal offset)
{
mCore.mContactOffset = offset;
ShapeSim* exclusiveSim = getExclusiveSim();
if(exclusiveSim)
exclusiveSim->getScene().updateContactDistance(exclusiveSim->getElementID(), offset);
}
// PX_SERIALIZATION
PX_FORCE_INLINE void exportExtraDataMaterials(PxSerializationContext& stream, const MaterialIndicesStruct& materials)
{
stream.alignData(PX_SERIAL_ALIGN);
stream.writeData(materials.indices, sizeof(PxU16)*materials.numIndices);
}
void ShapeCore::exportExtraData(PxSerializationContext& stream)
{
const MaterialIndicesStruct* materialsLL = getMaterials(mCore.mGeometry);
if(materialsLL)
exportExtraDataMaterials(stream, *materialsLL);
}
void ShapeCore::importExtraData(PxDeserializationContext& context)
{
MaterialIndicesStruct* materialsLL = const_cast<MaterialIndicesStruct*>(getMaterials(mCore.mGeometry));
if(materialsLL)
materialsLL->indices = context.readExtraData<PxU16, PX_SERIAL_ALIGN>(materialsLL->numIndices);
}
void ShapeCore::resolveMaterialReference(PxU32 materialTableIndex, PxU16 materialIndex)
{
if(materialTableIndex == 0)
mCore.mMaterialIndex = materialIndex;
MaterialIndicesStruct* materialsLL = const_cast<MaterialIndicesStruct*>(getMaterials(mCore.mGeometry));
if(materialsLL)
materialsLL->indices[materialTableIndex] = materialIndex;
}
void ShapeCore::resolveReferences(PxDeserializationContext& context)
{
// Resolve geometry pointers if needed
PxGeometry& geom = const_cast<PxGeometry&>(mCore.mGeometry.getGeometry());
switch(geom.getType())
{
case PxGeometryType::eCONVEXMESH:
{
PxConvexMeshGeometryLL& convexGeom = static_cast<PxConvexMeshGeometryLL&>(geom);
context.translatePxBase(convexGeom.convexMesh);
// update the hullData pointer
static_cast<PxConvexMeshGeometryLL&>(geom) = extendForLL(convexGeom);
}
break;
case PxGeometryType::eHEIGHTFIELD:
{
PxHeightFieldGeometryLL& hfGeom = static_cast<PxHeightFieldGeometryLL&>(geom);
context.translatePxBase(hfGeom.heightField);
// update hf pointers
static_cast<PxHeightFieldGeometryLL&>(geom) = extendForLL(hfGeom);
}
break;
case PxGeometryType::eTRIANGLEMESH:
{
PxTriangleMeshGeometryLL& meshGeom = static_cast<PxTriangleMeshGeometryLL&>(geom);
context.translatePxBase(meshGeom.triangleMesh);
// update mesh pointers
static_cast<PxTriangleMeshGeometryLL&>(geom) = extendForLL(meshGeom);
}
break;
case PxGeometryType::eTETRAHEDRONMESH:
case PxGeometryType::ePARTICLESYSTEM:
case PxGeometryType::eCUSTOM:
{
// implement
PX_ASSERT(0);
}
break;
case PxGeometryType::eSPHERE:
case PxGeometryType::ePLANE:
case PxGeometryType::eCAPSULE:
case PxGeometryType::eBOX:
case PxGeometryType::eCONVEXCORE:
case PxGeometryType::eGEOMETRY_COUNT:
case PxGeometryType::eINVALID:
break;
}
}
//~PX_SERIALIZATION

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,343 @@
// 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_SHAPE_INTERACTION_H
#define SC_SHAPE_INTERACTION_H
#include "ScElementSimInteraction.h"
#include "ScShapeSim.h"
#include "ScActorPair.h"
#include "ScScene.h"
#include "ScBodySim.h"
#include "PxsContactManager.h"
#include "PxsContext.h"
#include "PxsSimpleIslandManager.h"
#define INVALID_REPORT_PAIR_ID 0xffffffff
namespace physx
{
class PxsContactManagerOutputIterator;
namespace Sc
{
class ContactReportAllocationManager;
PX_FORCE_INLINE IG::Edge::EdgeType getInteractionEdgeType(PxActorType::Enum actorTypeLargest)
{
IG::Edge::EdgeType type = IG::Edge::eCONTACT_MANAGER;
#if PX_SUPPORT_GPU_PHYSX
if(actorTypeLargest == PxActorType::eDEFORMABLE_VOLUME)
type = IG::Edge::eSOFT_BODY_CONTACT;
else if(actorTypeLargest == PxActorType::eDEFORMABLE_SURFACE)
type = IG::Edge::eFEM_CLOTH_CONTACT;
else if(actorTypeLargest == PxActorType::ePBD_PARTICLESYSTEM)
type = IG::Edge::ePARTICLE_SYSTEM_CONTACT;
#else
PX_UNUSED(actorTypeLargest);
#endif
return type;
}
/*
Description: A ShapeInteraction represents a pair of objects which _may_ have contacts. Created by the broadphase
and processed by the NPhaseCore.
*/
class ShapeInteraction : public ElementSimInteraction
{
friend class NPhaseCore;
ShapeInteraction& operator=(const ShapeInteraction&);
public:
enum SiFlag
{
PAIR_FLAGS_MASK = (PxPairFlag::eNEXT_FREE - 1), // Bits where the PxPairFlags get stored
NEXT_FREE = ((PAIR_FLAGS_MASK << 1) & ~PAIR_FLAGS_MASK),
HAS_TOUCH = (NEXT_FREE << 0), // Tracks the last know touch state
HAS_NO_TOUCH = (NEXT_FREE << 1), // Tracks the last know touch state
TOUCH_KNOWN = (HAS_TOUCH | HAS_NO_TOUCH), // If none of these flags is set, the touch state is not known (for example, this is true for pairs that never ran narrowphase
CONTACTS_COLLECT_POINTS = (NEXT_FREE << 2), // The user wants to get the contact points (includes debug rendering)
CONTACTS_RESPONSE_DISABLED = (NEXT_FREE << 3), // Collision response disabled (either by the user through PxPairFlag::eSOLVE_CONTACT or because the pair has two kinematics)
CONTACT_FORCE_THRESHOLD_PAIRS = PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST),
CONTACT_REPORT_EVENTS = PxU32(PxPairFlag::eNOTIFY_TOUCH_FOUND) | PxU32(PxPairFlag::eNOTIFY_TOUCH_PERSISTS) | PxU32(PxPairFlag::eNOTIFY_TOUCH_LOST) |
PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_FOUND) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_PERSISTS) | PxU32(PxPairFlag::eNOTIFY_THRESHOLD_FORCE_LOST),
CONTACT_REPORT_EXTRA_DATA = PxU32(PxPairFlag::ePRE_SOLVER_VELOCITY) | PxU32(PxPairFlag::ePOST_SOLVER_VELOCITY) | PxU32(PxPairFlag::eCONTACT_EVENT_POSE),
FORCE_THRESHOLD_EXCEEDED_NOW = (NEXT_FREE << 4),
FORCE_THRESHOLD_EXCEEDED_BEFORE = (NEXT_FREE << 5),
FORCE_THRESHOLD_EXCEEDED_FLAGS = FORCE_THRESHOLD_EXCEEDED_NOW | FORCE_THRESHOLD_EXCEEDED_BEFORE,
IS_IN_PERSISTENT_EVENT_LIST = (NEXT_FREE << 6), // The pair is in the list of persistent contact events
WAS_IN_PERSISTENT_EVENT_LIST = (NEXT_FREE << 7), // The pair is inactive but used to be in the list of persistent contact events
IN_PERSISTENT_EVENT_LIST = IS_IN_PERSISTENT_EVENT_LIST | WAS_IN_PERSISTENT_EVENT_LIST,
IS_IN_FORCE_THRESHOLD_EVENT_LIST= (NEXT_FREE << 8), // The pair is in the list of force threshold contact events
IS_IN_CONTACT_EVENT_LIST = IS_IN_PERSISTENT_EVENT_LIST | IS_IN_FORCE_THRESHOLD_EVENT_LIST,
LL_MANAGER_RECREATE_EVENT = CONTACT_REPORT_EVENTS | CONTACTS_COLLECT_POINTS |
CONTACTS_RESPONSE_DISABLED | PxU32(PxPairFlag::eMODIFY_CONTACTS)
};
ShapeInteraction(ShapeSimBase& s1, ShapeSimBase& s2, PxPairFlags pairFlags, PxsContactManager* contactManager);
~ShapeInteraction();
// Submits to contact stream
void processUserNotification(PxU32 contactEvent, PxU16 infoFlags, bool touchLost, PxU32 ccdPass, bool useCurrentTransform,
PxsContactManagerOutputIterator& outputs); // ccdPass is 0 for discrete collision and then 1,2,... for the CCD passes
void processUserNotificationSync();
void processUserNotificationAsync(PxU32 contactEvent, PxU16 infoFlags, bool touchLost, PxU32 ccdPass, bool useCurrentTransform,
PxsContactManagerOutputIterator& outputs, ContactReportAllocationManager* alloc = NULL); // ccdPass is 0 for discrete collision and then 1,2,... for the CCD passes
void visualize( PxRenderOutput&, PxsContactManagerOutputIterator&,
float scale, float contactImpulse, float contactNormal, float contactError, float contactPoint,
float frictionImpulse, float frictionNormal, float frictionPoint);
PxU32 getContactPointData(const void*& contactPatches, const void*& contactPoints, PxU32& contactDataSize, PxU32& contactPointCount, PxU32& patchCount, const PxReal*& impulses, PxU32 startOffset, PxsContactManagerOutputIterator& outputs);
PxU32 getContactPointData(const void*& contactPatches, const void*& contactPoints, PxU32& contactDataSize, PxU32& contactPointCount, PxU32& patchCount, const PxReal*& impulses, PxU32 startOffset, PxsContactManagerOutputIterator& outputs, const void*& frictionPatches);
bool managerLostTouch(PxU32 ccdPass, PxsContactManagerOutputIterator& outputs);
void managerNewTouch(PxU32 ccdPass, PxsContactManagerOutputIterator& outputs);
PX_FORCE_INLINE void adjustCountersOnLostTouch();
PX_FORCE_INLINE void adjustCountersOnNewTouch();
PX_FORCE_INLINE void sendCCDRetouch(PxU32 ccdPass, PxsContactManagerOutputIterator& outputs);
void setContactReportPostSolverVelocity(ContactStreamManager& cs);
void sendLostTouchReport(bool shapeVolumeRemoved, PxU32 ccdPass, PxsContactManagerOutputIterator& ouptuts);
void resetManagerCachedState() const;
PX_FORCE_INLINE ActorPair* getActorPair() const { return mActorPair; }
PX_FORCE_INLINE void setActorPair(ActorPair& aPair) { mActorPair = &aPair; }
PX_FORCE_INLINE void clearActorPair() { mActorPair = NULL; }
PX_FORCE_INLINE ActorPairReport& getActorPairReport() const { return ActorPairReport::cast(*mActorPair); }
PX_INLINE PxIntBool isReportPair() const { /*PX_ASSERT(!(PxIntBool(getPairFlags() & CONTACT_REPORT_EVENTS)) || mActorPair->isReportPair());*/ return PxIntBool(getPairFlags() & CONTACT_REPORT_EVENTS); }
PX_INLINE PxIntBool hasTouch() const { return readFlag(HAS_TOUCH); }
PX_INLINE PxIntBool hasCCDTouch() const { PX_ASSERT(mManager); return mManager->getHadCCDContact(); }
PX_INLINE void swapAndClearForceThresholdExceeded();
PX_FORCE_INLINE void raiseFlag(SiFlag flag) { mFlags |= flag; }
PX_FORCE_INLINE PxIntBool readFlag(SiFlag flag) const { return PxIntBool(mFlags & flag); }
PX_FORCE_INLINE PxU32 getPairFlags() const;
PX_FORCE_INLINE void removeFromReportPairList();
void onShapeChangeWhileSleeping(bool shapeOfDynamicChanged);
PX_FORCE_INLINE PxIntBool hasKnownTouchState() const;
bool onActivate(PxsContactManager* contactManager);
bool onDeactivate();
void updateState(const PxU8 externalDirtyFlags);
const PxsContactManager* getContactManager() const { return mManager; }
void clearIslandGenData(IG::SimpleIslandManager& islandManager);
PX_FORCE_INLINE IG::EdgeIndex getEdgeIndex() const { return mEdgeIndex; }
PX_FORCE_INLINE Sc::ShapeSimBase& getShape0() const { return static_cast<ShapeSimBase&>(getElement0()); }
PX_FORCE_INLINE Sc::ShapeSimBase& getShape1() const { return static_cast<ShapeSimBase&>(getElement1()); }
PX_FORCE_INLINE Sc::ActorSim& getActor0() { return getActorSim0(); }
PX_FORCE_INLINE Sc::ActorSim& getActor1() { return getActorSim1(); }
private:
ActorPair* mActorPair;
PxsContactManager* mManager;
PxU32 mContactReportStamp;
PxU32 mReportPairIndex; // Owned by NPhaseCore for its report pair list
PxU32 mReportStreamIndex; // position of this pair in the contact report stream
void createManager(PxsContactManager* contactManager);
PX_INLINE bool updateManager(PxsContactManager* contactManager);
PX_INLINE void destroyManager();
PX_FORCE_INLINE bool activeManagerAllowed() const;
PX_FORCE_INLINE PxU32 getManagerContactState() const { return mFlags & LL_MANAGER_RECREATE_EVENT; }
PX_FORCE_INLINE void clearFlag(SiFlag flag) { mFlags &= ~flag; }
PX_INLINE void setFlag(SiFlag flag, bool value)
{
if (value)
raiseFlag(flag);
else
clearFlag(flag);
}
PX_FORCE_INLINE void setHasTouch() { clearFlag(HAS_NO_TOUCH); raiseFlag(HAS_TOUCH); }
PX_FORCE_INLINE void setHasNoTouch() { clearFlag(HAS_TOUCH); raiseFlag(HAS_NO_TOUCH); }
PX_FORCE_INLINE void setPairFlags(PxPairFlags flags);
PX_FORCE_INLINE void processReportPairOnActivate();
PX_FORCE_INLINE void processReportPairOnDeactivate();
// Certain SiFlag cache properties of the pair. If these properties change then the flags have to be updated.
// For example: is collision enabled for this pair? are contact points requested for this pair?
PX_FORCE_INLINE void updateFlags(const Sc::Scene&, const Sc::ActorSim&, const Sc::ActorSim&, const PxU32 pairFlags);
friend class Sc::Scene;
};
} // namespace Sc
PX_FORCE_INLINE void Sc::ShapeInteraction::setPairFlags(PxPairFlags flags)
{
PX_ASSERT(PxU32(flags) < PxPairFlag::eNEXT_FREE); // to find out if a new PxPairFlag has been added after eLAST instead of in front
PxU32 newFlags = mFlags;
PxU32 fl = PxU32(flags) & PAIR_FLAGS_MASK;
newFlags &= (~PAIR_FLAGS_MASK); // clear old flags
newFlags |= fl;
mFlags = newFlags;
}
// PT: returning PxU32 instead of PxPairFlags to remove LHS. Please do not undo this.
PX_FORCE_INLINE PxU32 Sc::ShapeInteraction::getPairFlags() const
{
return (mFlags & PAIR_FLAGS_MASK);
}
PX_INLINE void Sc::ShapeInteraction::swapAndClearForceThresholdExceeded()
{
PxU32 flags = mFlags;
PX_COMPILE_TIME_ASSERT(FORCE_THRESHOLD_EXCEEDED_NOW == (FORCE_THRESHOLD_EXCEEDED_BEFORE >> 1));
PxU32 nowToBefore = (flags & FORCE_THRESHOLD_EXCEEDED_NOW) << 1;
flags &= ~(FORCE_THRESHOLD_EXCEEDED_NOW | FORCE_THRESHOLD_EXCEEDED_BEFORE);
flags |= nowToBefore;
mFlags = flags;
}
PX_FORCE_INLINE void Sc::ShapeInteraction::removeFromReportPairList()
{
// this method should only get called if the pair is in the list for
// persistent or force based contact reports
PX_ASSERT(mReportPairIndex != INVALID_REPORT_PAIR_ID);
PX_ASSERT(readFlag(IS_IN_CONTACT_EVENT_LIST));
Scene& scene = getScene();
if (readFlag(IS_IN_FORCE_THRESHOLD_EVENT_LIST))
scene.getNPhaseCore()->removeFromForceThresholdContactEventPairs(this);
else
{
PX_ASSERT(readFlag(IS_IN_PERSISTENT_EVENT_LIST));
scene.getNPhaseCore()->removeFromPersistentContactEventPairs(this);
}
}
PX_INLINE bool Sc::ShapeInteraction::updateManager(PxsContactManager* contactManager)
{
if (activeManagerAllowed())
{
if (mManager == 0)
createManager(contactManager);
return (mManager != NULL); // creation might fail (pool reached limit, mem allocation failed etc.)
}
else
return false;
}
PX_INLINE void Sc::ShapeInteraction::destroyManager()
{
PX_ASSERT(mManager);
Scene& scene = getScene();
PxvNphaseImplementationContext* nphaseImplementationContext = scene.getLowLevelContext()->getNphaseImplementationContext();
PX_ASSERT(nphaseImplementationContext);
nphaseImplementationContext->unregisterContactManager(mManager);
/*if (mEdgeIndex != IG_INVALID_EDGE)
scene.getSimpleIslandManager()->clearEdgeRigidCM(mEdgeIndex);*/
scene.getLowLevelContext()->destroyContactManager(mManager);
mManager = 0;
}
PX_FORCE_INLINE bool Sc::ShapeInteraction::activeManagerAllowed() const
{
ActorSim& bodySim0 = getActorSim0();
ActorSim& bodySim1 = getActorSim1();
// the first shape always belongs to a dynamic body or deformable volume
#if PX_SUPPORT_GPU_PHYSX
PX_ASSERT(bodySim0.isDynamicRigid() || bodySim0.isDeformableSurface() || bodySim0.isDeformableVolume() || bodySim0.isParticleSystem());
#else
PX_ASSERT(bodySim0.isDynamicRigid());
#endif
// PT: try to prevent OM-103695 / PX-4509
// ### DEFENSIVE
if(!bodySim0.getNodeIndex().isValid())
return PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "ShapeInteraction::activeManagerAllowed: found invalid node!");
const IG::IslandSim& islandSim = getScene().getSimpleIslandManager()->getSpeculativeIslandSim();
//check whether active in the speculative sim!
return (islandSim.getNode(bodySim0.getNodeIndex()).isActive() ||
(!bodySim1.isStaticRigid() && islandSim.getNode(bodySim1.getNodeIndex()).isActive()));
}
PX_FORCE_INLINE void Sc::ShapeInteraction::sendCCDRetouch(PxU32 ccdPass, PxsContactManagerOutputIterator& outputs)
{
const PxU32 pairFlags = getPairFlags();
if (pairFlags & PxPairFlag::eNOTIFY_TOUCH_CCD)
processUserNotification(PxPairFlag::eNOTIFY_TOUCH_CCD, 0, false, ccdPass, false, outputs);
}
PX_FORCE_INLINE void Sc::ShapeInteraction::adjustCountersOnLostTouch()
{
PX_ASSERT(mActorPair->getTouchCount());
mActorPair->decTouchCount();
}
PX_FORCE_INLINE void Sc::ShapeInteraction::adjustCountersOnNewTouch()
{
mActorPair->incTouchCount();
}
PX_FORCE_INLINE PxIntBool Sc::ShapeInteraction::hasKnownTouchState() const
{
// For a pair where the bodies were added asleep, the touch state is not known until narrowphase runs on the pair for the first time.
// If such a pair looses AABB overlap before, the conservative approach is to wake the bodies up. This method provides an indicator that
// this is such a pair. Note: this might also wake up objects that do not touch but that's the price to pay (unless we want to run
// overlap tests on such pairs).
if (mManager)
return mManager->touchStatusKnown();
else
return readFlag(TOUCH_KNOWN);
}
}
#endif

View File

@@ -0,0 +1,49 @@
// 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.
#include "ScShapeSim.h"
using namespace physx;
using namespace Sc;
void resetElementID(Scene& scene, ShapeSimBase& shapeSim);
ShapeSim::ShapeSim(ActorSim& owner, ShapeCore& core) : ShapeSimBase(owner, &core)
{
const PxU32 index = getElementID();
initSubsystemsDependingOnElementID(index);
core.setExclusiveSim(this);
}
ShapeSim::~ShapeSim()
{
Sc::ShapeCore::getCore(*mShapeCore).setExclusiveSim(NULL);
Scene& scScene = getScene();
resetElementID(scScene, *this);
}

View File

@@ -0,0 +1,58 @@
// 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_SHAPE_SIM_H
#define SC_SHAPE_SIM_H
#include "ScShapeSimBase.h"
namespace physx
{
/** Simulation object corresponding to a shape core object. This object is created when
a ShapeCore object is added to the simulation, and destroyed when it is removed
*/
namespace Sc
{
class ActorSim;
class ShapeCore;
class ShapeSim : public ShapeSimBase
{
PX_NOCOPY(ShapeSim)
public:
ShapeSim(ActorSim&, ShapeCore& core);
~ShapeSim();
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,432 @@
// 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.
#include "ScShapeSimBase.h"
#include "ScSqBoundsManager.h"
#include "ScTriggerInteraction.h"
#include "ScSimulationController.h"
#include "CmTransformUtils.h"
#include "ScShapeInteraction.h"
using namespace physx;
using namespace Sc;
// PT: keep local functions in cpp, no need to pollute the header. Don't force conversions to bool if not necessary.
static PX_FORCE_INLINE PxU32 hasTriggerFlags(PxShapeFlags flags) { return PxU32(flags) & PxU32(PxShapeFlag::eTRIGGER_SHAPE); }
void resetElementID(Scene& scene, ShapeSimBase& shapeSim)
{
PX_ASSERT(!shapeSim.isInBroadPhase());
// scene.getDirtyShapeSimMap().reset(shapeSim.getElementID());
scene.getDirtyShapeSimMap().boundedReset(shapeSim.getElementID());
if (shapeSim.getSqBoundsId() != PX_INVALID_U32)
shapeSim.destroySqBounds();
}
static PX_INLINE Bp::FilterGroup::Enum getBPGroup(const ShapeSimBase& shapeSim)
{
const BodySim* bs = shapeSim.getBodySim();
const RigidSim& rbSim = shapeSim.getRbSim();
bool isKinematic = bs ? bs->isKinematic() : false;
if (isKinematic && bs->hasForcedKinematicNotif())
isKinematic = false;
return Bp::getFilterGroup(rbSim.getActorType() == PxActorType::eRIGID_STATIC, rbSim.getActorID(), isKinematic);
}
static void setElementInteractionsDirty(Sc::ElementSim& elementSim, InteractionDirtyFlag::Enum flag, PxU8 interactionFlag)
{
ElementSim::ElementInteractionIterator iter = elementSim.getElemInteractions();
ElementSimInteraction* interaction = iter.getNext();
while(interaction)
{
if(interaction->readInteractionFlag(interactionFlag))
interaction->setDirty(flag);
interaction = iter.getNext();
}
}
void ShapeSimBase::onFilterDataChange()
{
setElementInteractionsDirty(*this, InteractionDirtyFlag::eFILTER_STATE, InteractionFlag::eFILTERABLE);
}
void ShapeSimBase::onResetFiltering()
{
if (isInBroadPhase())
reinsertBroadPhase();
}
void ShapeSimBase::onRestOffsetChange()
{
setElementInteractionsDirty(*this, InteractionDirtyFlag::eREST_OFFSET, InteractionFlag::eRB_ELEMENT);
}
void ShapeSimBase::onContactOffsetChange()
{
if (isInBroadPhase())
getScene().getAABBManager()->setContactDistance(getElementID(), getCore().getContactOffset());
}
void ShapeSimBase::removeFromBroadPhase(bool wakeOnLostTouch)
{
if (isInBroadPhase())
internalRemoveFromBroadPhase(wakeOnLostTouch);
}
void ShapeSimBase::reinsertBroadPhase()
{
bool wasPendingInsert = false;
if (isInBroadPhase())
{
wasPendingInsert = internalRemoveFromBroadPhase();
}
// internalAddToBroadPhase();
Scene& scene = getScene();
// Scene::removeShape
{
//unregisterShapeFromNphase(shape.getCore());
scene.getSimulationController()->removePxgShape(getElementID());
scene.unregisterShapeFromNphase(getCore(), getElementID());
}
PxU32 indexFrom = getElementID();
// Call ShapeSim dtor
{
resetElementID(scene, *this);
}
// Call ElementSim dtor - only required if this shape was not pending insert (otherwise the elementID is fine to keep)
if (!wasPendingInsert)
{
{
releaseID();
}
// Call ElementSim ctor
{
initID();
}
}
// Call ShapeSim ctor
{
initSubsystemsDependingOnElementID(indexFrom);
}
// Scene::addShape
{
scene.getSimulationController()->addPxgShape(this, getPxsShapeCore(), getActorNodeIndex(), getElementID());
// PT: TODO: anything else needed here?
scene.registerShapeInNphase(&getRbSim().getRigidCore(), getCore(), getElementID()); // register in narrowphase getElementID() - transformcacheID. so I guess we must know at this point the definite index
}
}
PX_FORCE_INLINE void ShapeSimBase::internalAddToBroadPhase()
{
PX_ASSERT(!isInBroadPhase());
addToAABBMgr(getCore().getContactOffset(), getBPGroup(*this), (getCore().getCore().mShapeFlags & PxShapeFlag::eTRIGGER_SHAPE) ? Bp::ElementType::eTRIGGER : Bp::ElementType::eSHAPE);
}
PX_FORCE_INLINE bool ShapeSimBase::internalRemoveFromBroadPhase(bool wakeOnLostTouch)
{
PX_ASSERT(isInBroadPhase());
bool res = removeFromAABBMgr();
Scene& scene = getScene();
PxsContactManagerOutputIterator outputs = scene.getLowLevelContext()->getNphaseImplementationContext()->getContactManagerOutputs();
scene.getNPhaseCore()->onVolumeRemoved(this, wakeOnLostTouch ? PxU32(PairReleaseFlag::eWAKE_ON_LOST_TOUCH) : 0, outputs);
return res;
}
void ShapeSimBase::initSubsystemsDependingOnElementID(PxU32 indexFrom)
{
Scene& scScene = getScene();
Bp::BoundsArray& boundsArray = scScene.getBoundsArray();
const PxU32 index = getElementID();
PX_ALIGN(16, PxTransform absPos);
getAbsPoseAligned(&absPos);
PxsTransformCache& cache = scScene.getLowLevelContext()->getTransformCache();
cache.initEntry(index);
cache.setTransformCache(absPos, 0, index, indexFrom);
boundsArray.updateBounds(absPos, getCore().getGeometryUnion().getGeometry(), index, indexFrom);
{
PX_PROFILE_ZONE("API.simAddShapeToBroadPhase", scScene.getContextId());
if (isBroadPhase(getCore().getFlags()))
internalAddToBroadPhase();
else
scScene.getAABBManager()->reserveSpaceForBounds(index);
scScene.updateContactDistance(index, getContactOffset());
}
// if(scScene.getDirtyShapeSimMap().size() <= index)
// scScene.getDirtyShapeSimMap().resize(PxMax(index+1, (scScene.getDirtyShapeSimMap().size()+1) * 2u));
ActorSim& owner = mActor;
if (owner.isDynamicRigid() && static_cast<BodySim&>(owner).isActive())
createSqBounds();
}
PxNodeIndex ShapeSimBase::getActorNodeIndex() const
{
ActorSim& owner = mActor;
return owner.getActorType() == PxActorType::eRIGID_STATIC ? PxNodeIndex(PX_INVALID_NODE) : static_cast<BodySim&>(owner).getNodeIndex();
}
void ShapeSimBase::getAbsPoseAligned(PxTransform* PX_RESTRICT globalPose) const
{
// PT: TODO: simplify dynamic case when shape2Actor = idt
const PxsShapeCore& shapeCore = getCore().getCore();
const PxTransform& shape2Actor = shapeCore.getTransform();
const PxTransform* actor2World = NULL;
if (getActor().getActorType() == PxActorType::eRIGID_STATIC)
{
PxsRigidCore& core = static_cast<StaticSim&>(getActor()).getStaticCore().getCore();
if (shapeCore.mShapeCoreFlags.isSet(PxShapeCoreFlag::eIDT_TRANSFORM))
{
PX_ASSERT(shape2Actor.p.isZero() && shape2Actor.q.isIdentity());
*globalPose = core.body2World;
return;
}
actor2World = &core.body2World;
}
else
{
PxsBodyCore& core = static_cast<BodySim&>(getActor()).getBodyCore().getCore();
if (!core.hasIdtBody2Actor())
{
Cm::getDynamicGlobalPoseAligned(core.body2World, shape2Actor, core.getBody2Actor(), *globalPose);
return;
}
actor2World = &core.body2World;
}
Cm::getStaticGlobalPoseAligned(*actor2World, shape2Actor, *globalPose);
}
void ShapeSimBase::onFlagChange(PxShapeFlags oldFlags)
{
const PxShapeFlags newFlags = getCore().getFlags();
const bool oldBp = isBroadPhase(oldFlags) != 0;
const bool newBp = isBroadPhase(newFlags) != 0;
// Change of collision shape flags requires removal/add to broadphase
if (oldBp != newBp)
{
if (!oldBp && newBp)
{
// A.B. if a trigger was removed and inserted within the same frame we need to reinsert
if (hasTriggerFlags(newFlags) && getScene().getAABBManager()->isMarkedForRemove(getElementID()))
reinsertBroadPhase();
else
internalAddToBroadPhase();
}
else
internalRemoveFromBroadPhase();
}
else
{
const bool wasTrigger = hasTriggerFlags(oldFlags) != 0;
const bool isTrigger = hasTriggerFlags(newFlags) != 0;
if (wasTrigger != isTrigger)
reinsertBroadPhase(); // re-insertion is necessary because trigger pairs get killed
}
const PxShapeFlags hadSq = oldFlags & PxShapeFlag::eSCENE_QUERY_SHAPE;
const PxShapeFlags hasSq = newFlags & PxShapeFlag::eSCENE_QUERY_SHAPE;
if (hasSq && !hadSq)
{
BodySim* body = getBodySim();
if (body && body->isActive())
createSqBounds();
}
else if (hadSq && !hasSq)
destroySqBounds();
getScene().getSimulationController()->addPxgShape(this, getPxsShapeCore(), getActorNodeIndex(), getElementID());
}
BodySim* ShapeSimBase::getBodySim() const
{
ActorSim& a = getActor();
return a.isDynamicRigid() ? static_cast<BodySim*>(&a) : NULL;
}
PxsRigidCore& ShapeSimBase::getPxsRigidCore() const
{
ActorSim& a = getActor();
return a.isDynamicRigid() ? static_cast<BodySim&>(a).getBodyCore().getCore()
: static_cast<StaticSim&>(a).getStaticCore().getCore();
}
void ShapeSimBase::updateCached(PxU32 transformCacheFlags, PxBitMapPinned* shapeChangedMap)
{
PX_ALIGN(16, PxTransform absPose);
getAbsPoseAligned(&absPose);
Scene& scene = getScene();
const PxU32 index = getElementID();
scene.getLowLevelContext()->getTransformCache().setTransformCache(absPose, transformCacheFlags, index, index);
scene.getBoundsArray().updateBounds(absPose, getCore().getGeometryUnion().getGeometry(), index, index);
if (shapeChangedMap && isInBroadPhase())
shapeChangedMap->growAndSet(index);
}
void ShapeSimBase::updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray)
{
const PxU32 index = getElementID();
PxsCachedTransform& ct = transformCache.getTransformCache(index);
PxPrefetchLine(&ct);
getAbsPoseAligned(&ct.transform);
ct.flags = 0;
PxBounds3& b = boundsArray.begin()[index];
Gu::computeBounds(b, getCore().getGeometryUnion().getGeometry(), ct.transform, 0.0f, 1.0f);
}
void ShapeSimBase::updateBPGroup()
{
if (isInBroadPhase())
{
Sc::Scene& scene = getScene();
scene.getAABBManager()->setBPGroup(getElementID(), getBPGroup(*this));
reinsertBroadPhase();
// internalRemoveFromBroadPhase();
// internalAddToBroadPhase();
}
}
void ShapeSimBase::markBoundsForUpdate()
{
Scene& scene = getScene();
if (isInBroadPhase())
scene.getDirtyShapeSimMap().growAndSet(getElementID());
}
static PX_FORCE_INLINE void updateInteraction(Scene& scene, Interaction* i, const bool isDynamic, const bool isAsleep)
{
if (i->getType() == InteractionType::eOVERLAP)
{
ShapeInteraction* si = static_cast<ShapeInteraction*>(i);
si->resetManagerCachedState();
if (isAsleep)
si->onShapeChangeWhileSleeping(isDynamic);
}
else if (i->getType() == InteractionType::eTRIGGER)
(static_cast<TriggerInteraction*>(i))->forceProcessingThisFrame(scene); // trigger pairs need to be checked next frame
}
void ShapeSimBase::onVolumeOrTransformChange()
{
Scene& scene = getScene();
BodySim* body = getBodySim();
const bool isDynamic = (body != NULL);
const bool isAsleep = body ? !body->isActive() : true;
ElementSim::ElementInteractionIterator iter = getElemInteractions();
ElementSimInteraction* i = iter.getNext();
while (i)
{
updateInteraction(scene, i, isDynamic, isAsleep);
i = iter.getNext();
}
markBoundsForUpdate();
getScene().getSimulationController()->addPxgShape(this, getPxsShapeCore(), getActorNodeIndex(), getElementID());
}
void notifyActorInteractionsOfTransformChange(ActorSim& actor)
{
bool isDynamic;
bool isAsleep;
if (actor.isDynamicRigid())
{
isDynamic = true;
isAsleep = !static_cast<BodySim&>(actor).isActive();
}
else
{
isDynamic = false;
isAsleep = true;
}
Scene& scene = actor.getScene();
PxU32 nbInteractions = actor.getActorInteractionCount();
Interaction** interactions = actor.getActorInteractions();
while (nbInteractions--)
updateInteraction(scene, *interactions++, isDynamic, isAsleep);
}
void ShapeSimBase::createSqBounds()
{
if (mSqBoundsId != PX_INVALID_U32)
return;
BodySim* bodySim = getBodySim();
PX_ASSERT(bodySim);
if (bodySim->usingSqKinematicTarget() || bodySim->isFrozen() || !bodySim->isActive() || bodySim->readInternalFlag(BodySim::BF_IS_COMPOUND_RIGID))
return;
if (getCore().getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE)
getScene().getSqBoundsManager().addSyncShape(*this);
}
void ShapeSimBase::destroySqBounds()
{
if (mSqBoundsId != PX_INVALID_U32)
getScene().getSqBoundsManager().removeSyncShape(*this);
}

View File

@@ -0,0 +1,126 @@
// 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.
#ifndef SC_SHAPESIM_BASE_H
#define SC_SHAPESIM_BASE_H
#include "ScElementSim.h"
#include "ScShapeCore.h"
#include "ScRigidSim.h"
namespace physx
{
namespace Sc
{
PX_FORCE_INLINE PxU32 isBroadPhase(PxShapeFlags flags) { return PxU32(flags) & PxU32(PxShapeFlag::eTRIGGER_SHAPE | PxShapeFlag::eSIMULATION_SHAPE); }
class ShapeCore;
class ShapeSimBase : public ElementSim
{
PX_NOCOPY(ShapeSimBase)
public:
ShapeSimBase(ActorSim& owner, const ShapeCore* core) :
ElementSim (owner),
mSqBoundsId (PX_INVALID_U32),
mPrunerIndex(PX_INVALID_U32)
{ setCore(core); }
~ShapeSimBase() { }
PX_FORCE_INLINE void setCore(const ShapeCore* core);
PX_FORCE_INLINE const ShapeCore& getCore() const;
PX_FORCE_INLINE bool isPxsCoreValid() const { return mShapeCore != NULL; }
PX_INLINE PxGeometryType::Enum getGeometryType() const { return getCore().getGeometryType(); }
// This is just for getting a reference for the user, so we cast away const-ness
PX_INLINE PxShape* getPxShape() const { return const_cast<PxShape*>(getCore().getPxShape()); }
PX_FORCE_INLINE PxReal getRestOffset() const { return getCore().getRestOffset(); }
PX_FORCE_INLINE PxReal getTorsionalPatchRadius() const { return getCore().getTorsionalPatchRadius(); }
PX_FORCE_INLINE PxReal getMinTorsionalPatchRadius() const { return getCore().getMinTorsionalPatchRadius(); }
PX_FORCE_INLINE PxU32 getFlags() const { return getCore().getFlags(); }
PX_FORCE_INLINE PxReal getContactOffset() const { return getCore().getContactOffset(); }
PX_FORCE_INLINE PxU32 getTransformCacheID() const { return getElementID(); }
PX_FORCE_INLINE PxU32 getSqBoundsId() const { return mSqBoundsId; }
PX_FORCE_INLINE void setSqBoundsId(PxU32 id) { mSqBoundsId = id; }
PX_FORCE_INLINE PxU32 getSqPrunerIndex() const { return mPrunerIndex; }
PX_FORCE_INLINE void setSqPrunerIndex(PxU32 index) { mPrunerIndex = index; }
PX_FORCE_INLINE PxsShapeCore* getPxsShapeCore() { return mShapeCore; }
void onFilterDataChange();
void onRestOffsetChange();
void onFlagChange(PxShapeFlags oldFlags);
void onResetFiltering();
void onVolumeOrTransformChange();
void onContactOffsetChange();
void markBoundsForUpdate();
void reinsertBroadPhase();
void removeFromBroadPhase(bool wakeOnLostTouch);
void getAbsPoseAligned(PxTransform* PX_RESTRICT globalPose) const;
PxNodeIndex getActorNodeIndex() const;
PX_FORCE_INLINE RigidSim& getRbSim() const { return static_cast<RigidSim&>(getActor()); }
BodySim* getBodySim() const;
PxsRigidCore& getPxsRigidCore() const;
void createSqBounds();
void destroySqBounds();
void updateCached(PxU32 transformCacheFlags, PxBitMapPinned* shapeChangedMap);
void updateCached(PxsTransformCache& transformCache, Bp::BoundsArray& boundsArray);
void updateBPGroup();
protected:
PX_FORCE_INLINE void internalAddToBroadPhase();
PX_FORCE_INLINE bool internalRemoveFromBroadPhase(bool wakeOnLostTouch = true);
void initSubsystemsDependingOnElementID(PxU32 indexFrom);
PxsShapeCore* mShapeCore;
PxU32 mSqBoundsId;
PxU32 mPrunerIndex;
};
PX_FORCE_INLINE void ShapeSimBase::setCore(const ShapeCore* core)
{
mShapeCore = core ? const_cast<PxsShapeCore*>(&core->getCore()) : NULL;
}
PX_FORCE_INLINE const ShapeCore& ShapeSimBase::getCore() const
{
return Sc::ShapeCore::getCore(*mShapeCore);
}
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,213 @@
// 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_SIM_STATE_DATA_H
#define SC_SIM_STATE_DATA_H
#include "foundation/PxMemory.h"
#include "ScBodyCore.h"
namespace physx
{
namespace Sc
{
struct KinematicTransform
{
PxTransform targetPose; // The body will move to this pose over the superstep following this getting set.
PxU8 targetValid; // User set a kinematic target.
PxU8 pad[2];
PxU8 type;
};
struct Kinematic : public KinematicTransform
{
// The following members buffer the original body data to restore them when switching back to dynamic body
// (for kinematics the corresponding LowLevel properties are set to predefined values)
PxVec3 backupInverseInertia; // The inverse of the body space inertia tensor
PxReal backupInvMass; // The inverse of the body mass
PxReal backupLinearDamping; // The velocity is scaled by (1.0f - this * dt) inside integrateVelocity() every substep.
PxReal backupAngularDamping;
PxReal backupMaxAngVelSq; // The angular velocity's magnitude is clamped to this maximum value.
PxReal backupMaxLinVelSq; // The angular velocity's magnitude is clamped to this maximum value
};
PX_COMPILE_TIME_ASSERT(0 == (sizeof(Kinematic) & 0x0f));
enum VelocityModFlags
{
VMF_GRAVITY_DIRTY = (1 << 0),
VMF_ACC_DIRTY = (1 << 1),
VMF_VEL_DIRTY = (1 << 2)
};
// Important: Struct is reset in setForcesToDefaults.
struct VelocityMod
{
PxVec3 linearPerSec; // A request to change the linear velocity by this much each second. The velocity is changed by this * dt inside integrateVelocity().
PxU8 pad0[4];
PxVec3 angularPerSec;
PxU8 pad1[3];
PxU8 type;
PxVec3 linearPerStep; // A request to change the linear velocity by this much the next step. The velocity is changed inside updateForces().
PxU32 pad2;
PxVec3 angularPerStep;
PxU32 pad3;
PX_FORCE_INLINE void clear() { linearPerSec = angularPerSec = linearPerStep = angularPerStep = PxVec3(0.0f); }
PX_FORCE_INLINE void clearPerStep() { linearPerStep = angularPerStep = PxVec3(0.0f); }
PX_FORCE_INLINE const PxVec3& getLinearVelModPerSec() const { return linearPerSec; }
PX_FORCE_INLINE void accumulateLinearVelModPerSec(const PxVec3& v) { linearPerSec += v; }
PX_FORCE_INLINE void setLinearVelModPerSec(const PxVec3& v) { linearPerSec = v; }
PX_FORCE_INLINE void clearLinearVelModPerSec() { linearPerSec = PxVec3(0.0f); }
PX_FORCE_INLINE const PxVec3& getLinearVelModPerStep() const { return linearPerStep; }
PX_FORCE_INLINE void accumulateLinearVelModPerStep(const PxVec3& v) { linearPerStep += v; }
PX_FORCE_INLINE void clearLinearVelModPerStep() { linearPerStep = PxVec3(0.0f); }
PX_FORCE_INLINE const PxVec3& getAngularVelModPerSec() const { return angularPerSec; }
PX_FORCE_INLINE void accumulateAngularVelModPerSec(const PxVec3& v) { angularPerSec += v; }
PX_FORCE_INLINE void setAngularVelModPerSec(const PxVec3& v) { angularPerSec = v; }
PX_FORCE_INLINE void clearAngularVelModPerSec() { angularPerSec = PxVec3(0.0f); }
PX_FORCE_INLINE const PxVec3& getAngularVelModPerStep() const { return angularPerStep; }
PX_FORCE_INLINE void accumulateAngularVelModPerStep(const PxVec3& v) { angularPerStep += v; }
PX_FORCE_INLINE void clearAngularVelModPerStep() { angularPerStep = PxVec3(0.0f); }
};
PX_COMPILE_TIME_ASSERT(sizeof(VelocityMod) == sizeof(Kinematic));
// Structure to store data either for kinematics (target pose etc.) or for dynamics (vel and accel changes).
// note: we do not delete this object for kinematics even if no target is set.
struct SimStateData : public PxUserAllocated // TODO: may want to optimize the allocation of this further.
{
PxU8 data[sizeof(Kinematic)];
enum Enum
{
eVelMod=0,
eKine
};
SimStateData(){}
SimStateData(const PxU8 type)
{
PxMemZero(data, sizeof(Kinematic));
Kinematic* kine = reinterpret_cast<Kinematic*>(data);
kine->type = type;
}
PX_FORCE_INLINE PxU32 getType() const { const Kinematic* kine = reinterpret_cast<const Kinematic*>(data); return kine->type;}
PX_FORCE_INLINE bool isKine() const {return eKine == getType();}
PX_FORCE_INLINE bool isVelMod() const {return eVelMod == getType();}
PX_FORCE_INLINE Kinematic* getKinematicData() { Kinematic* kine = reinterpret_cast<Kinematic*>(data); PX_ASSERT(eKine == kine->type); return kine;}
PX_FORCE_INLINE VelocityMod* getVelocityModData() { VelocityMod* velmod = reinterpret_cast<VelocityMod*>(data); PX_ASSERT(eVelMod == velmod->type); return velmod;}
PX_FORCE_INLINE const Kinematic* getKinematicData() const { const Kinematic* kine = reinterpret_cast<const Kinematic*>(data); PX_ASSERT(eKine == kine->type); return kine;}
PX_FORCE_INLINE const VelocityMod* getVelocityModData() const { const VelocityMod* velmod = reinterpret_cast<const VelocityMod*>(data); PX_ASSERT(eVelMod == velmod->type); return velmod;}
};
PX_FORCE_INLINE void simStateBackupAndClearBodyProperties(SimStateData* simStateData, PxsBodyCore& core)
{
PX_ASSERT(simStateData && simStateData->isKine());
Kinematic* kine = simStateData->getKinematicData();
kine->backupLinearDamping = core.linearDamping;
kine->backupAngularDamping = core.angularDamping;
kine->backupInverseInertia = core.inverseInertia;
kine->backupInvMass = core.inverseMass;
kine->backupMaxAngVelSq = core.maxAngularVelocitySq;
kine->backupMaxLinVelSq = core.maxLinearVelocitySq;
core.inverseMass = 0.0f;
core.inverseInertia = PxVec3(0.0f);
core.linearDamping = 0.0f;
core.angularDamping = 0.0f;
core.maxAngularVelocitySq = PX_MAX_REAL;
core.maxLinearVelocitySq = PX_MAX_REAL;
}
PX_FORCE_INLINE void simStateRestoreBodyProperties(const SimStateData* simStateData, PxsBodyCore& core)
{
PX_ASSERT(simStateData && simStateData->isKine());
const Kinematic* kine = simStateData->getKinematicData();
core.inverseMass = kine->backupInvMass;
core.inverseInertia = kine->backupInverseInertia;
core.linearDamping = kine->backupLinearDamping;
core.angularDamping = kine->backupAngularDamping;
core.maxAngularVelocitySq = kine->backupMaxAngVelSq;
core.maxLinearVelocitySq = kine->backupMaxLinVelSq;
}
PX_FORCE_INLINE void simStateClearVelMod(SimStateData* simStateData)
{
if (simStateData && simStateData->isVelMod())
{
VelocityMod* velmod = simStateData->getVelocityModData();
velmod->clear();
}
}
PX_FORCE_INLINE bool simStateGetKinematicTarget(const SimStateData* simStateData, PxTransform& p)
{
if (simStateData && simStateData->isKine() && simStateData->getKinematicData()->targetValid)
{
p = simStateData->getKinematicData()->targetPose;
return true;
}
else
return false;
}
PX_FORCE_INLINE bool simStateGetHasValidKinematicTarget(const SimStateData* simStateData)
{
PX_ASSERT(!simStateData || simStateData->isKine());
return simStateData && simStateData->isKine() && simStateData->getKinematicData()->targetValid;
}
PX_FORCE_INLINE void simStateSetKinematicTarget(SimStateData* simStateData, const PxTransform& p)
{
PX_ASSERT(simStateData && simStateData->isKine());
// setting the kinematic target is only allowed if the body is part of a scene, at which point the
// mSimStateData buffer must exist
Kinematic* kine = simStateData->getKinematicData();
kine->targetPose = p;
kine->targetValid = 1;
}
PX_FORCE_INLINE void simStateInvalidateKinematicTarget(SimStateData* simStateData)
{
PX_ASSERT(simStateData && simStateData->isKine());
simStateData->getKinematicData()->targetValid = 0;
}
} // namespace Sc
} // namespace physx
#endif

View File

@@ -0,0 +1,153 @@
// 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.
#include "foundation/PxMemory.h"
#include "ScSimStats.h"
#include "PxvSimStats.h"
#include "PxsHeapMemoryAllocator.h"
using namespace physx;
Sc::SimStats::SimStats()
{
numBroadPhaseAdds = numBroadPhaseRemoves = 0;
gpuMemSizeParticles = 0;
gpuMemSizeDeformableSurfaces = 0;
gpuMemSizeDeformableVolumes = 0;
clear();
}
void Sc::SimStats::clear()
{
#if PX_ENABLE_SIM_STATS
PxMemZero(const_cast<void*>(reinterpret_cast<volatile void*>(&numTriggerPairs)), sizeof(TriggerPairCounts));
numBroadPhaseAddsPending = numBroadPhaseRemovesPending = 0;
#else
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
#endif
}
void Sc::SimStats::simStart()
{
#if PX_ENABLE_SIM_STATS
// pending broadphase adds/removes are now the current ones
numBroadPhaseAdds = numBroadPhaseAddsPending;
numBroadPhaseRemoves = numBroadPhaseRemovesPending;
clear();
#else
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
#endif
}
void Sc::SimStats::readOut(PxSimulationStatistics& s, const PxvSimStats& simStats) const
{
#if PX_ENABLE_SIM_STATS
s = PxSimulationStatistics(); // clear stats
for(PxU32 i=0; i < PxGeometryType::eCONVEXMESH+1; i++)
{
for(PxU32 j=0; j < PxGeometryType::eGEOMETRY_COUNT; j++)
{
s.nbTriggerPairs[i][j] += PxU32(numTriggerPairs[i][j]);
if (i != j)
s.nbTriggerPairs[j][i] += PxU32(numTriggerPairs[i][j]);
}
}
s.nbBroadPhaseAdds = numBroadPhaseAdds;
s.nbBroadPhaseRemoves = numBroadPhaseRemoves;
for(PxU32 i=0; i < PxGeometryType::eGEOMETRY_COUNT; i++)
{
s.nbDiscreteContactPairs[i][i] = simStats.mNbDiscreteContactPairs[i][i];
s.nbModifiedContactPairs[i][i] = simStats.mNbModifiedContactPairs[i][i];
s.nbCCDPairs[i][i] = simStats.mNbCCDPairs[i][i];
for(PxU32 j=i+1; j < PxGeometryType::eGEOMETRY_COUNT; j++)
{
PxU32 c = simStats.mNbDiscreteContactPairs[i][j];
s.nbDiscreteContactPairs[i][j] = c;
s.nbDiscreteContactPairs[j][i] = c;
c = simStats.mNbModifiedContactPairs[i][j];
s.nbModifiedContactPairs[i][j] = c;
s.nbModifiedContactPairs[j][i] = c;
c = simStats.mNbCCDPairs[i][j];
s.nbCCDPairs[i][j] = c;
s.nbCCDPairs[j][i] = c;
}
#if PX_DEBUG
for(PxU32 j=0; j < i; j++)
{
// PxvSimStats should only use one half of the matrix
PX_ASSERT(simStats.mNbDiscreteContactPairs[i][j] == 0);
PX_ASSERT(simStats.mNbModifiedContactPairs[i][j] == 0);
PX_ASSERT(simStats.mNbCCDPairs[i][j] == 0);
}
#endif
}
s.nbDiscreteContactPairsTotal = simStats.mNbDiscreteContactPairsTotal;
s.nbDiscreteContactPairsWithCacheHits = simStats.mNbDiscreteContactPairsWithCacheHits;
s.nbDiscreteContactPairsWithContacts = simStats.mNbDiscreteContactPairsWithContacts;
s.nbActiveConstraints = simStats.mNbActiveConstraints;
s.nbActiveDynamicBodies = simStats.mNbActiveDynamicBodies;
s.nbActiveKinematicBodies = simStats.mNbActiveKinematicBodies;
s.nbAxisSolverConstraints = simStats.mNbAxisSolverConstraints;
s.peakConstraintMemory = simStats.mPeakConstraintBlockAllocations * 16 * 1024;
s.compressedContactSize = simStats.mTotalCompressedContactSize;
s.requiredContactConstraintMemory = simStats.mTotalConstraintSize;
s.nbNewPairs = simStats.mNbNewPairs;
s.nbLostPairs = simStats.mNbLostPairs;
s.nbNewTouches = simStats.mNbNewTouches;
s.nbLostTouches = simStats.mNbLostTouches;
s.nbPartitions = simStats.mNbPartitions;
s.gpuDynamicsMemoryConfigStatistics.tempBufferCapacity = simStats.mGpuDynamicsTempBufferCapacity;
s.gpuDynamicsMemoryConfigStatistics.rigidContactCount = simStats.mGpuDynamicsRigidContactCount;
s.gpuDynamicsMemoryConfigStatistics.rigidPatchCount = simStats.mGpuDynamicsRigidPatchCount;
s.gpuDynamicsMemoryConfigStatistics.foundLostPairs = simStats.mGpuDynamicsFoundLostPairs;
s.gpuDynamicsMemoryConfigStatistics.foundLostAggregatePairs = simStats.mGpuDynamicsFoundLostAggregatePairs;
s.gpuDynamicsMemoryConfigStatistics.totalAggregatePairs = simStats.mGpuDynamicsTotalAggregatePairs;
s.gpuDynamicsMemoryConfigStatistics.deformableSurfaceContacts = simStats.mGpuDynamicsDeformableSurfaceContacts;
s.gpuDynamicsMemoryConfigStatistics.deformableVolumeContacts = simStats.mGpuDynamicsDeformableVolumeContacts;
s.gpuDynamicsMemoryConfigStatistics.softbodyContacts = simStats.mGpuDynamicsDeformableVolumeContacts; //deprecated
s.gpuDynamicsMemoryConfigStatistics.particleContacts = simStats.mGpuDynamicsParticleContacts;
s.gpuDynamicsMemoryConfigStatistics.collisionStackSize = simStats.mGpuDynamicsCollisionStackSize;
#else
PX_CATCH_UNDEFINED_ENABLE_SIM_STATS
PX_UNUSED(s);
PX_UNUSED(simStats);
#endif
}

View File

@@ -0,0 +1,90 @@
// 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_SIM_STATS_H
#define SC_SIM_STATS_H
#include "geometry/PxGeometry.h"
#include "PxSimulationStatistics.h"
#include "foundation/PxAtomic.h"
#include "foundation/PxUserAllocated.h"
namespace physx
{
struct PxvSimStats;
namespace Sc
{
/*
Description: contains statistics for the scene.
*/
class SimStats : public PxUserAllocated
{
public:
SimStats();
void clear(); //set counters to zero
void simStart();
void readOut(PxSimulationStatistics& dest, const PxvSimStats& simStats) const;
PX_INLINE void incBroadphaseAdds()
{
numBroadPhaseAddsPending++;
}
PX_INLINE void incBroadphaseRemoves()
{
numBroadPhaseRemovesPending++;
}
private:
// Broadphase adds/removes for the current simulation step
PxU32 numBroadPhaseAdds;
PxU32 numBroadPhaseRemoves;
// Broadphase adds/removes for the next simulation step
PxU32 numBroadPhaseAddsPending;
PxU32 numBroadPhaseRemovesPending;
public:
typedef PxI32 TriggerPairCountsNonVolatile[PxGeometryType::eCONVEXMESH+1][PxGeometryType::eGEOMETRY_COUNT];
typedef volatile TriggerPairCountsNonVolatile TriggerPairCounts;
TriggerPairCounts numTriggerPairs;
PxU64 gpuMemSizeParticles;
PxU64 gpuMemSizeDeformableSurfaces;
PxU64 gpuMemSizeDeformableVolumes;
};
} // namespace Sc
}
#endif

View File

@@ -0,0 +1,127 @@
// 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.
#include "ScSimulationController.h"
#include "foundation/PxAllocator.h"
#include "CmTask.h"
#include "CmFlushPool.h"
#include "PxNodeIndex.h"
#include "ScArticulationSim.h"
#include "PxsContext.h"
#include "foundation/PxAllocator.h"
#include "BpAABBManager.h"
#include "DyVArticulation.h"
using namespace physx;
using namespace IG;
using namespace Sc;
void SimulationController::updateScBodyAndShapeSim(PxsTransformCache& /*cache*/, Bp::BoundsArray& /*boundArray*/, PxBaseTask* continuation)
{
mCallback->updateScBodyAndShapeSim(continuation);
}
namespace
{
class UpdateArticulationAfterIntegrationTask : public Cm::Task
{
IslandSim& mIslandSim;
const PxNodeIndex* const PX_RESTRICT mNodeIndices;
const PxU32 mNbArticulations;
const PxReal mDt;
PX_NOCOPY(UpdateArticulationAfterIntegrationTask)
public:
static const PxU32 NbArticulationsPerTask = 64;
UpdateArticulationAfterIntegrationTask(PxU64 contextId, PxU32 nbArticulations, PxReal dt, const PxNodeIndex* nodeIndices, IslandSim& islandSim) :
Cm::Task(contextId),
mIslandSim(islandSim),
mNodeIndices(nodeIndices),
mNbArticulations(nbArticulations),
mDt(dt)
{
}
virtual void runInternal()
{
for (PxU32 i = 0; i < mNbArticulations; ++i)
{
PxNodeIndex nodeIndex = mNodeIndices[i];
ArticulationSim* articSim = getArticulationSim(mIslandSim, nodeIndex);
articSim->sleepCheck(mDt);
articSim->updateCached(NULL);
}
}
virtual const char* getName() const { return "UpdateArticulationAfterIntegrationTask"; }
};
}
//KS - TODO - parallelize this bit!!!!!
void SimulationController::updateArticulationAfterIntegration(
PxsContext* llContext,
Bp::AABBManagerBase* aabbManager,
PxArray<BodySim*>& ccdBodies,
PxBaseTask* continuation,
IslandSim& islandSim,
float dt
)
{
const PxU32 nbActiveArticulations = islandSim.getNbActiveNodes(Node::eARTICULATION_TYPE);
Cm::FlushPool& flushPool = llContext->getTaskPool();
const PxNodeIndex* activeArticulations = islandSim.getActiveNodes(Node::eARTICULATION_TYPE);
for (PxU32 i = 0; i < nbActiveArticulations; i += UpdateArticulationAfterIntegrationTask::NbArticulationsPerTask)
{
UpdateArticulationAfterIntegrationTask* task =
PX_PLACEMENT_NEW(flushPool.allocate(sizeof(UpdateArticulationAfterIntegrationTask)), UpdateArticulationAfterIntegrationTask)(islandSim.getContextId(), PxMin(UpdateArticulationAfterIntegrationTask::NbArticulationsPerTask, PxU32(nbActiveArticulations - i)), dt,
activeArticulations + i, islandSim);
startTask(task, continuation);
}
llContext->getLock().lock();
//const NodeIndex* activeArticulations = islandSim.getActiveNodes(Node::eARTICULATION_TYPE);
PxBitMapPinned& changedAABBMgrActorHandles = aabbManager->getChangedAABBMgActorHandleMap();
for (PxU32 i = 0; i < nbActiveArticulations; i++)
{
ArticulationSim* articSim = getArticulationSim(islandSim, activeArticulations[i]);
//KS - check links for CCD flags and add to mCcdBodies list if required....
articSim->updateCCDLinks(ccdBodies);
articSim->markShapesUpdated(&changedAABBMgrActorHandles);
}
llContext->getLock().unlock();
}

View File

@@ -0,0 +1,54 @@
// 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_SIMULATION_CONTROLLER_H
#define SC_SIMULATION_CONTROLLER_H
#include "PxsSimulationController.h"
namespace physx
{
namespace Sc
{
class SimulationController : public PxsSimulationController
{
PX_NOCOPY(SimulationController)
public:
SimulationController(PxsSimulationControllerCallback* callback) : PxsSimulationController(callback, PxIntFalse) {}
virtual ~SimulationController() {}
virtual void updateScBodyAndShapeSim(PxsTransformCache& cache, Bp::BoundsArray& boundArray, PxBaseTask* continuation) PX_OVERRIDE;
virtual void updateArticulationAfterIntegration(PxsContext* llContext, Bp::AABBManagerBase* aabbManager,
PxArray<Sc::BodySim*>& ccdBodies, PxBaseTask* continuation, IG::IslandSim& islandSim, float dt) PX_OVERRIDE;
};
}
}
#endif

View File

@@ -0,0 +1,304 @@
// 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.
#include "ScScene.h"
#include "ScArticulationSim.h"
#include "ScBodySim.h"
#include "ScActorSim.h"
#include "DyIslandManager.h"
#if PX_SUPPORT_GPU_PHYSX
#include "ScDeformableSurfaceSim.h"
#include "ScDeformableVolumeSim.h"
#include "ScParticleSystemSim.h"
#endif
#include "common/PxProfileZone.h"
using namespace physx;
using namespace Cm;
using namespace Dy;
using namespace Sc;
// PT: "setActive()" moved from ActorSim to BodySim because GPU classes silently re-implement this in a very different way (see below),
// i.e. it defeats the purpose of the virtual activate()/deactivate() functions.
void Sc::BodySim::setActive(bool active, bool asPartOfCreation)
{
PX_ASSERT(!active || isDynamicRigid()); // Currently there should be no need to activate an actor that does not take part in island generation
if(asPartOfCreation || isActive() != active)
{
PX_ASSERT(!asPartOfCreation || (getActorInteractionCount() == 0)); // On creation or destruction there should be no interactions
if(active)
{
if(!asPartOfCreation)
getScene().addToActiveList(*this); // Inactive => Active
activate();
PX_ASSERT(asPartOfCreation || isActive());
}
else
{
if(!asPartOfCreation)
getScene().removeFromActiveList(*this); // Active => Inactive
deactivate();
PX_ASSERT(asPartOfCreation || (!isActive()));
}
}
}
void Sc::ArticulationSim::setActive(bool b, bool asPartOfCreation)
{
const PxReal wakeCounter = mCore.getWakeCounter();
const PxU32 nbBodies = mBodies.size();
for(PxU32 i=0;i<nbBodies;i++)
{
if(i+1 < nbBodies)
{
PxPrefetchLine(mBodies[i+1],0);
PxPrefetchLine(mBodies[i+1],128);
}
//KS - force in the wake counter from the articulation to its links. This is required because
//GPU articulation simulation does not DMA back wake counters for each link - it just brings back a global wake counter
mBodies[i]->getBodyCore().setWakeCounterFromSim(wakeCounter);
mBodies[i]->setActive(b, asPartOfCreation);
}
}
// PT: moving all the sleeping-related implementations to the same file clearly exposes the inconsistencies between them
#if PX_SUPPORT_GPU_PHYSX
void Sc::ParticleSystemSim::setActive(bool /*active*/, bool /*asPartOfCreation*/)
{
}
void Sc::DeformableSurfaceSim::activate()
{
mScene.getSimulationController()->activateCloth(mLLDeformableSurface);
activateInteractions(*this);
}
void Sc::DeformableSurfaceSim::deactivate()
{
mScene.getSimulationController()->deactivateCloth(mLLDeformableSurface);
deactivateInteractions(*this);
}
void Sc::DeformableSurfaceSim::setActive(bool active, bool /*asPartOfCreation*/)
{
if(active)
activate();
else
deactivate();
}
void Sc::DeformableVolumeSim::setActive(bool active, bool /*asPartOfCreation*/)
{
if(active)
getScene().getSimulationController()->activateSoftbody(mLLDeformableVolume);
else
getScene().getSimulationController()->deactivateSoftbody(mLLDeformableVolume);
}
#endif
namespace
{
struct GetRigidSim { static PX_FORCE_INLINE BodySim* getSim(const IG::Node& node) { return reinterpret_cast<BodySim*>(reinterpret_cast<PxU8*>(node.mObject) - BodySim::getRigidBodyOffset()); } };
struct GetArticSim { static PX_FORCE_INLINE ArticulationSim* getSim(const IG::Node& node) { return reinterpret_cast<ArticulationSim*>(getObjectFromIG<FeatherstoneArticulation>(node)->getUserData()); } };
#if PX_SUPPORT_GPU_PHYSX
struct GetDeformableSurfaceSim { static PX_FORCE_INLINE DeformableSurfaceSim* getSim(const IG::Node& node) { return getObjectFromIG<DeformableSurface>(node)->getSim(); } };
struct GetDeformableVolumeSim { static PX_FORCE_INLINE DeformableVolumeSim* getSim(const IG::Node& node) { return getObjectFromIG<DeformableVolume>(node)->getSim(); } };
#endif
}
template<class SimT, class SimAccessT, const bool active>
static void setActive(PxU32& nbModified, const IG::IslandSim& islandSim, IG::Node::NodeType type)
{
PxU32 nbToProcess = active ? islandSim.getNbNodesToActivate(type) : islandSim.getNbNodesToDeactivate(type);
const PxNodeIndex* indices = active ? islandSim.getNodesToActivate(type) : islandSim.getNodesToDeactivate(type);
while(nbToProcess--)
{
const IG::Node& node = islandSim.getNode(*indices++);
PX_ASSERT(node.mType == type);
if((!!node.isActive())==active)
{
SimT* sim = SimAccessT::getSim(node);
if(sim)
{
sim->setActive(active);
nbModified++;
}
}
}
}
#ifdef BATCHED
namespace
{
struct SetActiveRigidSim
{
template<const bool active>
static void setActive(Scene& /*scene*/, PxU32 nbObjects, BodySim** objects)
{
if(1)
{
while(nbObjects--)
{
(*objects)->setActive(active);
objects++;
}
}
else
{
if(active)
{
// scene.addToActiveList(*this);
// activate();
// PX_ASSERT(isActive());
}
else
{
// scene.removeFromActiveList(*this);
// deactivate();
// PX_ASSERT(!isActive());
}
}
}
};
}
template<class SimT, class SimAccessT, class SetActiveBatchedT, const bool active>
static void setActiveBatched(Scene& scene, PxU32& nbModified, const IG::IslandSim& islandSim, IG::Node::NodeType type)
{
PxU32 nbToProcess = active ? islandSim.getNbNodesToActivate(type) : islandSim.getNbNodesToDeactivate(type);
const PxNodeIndex* indices = active ? islandSim.getNodesToActivate(type) : islandSim.getNodesToDeactivate(type);
PX_ALLOCA(batch, SimT*, nbToProcess);
PxU32 nb = 0;
while(nbToProcess--)
{
const IG::Node& node = islandSim.getNode(*indices++);
PX_ASSERT(node.mType == type);
if(node.isActive()==active)
{
SimT* sim = SimAccessT::getSim(node);
if(sim && sim->isActive()!=active)
batch.mPointer[nb++] = sim;
}
}
SetActiveBatchedT::setActive<active>(scene, nb, batch.mPointer);
nbModified = nb;
}
/*
Batched version would be just:
a) addToActiveList(batched objects)
b) activate(batched objects)
void Sc::ActorSim::setActive(bool active)
{
PX_ASSERT(!active || isDynamicRigid()); // Currently there should be no need to activate an actor that does not take part in island generation
if(isActive() != active)
{
if(active)
{
// Inactive => Active
getScene().addToActiveList(*this);
activate();
PX_ASSERT(isActive());
}
else
{
// Active => Inactive
getScene().removeFromActiveList(*this);
deactivate();
PX_ASSERT(!isActive());
}
}
}
*/
#endif
void Sc::Scene::putObjectsToSleep()
{
PX_PROFILE_ZONE("Sc::Scene::putObjectsToSleep", mContextId);
//Set to sleep all bodies that were in awake islands that have just been put to sleep.
const IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim();
PxU32 nbBodiesDeactivated = 0;
//setActiveBatched<BodySim, GetRigidSim, SetActiveRigidSim, false>(*this, nbBodiesDeactivated, islandSim, IG::Node::eRIGID_BODY_TYPE);
setActive<BodySim, GetRigidSim, false>(nbBodiesDeactivated, islandSim, IG::Node::eRIGID_BODY_TYPE);
setActive<ArticulationSim, GetArticSim, false>(nbBodiesDeactivated, islandSim, IG::Node::eARTICULATION_TYPE);
#if PX_SUPPORT_GPU_PHYSX
setActive<DeformableSurfaceSim, GetDeformableSurfaceSim, false>(nbBodiesDeactivated, islandSim, IG::Node::eDEFORMABLE_SURFACE_TYPE);
setActive<DeformableVolumeSim, GetDeformableVolumeSim, false>(nbBodiesDeactivated, islandSim, IG::Node::eDEFORMABLE_VOLUME_TYPE);
#endif
if(nbBodiesDeactivated)
mDynamicsContext->setStateDirty(true);
}
void Sc::Scene::wakeObjectsUp()
{
PX_PROFILE_ZONE("Sc::Scene::wakeObjectsUp", mContextId);
//Wake up all bodies that were in sleeping islands that have just been hit by a moving object.
const IG::IslandSim& islandSim = mSimpleIslandManager->getAccurateIslandSim();
PxU32 nbBodiesWoken = 0;
setActive<BodySim, GetRigidSim, true>(nbBodiesWoken, islandSim, IG::Node::eRIGID_BODY_TYPE);
setActive<ArticulationSim, GetArticSim, true>(nbBodiesWoken, islandSim, IG::Node::eARTICULATION_TYPE);
#if PX_SUPPORT_GPU_PHYSX
setActive<DeformableSurfaceSim, GetDeformableSurfaceSim, true>(nbBodiesWoken, islandSim, IG::Node::eDEFORMABLE_SURFACE_TYPE);
setActive<DeformableVolumeSim, GetDeformableVolumeSim, true>(nbBodiesWoken, islandSim, IG::Node::eDEFORMABLE_VOLUME_TYPE);
#endif
if(nbBodiesWoken)
mDynamicsContext->setStateDirty(true);
}

View File

@@ -0,0 +1,329 @@
// 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.
#include "GuPrunerTypedef.h"
#include "ScSqBoundsManager.h"
#include "ScBodySim.h"
#include "ScShapeSim.h"
#include "ScSqBoundsSync.h"
#include "common/PxProfileZone.h"
using namespace physx;
using namespace Sc;
#define INVALID_REF ScPrunerHandle(Gu::INVALID_PRUNERHANDLE)
SqBoundsManager0::SqBoundsManager0() :
mShapes ("SqBoundsManager::mShapes"),
mRefs ("SqBoundsManager::mRefs"),
mBoundsIndices ("SqBoundsManager::mBoundsIndices"),
mRefless ("SqBoundsManager::mRefless")
{
}
void SqBoundsManager0::addSyncShape(ShapeSimBase& shape)
{
PX_ASSERT(shape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE);
PX_ASSERT(!shape.getBodySim()->usingSqKinematicTarget());
PX_ASSERT(!shape.getBodySim()->isFrozen());
const PxU32 id = mShapes.size();
PX_ASSERT(id == mRefs.size());
PX_ASSERT(id == mBoundsIndices.size());
shape.setSqBoundsId(id);
// PT: mShapes / mRefs / mBoundsIndices are "parallel arrays". These arrays are persistent.
// mRefless is temporary/transient data to help populate mRefs each frame.
// mRefs / mBoundsIndices will be ultimately passed to updateObjects, whose API dictates the layout here.
// mShapes is not actually used for the sync, it's only here to be able to call setSqBoundsId in removeShape.
mShapes.pushBack(static_cast<Sc::ShapeSim*>(&shape));
mRefs.pushBack(INVALID_REF);
mBoundsIndices.pushBack(shape.getElementID());
mRefless.pushBack(static_cast<Sc::ShapeSim*>(&shape));
}
void SqBoundsManager0::removeSyncShape(ShapeSimBase& shape)
{
const PxU32 id = shape.getSqBoundsId();
PX_ASSERT(id!=PX_INVALID_U32);
shape.setSqBoundsId(PX_INVALID_U32);
mShapes[id] = mShapes.back();
mBoundsIndices[id] = mBoundsIndices.back();
mRefs[id] = mRefs.back();
if(id+1 != mShapes.size())
mShapes[id]->setSqBoundsId(id);
mShapes.popBack();
mRefs.popBack();
mBoundsIndices.popBack();
}
void SqBoundsManager0::syncBounds(SqBoundsSync& sync, SqRefFinder& finder, const PxBounds3* bounds, const PxTransform32* transforms, PxU64 contextID, const PxBitMap& ignoredIndices)
{
PX_PROFILE_ZONE("Sim.sceneQuerySyncBounds", contextID);
PX_UNUSED(contextID);
#if PX_DEBUG
for(PxU32 i=0;i<mShapes.size();i++)
{
const ShapeSimBase& shape = *mShapes[i];
PX_UNUSED(shape);
PX_ASSERT(shape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE);
PX_ASSERT(!shape.getBodySim()->usingSqKinematicTarget());
PX_ASSERT(!shape.getBodySim()->isFrozen());
}
#endif
ShapeSimBase*const * shapes = mRefless.begin();
for(PxU32 i=0, size = mRefless.size();i<size;i++)
{
const PxU32 id = shapes[i]->getSqBoundsId();
// PT:
//
// If id == PX_INVALID_U32, the shape has been removed and not re-added. Nothing to do in this case, we just ignore it.
// This case didn't previously exist since mRefless only contained valid (added) shapes. But now we left removed shapes in the
// structure, and these have an id == PX_INVALID_U32.
//
// Now if the id is valid but mRefs[id] == PX_INVALID_U32, this is a regular shape that has been added and not processed yet.
// So we process it.
//
// Finally, if both id and mRefs[id] are not PX_INVALID_U32, this is a shape that has been added, removed, and re-added. The
// array contains the same shape twice and we only need to process it once.
if(id!=PX_INVALID_U32)
{
if(mRefs[id] == INVALID_REF)
{
PxU32 prunerIndex = 0xffffffff;
mRefs[id] = finder.find(static_cast<PxRigidBody*>(shapes[i]->getBodySim()->getPxActor()), shapes[i]->getPxShape(), prunerIndex);
PX_ASSERT(prunerIndex==1);
}
}
}
mRefless.clear();
sync.sync(1, mRefs.begin(), mBoundsIndices.begin(), bounds, transforms, mShapes.size(), ignoredIndices);
}
// PT: we need to change the code so that the shape is added to the proper array during syncBounds, not during addSyncShape,
// because the pruner index is not known in addSyncShape. We could perhaps call the ref-finder directly in addSyncShape, but
// it would impose an order on the calls (the shape would need to be added to the pruners before addSyncShape is called. There's
// no such requirement with the initial code).
//
// Instead we do this:
// - in addSyncShape we just add the shape to a "waiting room", that's all.
// - adding the shape to the proper array is delayed until syncBounds. That way the prunerIndex will be available. Also we could
// then take advantage of batching, since all shapes are processed/added at the same time.
// - the only catch is that we need to ensure the previous edge-cases are still properly handled, i.e. when a shape is added then
// removed before sync is called, etc.
//
SqBoundsManagerEx::SqBoundsManagerEx() :
mWaitingRoom ("SqBoundsManagerEx::mWaitingRoom"),
mPrunerSyncData (NULL),
mPrunerSyncDataSize (0)
{
}
SqBoundsManagerEx::~SqBoundsManagerEx()
{
const PxU32 nbToGo = mPrunerSyncDataSize;
for(PxU32 i=0;i<nbToGo;i++)
{
PrunerSyncData* psd = mPrunerSyncData[i];
PX_DELETE(psd);
}
PX_FREE(mPrunerSyncData);
}
void SqBoundsManagerEx::resize(PxU32 index)
{
PxU32 size = mPrunerSyncDataSize ? mPrunerSyncDataSize*2 : 64;
const PxU32 minSize = index+1;
if(minSize>size)
size = minSize*2;
PrunerSyncData** items = PX_ALLOCATE(PrunerSyncData*, size, "PrunerSyncData");
if(mPrunerSyncData)
PxMemCopy(items, mPrunerSyncData, mPrunerSyncDataSize*sizeof(PrunerSyncData*));
PxMemZero(items+mPrunerSyncDataSize, (size-mPrunerSyncDataSize)*sizeof(PrunerSyncData*));
PX_FREE(mPrunerSyncData);
mPrunerSyncData = items;
mPrunerSyncDataSize = size;
}
void SqBoundsManagerEx::addSyncShape(ShapeSimBase& shape)
{
PX_ASSERT(shape.getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE);
PX_ASSERT(!shape.getBodySim()->usingSqKinematicTarget());
PX_ASSERT(!shape.getBodySim()->isFrozen());
PX_ASSERT(shape.getSqBoundsId()==PX_INVALID_U32);
PX_ASSERT(shape.getSqPrunerIndex()==PX_INVALID_U32);
const PxU32 id = mWaitingRoom.size();
mWaitingRoom.pushBack(&shape);
shape.setSqBoundsId(id);
shape.setSqPrunerIndex(PX_INVALID_U32);
}
void SqBoundsManagerEx::removeSyncShape(ShapeSimBase& shape)
{
const PxU32 id = shape.getSqBoundsId();
const PxU32 prunerIndex = shape.getSqPrunerIndex();
PX_ASSERT(id!=PX_INVALID_U32);
shape.setSqBoundsId(PX_INVALID_U32);
shape.setSqPrunerIndex(PX_INVALID_U32);
if(prunerIndex==PX_INVALID_U32)
{
// PT: this shape is still in the waiting room
PX_ASSERT(mWaitingRoom[id]==&shape);
mWaitingRoom[id] = mWaitingRoom.back();
if(id+1 != mWaitingRoom.size())
mWaitingRoom[id]->setSqBoundsId(id);
mWaitingRoom.popBack();
}
else
{
// PT: this shape is active
PX_ASSERT(prunerIndex<mPrunerSyncDataSize);
PrunerSyncData* psd = mPrunerSyncData[prunerIndex];
PX_ASSERT(psd);
PX_ASSERT(psd->mShapes[id]==&shape);
psd->mShapes[id] = psd->mShapes.back();
psd->mBoundsIndices[id] = psd->mBoundsIndices.back();
psd->mRefs[id] = psd->mRefs.back();
if(id+1 != psd->mShapes.size())
psd->mShapes[id]->setSqBoundsId(id);
psd->mShapes.popBack();
psd->mBoundsIndices.popBack();
psd->mRefs.popBack();
if(!psd->mShapes.size())
{
PX_DELETE(psd);
mPrunerSyncData[prunerIndex] = NULL;
}
}
}
void SqBoundsManagerEx::syncBounds(SqBoundsSync& sync, SqRefFinder& finder, const PxBounds3* bounds, const PxTransform32* transforms, PxU64 contextID, const PxBitMap& ignoredIndices)
{
PX_PROFILE_ZONE("Sim.sceneQuerySyncBounds", contextID);
PX_UNUSED(contextID);
/*
#if PX_DEBUG
for(PxU32 i=0;i<mShapeData.size();i++)
{
const ShapeSQData& shape = mShapeData[i];
PX_UNUSED(shape);
PX_ASSERT(shape.mSim->getFlags() & PxShapeFlag::eSCENE_QUERY_SHAPE);
PX_ASSERT(!shape.mSim->getBodySim()->usingSqKinematicTarget());
PX_ASSERT(!shape.mSim->getBodySim()->isFrozen());
}
#endif
*/
const PxU32 nbToGo = mWaitingRoom.size();
if(nbToGo)
{
for(PxU32 i=0;i<nbToGo;i++)
{
ShapeSimBase* sim = mWaitingRoom[i];
PX_ASSERT(i==sim->getSqBoundsId());
PX_ASSERT(PX_INVALID_U32==sim->getSqPrunerIndex());
PxU32 prunerIndex = 0xffffffff;
const ScPrunerHandle prunerHandle = finder.find(static_cast<PxRigidBody*>(sim->getBodySim()->getPxActor()), sim->getPxShape(), prunerIndex);
PX_ASSERT(prunerIndex!=0xffffffff);
if(prunerIndex>=mPrunerSyncDataSize)
resize(prunerIndex);
PrunerSyncData* psd = mPrunerSyncData[prunerIndex];
if(!psd)
{
psd = PX_NEW(PrunerSyncData);
mPrunerSyncData[prunerIndex] = psd;
}
PxArray<ShapeSimBase*>& shapes = psd->mShapes;
PxArray<ScPrunerHandle>& refs = psd->mRefs;
PxArray<PxU32>& boundsIndices = psd->mBoundsIndices;
const PxU32 id = shapes.size();
PX_ASSERT(id == refs.size());
PX_ASSERT(id == boundsIndices.size());
sim->setSqBoundsId(id);
sim->setSqPrunerIndex(prunerIndex);
// PT: mShapes / mRefs / mBoundsIndices are "parallel arrays". These arrays are persistent.
// mRefless is temporary/transient data to help populate mRefs each frame.
// mRefs / mBoundsIndices will be ultimately passed to updateObjects, whose API dictates the layout here.
// mShapes is not actually used for the sync, it's only here to be able to call setSqBoundsId in removeShape.
shapes.pushBack(sim);
refs.pushBack(prunerHandle);
boundsIndices.pushBack(sim->getElementID());
}
mWaitingRoom.clear(); // PT: TODO: optimize wasted memory here
}
// PT: TODO: optimize this
{
const PxU32 nb = mPrunerSyncDataSize;
for(PxU32 i=0;i<nb;i++)
{
PrunerSyncData* psd = mPrunerSyncData[i];
if(psd)
sync.sync(i, psd->mRefs.begin(), psd->mBoundsIndices.begin(), bounds, transforms, psd->mRefs.size(), ignoredIndices);
}
}
}

View File

@@ -0,0 +1,106 @@
// 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_SQ_BOUNDS_MANAGER_H
#define SC_SQ_BOUNDS_MANAGER_H
#include "foundation/PxUserAllocated.h"
#include "foundation/PxBitMap.h"
#include "foundation/PxArray.h"
#include "ScSqBoundsSync.h"
namespace physx
{
class PxBounds3;
namespace Sc
{
struct SqBoundsSync;
struct SqRefFinder;
class ShapeSimBase;
class SqBoundsManager0 : public PxUserAllocated
{
PX_NOCOPY(SqBoundsManager0)
public:
SqBoundsManager0();
void addSyncShape(ShapeSimBase& shape);
void removeSyncShape(ShapeSimBase& shape);
void syncBounds(SqBoundsSync& sync, SqRefFinder& finder, const PxBounds3* bounds, const PxTransform32* transforms, PxU64 contextID, const PxBitMap& ignoredIndices);
private:
PxArray<ShapeSimBase*> mShapes; //
PxArray<ScPrunerHandle> mRefs; // SQ pruner references
PxArray<PxU32> mBoundsIndices; // indices into the Sc bounds array
PxArray<ShapeSimBase*> mRefless; // shapesims without references
};
class SqBoundsManagerEx : public PxUserAllocated
{
PX_NOCOPY(SqBoundsManagerEx)
public:
SqBoundsManagerEx();
~SqBoundsManagerEx();
void addSyncShape(ShapeSimBase& shape);
void removeSyncShape(ShapeSimBase& shape);
void syncBounds(SqBoundsSync& sync, SqRefFinder& finder, const PxBounds3* bounds, const PxTransform32* transforms, PxU64 contextID, const PxBitMap& ignoredIndices);
private:
PxArray<ShapeSimBase*> mWaitingRoom;
// PT: one of the many solutions discussed in https://confluence.nvidia.com/display/~pterdiman/The+new+SQ+system
// Just to get something working. This will most likely need revisiting later.
struct PrunerSyncData : public PxUserAllocated
{
PxArray<ShapeSimBase*> mShapes; //
// PT: layout dictated by the SqPruner API here. We could consider merging these two arrays.
PxArray<ScPrunerHandle> mRefs; // SQ pruner references
PxArray<PxU32> mBoundsIndices; // indices into the Sc bounds array
};
PrunerSyncData** mPrunerSyncData;
PxU32 mPrunerSyncDataSize;
void resize(PxU32 index);
};
//class SqBoundsManager : public SqBoundsManager0
class SqBoundsManager : public SqBoundsManagerEx
{
public:
};
}
}
#endif

View File

@@ -0,0 +1,48 @@
// 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.
#include "ScStaticCore.h"
#include "ScStaticSim.h"
#include "PxRigidStatic.h"
using namespace physx;
Sc::StaticSim* Sc::StaticCore::getSim() const
{
return static_cast<StaticSim*>(Sc::ActorCore::getSim());
}
void Sc::StaticCore::setActor2World(const PxTransform& actor2World)
{
mCore.body2World = actor2World;
StaticSim* sim = getSim();
if(sim)
sim->notifyShapesOfTransformChange();
}

View File

@@ -0,0 +1,55 @@
// 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_STATIC_SIM_H
#define SC_STATIC_SIM_H
#include "ScRigidSim.h"
#include "ScStaticCore.h"
namespace physx
{
namespace Sc
{
class StaticSim : public RigidSim
{
//---------------------------------------------------------------------------------
// Construction, destruction & initialization
//---------------------------------------------------------------------------------
public:
StaticSim(Scene& scene, StaticCore& core) : RigidSim(scene, core) {}
~StaticSim() { getStaticCore().setSim(NULL); }
PX_FORCE_INLINE StaticCore& getStaticCore() const { return static_cast<StaticCore&>(getRigidCore()); }
};
} // namespace Sc
}
#endif

Some files were not shown because too many files have changed in this diff Show More