feat(physics): wire physx sdk into build
This commit is contained in:
197
engine/third_party/physx/source/physxcharacterkinematic/src/CctBoxController.cpp
vendored
Normal file
197
engine/third_party/physx/source/physxcharacterkinematic/src/CctBoxController.cpp
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// 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 "geometry/PxBoxGeometry.h"
|
||||
#include "characterkinematic/PxController.h"
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxShape.h"
|
||||
|
||||
#include "CctBoxController.h"
|
||||
#include "CctCharacterControllerManager.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
static PX_FORCE_INLINE PxVec3 CCTtoProxyExtents(PxF32 halfHeight, PxF32 halfSideExtent, PxF32 halfForwardExtent, PxF32 coeff)
|
||||
{
|
||||
// PT: because we now orient the box CCT using the same quat as for capsules...
|
||||
// i.e. the identity quat corresponds to a up dir = 1,0,0 (which is like the worst choice we could have made, of course)
|
||||
return PxVec3(halfHeight * coeff, halfSideExtent * coeff, halfForwardExtent * coeff);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
BoxController::BoxController(const PxControllerDesc& desc, PxPhysics& sdk, PxScene* s) : Controller(desc, s)
|
||||
{
|
||||
mType = PxControllerShapeType::eBOX;
|
||||
|
||||
const PxBoxControllerDesc& bc = static_cast<const PxBoxControllerDesc&>(desc);
|
||||
|
||||
mHalfHeight = bc.halfHeight;
|
||||
mHalfSideExtent = bc.halfSideExtent;
|
||||
mHalfForwardExtent = bc.halfForwardExtent;
|
||||
|
||||
// Create kinematic actor under the hood
|
||||
PxBoxGeometry boxGeom;
|
||||
boxGeom.halfExtents = CCTtoProxyExtents(bc.halfHeight, bc.halfSideExtent, bc.halfForwardExtent, mProxyScaleCoeff);
|
||||
|
||||
createProxyActor(sdk, boxGeom, *desc.material, desc.clientID);
|
||||
}
|
||||
|
||||
BoxController::~BoxController()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BoxController::invalidateCache()
|
||||
{
|
||||
if(mManager->mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
mCctModule.voidTestCache();
|
||||
|
||||
if(mManager->mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BoxController::getWorldBox(PxExtendedBounds3& box) const
|
||||
{
|
||||
setCenterExtents(box, mPosition, PxVec3(mHalfHeight, mHalfSideExtent, mHalfForwardExtent));
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxF32 BoxController::getHalfHeight() const
|
||||
{
|
||||
return mHalfHeight;
|
||||
}
|
||||
|
||||
PxF32 BoxController::getHalfSideExtent() const
|
||||
{
|
||||
return mHalfSideExtent;
|
||||
}
|
||||
|
||||
PxF32 BoxController::getHalfForwardExtent() const
|
||||
{
|
||||
return mHalfForwardExtent;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool BoxController::updateKinematicProxy()
|
||||
{
|
||||
// Set extents for kinematic proxy
|
||||
if(mKineActor)
|
||||
{
|
||||
PxShape* shape = getKineShape();
|
||||
|
||||
const PxGeometry& geom = shape->getGeometry();
|
||||
PX_ASSERT(geom.getType() == PxGeometryType::eBOX);
|
||||
PxBoxGeometry bg = static_cast<const PxBoxGeometry&>(geom);
|
||||
|
||||
bg.halfExtents = CCTtoProxyExtents(mHalfHeight, mHalfSideExtent, mHalfForwardExtent, mProxyScaleCoeff);
|
||||
shape->setGeometry(bg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BoxController::setHalfHeight(PxF32 halfHeight)
|
||||
{
|
||||
if(halfHeight<=0.0f)
|
||||
return false;
|
||||
|
||||
mHalfHeight = halfHeight;
|
||||
return updateKinematicProxy();
|
||||
}
|
||||
|
||||
bool BoxController::setHalfSideExtent(PxF32 halfSideExtent)
|
||||
{
|
||||
if(halfSideExtent<=0.0f)
|
||||
return false;
|
||||
|
||||
mHalfSideExtent = halfSideExtent;
|
||||
return updateKinematicProxy();
|
||||
}
|
||||
|
||||
bool BoxController::setHalfForwardExtent(PxF32 halfForwardExtent)
|
||||
{
|
||||
if(halfForwardExtent<=0.0f)
|
||||
return false;
|
||||
|
||||
mHalfForwardExtent = halfForwardExtent;
|
||||
return updateKinematicProxy();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxExtendedVec3 BoxController::getFootPosition() const
|
||||
{
|
||||
PxExtendedVec3 groundPosition = mPosition; // Middle of the CCT
|
||||
sub(groundPosition, mUserParams.mUpDirection * (mHalfHeight + mUserParams.mContactOffset)); // Ground
|
||||
return groundPosition;
|
||||
}
|
||||
|
||||
bool BoxController::setFootPosition(const PxExtendedVec3& position)
|
||||
{
|
||||
PxExtendedVec3 centerPosition = position;
|
||||
add(centerPosition, mUserParams.mUpDirection * (mHalfHeight + mUserParams.mContactOffset));
|
||||
return setPosition(centerPosition);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BoxController::getOBB(PxExtendedBox& obb) const
|
||||
{
|
||||
// PT: TODO: optimize this
|
||||
PxExtendedBounds3 worldBox;
|
||||
getWorldBox(worldBox);
|
||||
|
||||
getCenter(worldBox, obb.center);
|
||||
getExtents(worldBox, obb.extents);
|
||||
obb.rot = mUserParams.mQuatFromUp;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void BoxController::resize(PxReal height)
|
||||
{
|
||||
const float oldHeight = getHalfHeight();
|
||||
setHalfHeight(height);
|
||||
|
||||
const float delta = height - oldHeight;
|
||||
PxExtendedVec3 pos = getPosition();
|
||||
add(pos, mUserParams.mUpDirection * delta);
|
||||
setPosition(pos);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
112
engine/third_party/physx/source/physxcharacterkinematic/src/CctBoxController.h
vendored
Normal file
112
engine/third_party/physx/source/physxcharacterkinematic/src/CctBoxController.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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 CCT_BOX_CONTROLLER
|
||||
#define CCT_BOX_CONTROLLER
|
||||
|
||||
/* Exclude from documentation */
|
||||
/** \cond */
|
||||
|
||||
#include "characterkinematic/PxBoxController.h"
|
||||
|
||||
#include "CctController.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
class PxPhysics;
|
||||
|
||||
namespace Cct
|
||||
{
|
||||
|
||||
class BoxController : public PxBoxController, public Controller
|
||||
{
|
||||
public:
|
||||
BoxController(const PxControllerDesc& desc, PxPhysics& sdk, PxScene* scene);
|
||||
virtual ~BoxController();
|
||||
|
||||
// Controller
|
||||
virtual PxF32 getHalfHeightInternal() const PX_OVERRIDE PX_FINAL { return mHalfHeight; }
|
||||
virtual bool getWorldBox(PxExtendedBounds3& box) const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxController* getPxController() PX_OVERRIDE PX_FINAL { return this; }
|
||||
//~Controller
|
||||
|
||||
// PxController
|
||||
virtual PxControllerShapeType::Enum getType() const PX_OVERRIDE PX_FINAL { return mType; }
|
||||
virtual void release() PX_OVERRIDE PX_FINAL { releaseInternal(); }
|
||||
virtual PxControllerCollisionFlags move(const PxVec3& disp, PxF32 minDist, PxF32 elapsedTime, const PxControllerFilters& filters, const PxObstacleContext* obstacles) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setPosition(const PxExtendedVec3& position) PX_OVERRIDE PX_FINAL { return setPos(position); }
|
||||
virtual const PxExtendedVec3& getPosition() const PX_OVERRIDE PX_FINAL { return mPosition; }
|
||||
virtual bool setFootPosition(const PxExtendedVec3& position) PX_OVERRIDE PX_FINAL;
|
||||
virtual PxExtendedVec3 getFootPosition() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxRigidDynamic* getActor() const PX_OVERRIDE PX_FINAL { return mKineActor; }
|
||||
virtual void setStepOffset(const float offset) PX_OVERRIDE PX_FINAL { if(offset>=0.0f)
|
||||
mUserParams.mStepOffset = offset; }
|
||||
virtual PxF32 getStepOffset() const PX_OVERRIDE PX_FINAL { return mUserParams.mStepOffset; }
|
||||
virtual void setNonWalkableMode(PxControllerNonWalkableMode::Enum flag) PX_OVERRIDE PX_FINAL { mUserParams.mNonWalkableMode = flag; }
|
||||
virtual PxControllerNonWalkableMode::Enum getNonWalkableMode() const PX_OVERRIDE PX_FINAL { return mUserParams.mNonWalkableMode; }
|
||||
virtual PxF32 getContactOffset() const PX_OVERRIDE PX_FINAL { return mUserParams.mContactOffset; }
|
||||
virtual void setContactOffset(PxF32 offset) PX_OVERRIDE PX_FINAL { if(offset>0.0f)
|
||||
mUserParams.mContactOffset = offset;}
|
||||
virtual PxVec3 getUpDirection() const PX_OVERRIDE PX_FINAL { return mUserParams.mUpDirection; }
|
||||
virtual void setUpDirection(const PxVec3& up) PX_OVERRIDE PX_FINAL { setUpDirectionInternal(up); }
|
||||
virtual PxF32 getSlopeLimit() const PX_OVERRIDE PX_FINAL { return mUserParams.mSlopeLimit; }
|
||||
virtual void setSlopeLimit(PxF32 slopeLimit) PX_OVERRIDE PX_FINAL { if(slopeLimit>0.0f)
|
||||
mUserParams.mSlopeLimit = slopeLimit;}
|
||||
virtual void invalidateCache();
|
||||
virtual PxScene* getScene() PX_OVERRIDE PX_FINAL { return mScene; }
|
||||
virtual void* getUserData() const PX_OVERRIDE PX_FINAL { return mUserData; }
|
||||
virtual void setUserData(void* userData) PX_OVERRIDE PX_FINAL { mUserData = userData; }
|
||||
virtual void getState(PxControllerState& state) const PX_OVERRIDE PX_FINAL { return getInternalState(state); }
|
||||
virtual void getStats(PxControllerStats& stats) const PX_OVERRIDE PX_FINAL { return getInternalStats(stats); }
|
||||
virtual void resize(PxReal height);
|
||||
//~PxController
|
||||
|
||||
// PxBoxController
|
||||
virtual PxF32 getHalfHeight() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxF32 getHalfSideExtent() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxF32 getHalfForwardExtent() const PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setHalfHeight(PxF32 halfHeight) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setHalfSideExtent(PxF32 halfSideExtent) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setHalfForwardExtent(PxF32 halfForwardExtent) PX_OVERRIDE PX_FINAL;
|
||||
//~ PxBoxController
|
||||
|
||||
PxF32 mHalfHeight;
|
||||
PxF32 mHalfSideExtent;
|
||||
PxF32 mHalfForwardExtent;
|
||||
|
||||
bool updateKinematicProxy();
|
||||
void getOBB(PxExtendedBox& obb) const;
|
||||
};
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
/** \endcond */
|
||||
#endif
|
||||
191
engine/third_party/physx/source/physxcharacterkinematic/src/CctCapsuleController.cpp
vendored
Normal file
191
engine/third_party/physx/source/physxcharacterkinematic/src/CctCapsuleController.cpp
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
// 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 "geometry/PxCapsuleGeometry.h"
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxShape.h"
|
||||
#include "characterkinematic/PxController.h"
|
||||
#include "CctCapsuleController.h"
|
||||
#include "CctCharacterControllerManager.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
static PX_FORCE_INLINE float CCTtoProxyRadius(float r, PxF32 coeff) { return r * coeff; }
|
||||
static PX_FORCE_INLINE float CCTtoProxyHeight(float h, PxF32 coeff) { return 0.5f * h * coeff; }
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CapsuleController::CapsuleController(const PxControllerDesc& desc, PxPhysics& sdk, PxScene* s) : Controller(desc, s)
|
||||
{
|
||||
mType = PxControllerShapeType::eCAPSULE;
|
||||
|
||||
const PxCapsuleControllerDesc& cc = static_cast<const PxCapsuleControllerDesc&>(desc);
|
||||
|
||||
mRadius = cc.radius;
|
||||
mHeight = cc.height;
|
||||
mClimbingMode = cc.climbingMode;
|
||||
|
||||
// Create kinematic actor under the hood
|
||||
PxCapsuleGeometry capsGeom;
|
||||
capsGeom.radius = CCTtoProxyRadius(cc.radius, mProxyScaleCoeff);
|
||||
capsGeom.halfHeight = CCTtoProxyHeight(cc.height, mProxyScaleCoeff);
|
||||
|
||||
createProxyActor(sdk, capsGeom, *desc.material, desc.clientID);
|
||||
}
|
||||
|
||||
CapsuleController::~CapsuleController()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CapsuleController::invalidateCache()
|
||||
{
|
||||
if(mManager->mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
mCctModule.voidTestCache();
|
||||
|
||||
if(mManager->mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CapsuleController::getWorldBox(PxExtendedBounds3& box) const
|
||||
{
|
||||
setCenterExtents(box, mPosition, PxVec3(mRadius, mRadius+mHeight*0.5f, mRadius));
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CapsuleController::setRadius(PxF32 r)
|
||||
{
|
||||
// Set radius for CCT volume
|
||||
mRadius = r;
|
||||
|
||||
// Set radius for kinematic proxy
|
||||
if(mKineActor)
|
||||
{
|
||||
PxShape* shape = getKineShape();
|
||||
|
||||
const PxGeometry& geom = shape->getGeometry();
|
||||
PX_ASSERT(geom.getType() == PxGeometryType::eCAPSULE);
|
||||
PxCapsuleGeometry cg = static_cast<const PxCapsuleGeometry&>(geom);
|
||||
|
||||
cg.radius = CCTtoProxyRadius(r, mProxyScaleCoeff);
|
||||
shape->setGeometry(cg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CapsuleController::setHeight(PxF32 h)
|
||||
{
|
||||
// Set height for CCT volume
|
||||
mHeight = h;
|
||||
|
||||
// Set height for kinematic proxy
|
||||
if(mKineActor)
|
||||
{
|
||||
PxShape* shape = getKineShape();
|
||||
|
||||
const PxGeometry& geom = shape->getGeometry();
|
||||
PX_ASSERT(geom.getType() == PxGeometryType::eCAPSULE);
|
||||
PxCapsuleGeometry cg = static_cast<const PxCapsuleGeometry&>(geom);
|
||||
|
||||
cg.halfHeight = CCTtoProxyHeight(h, mProxyScaleCoeff);
|
||||
shape->setGeometry(cg);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxCapsuleClimbingMode::Enum CapsuleController::getClimbingMode() const
|
||||
{
|
||||
return mClimbingMode;
|
||||
}
|
||||
|
||||
bool CapsuleController::setClimbingMode(PxCapsuleClimbingMode::Enum mode)
|
||||
{
|
||||
if(mode>=PxCapsuleClimbingMode::eLAST)
|
||||
return false;
|
||||
mClimbingMode = mode;
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxExtendedVec3 CapsuleController::getFootPosition() const
|
||||
{
|
||||
PxExtendedVec3 groundPosition = mPosition; // Middle of the CCT
|
||||
sub(groundPosition, mUserParams.mUpDirection * (mUserParams.mContactOffset+mRadius+mHeight*0.5f)); // Ground
|
||||
return groundPosition;
|
||||
}
|
||||
|
||||
bool CapsuleController::setFootPosition(const PxExtendedVec3& position)
|
||||
{
|
||||
PxExtendedVec3 centerPosition = position;
|
||||
add(centerPosition, mUserParams.mUpDirection * (mUserParams.mContactOffset+mRadius+mHeight*0.5f));
|
||||
return setPosition(centerPosition);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CapsuleController::getCapsule(PxExtendedCapsule& capsule) const
|
||||
{
|
||||
// PT: TODO: optimize this
|
||||
PxExtendedVec3 p0 = mPosition;
|
||||
PxExtendedVec3 p1 = mPosition;
|
||||
const PxVec3 extents = mUserParams.mUpDirection*mHeight*0.5f;
|
||||
sub(p0, extents);
|
||||
add(p1, extents);
|
||||
|
||||
capsule.p0 = p0;
|
||||
capsule.p1 = p1;
|
||||
capsule.radius = mRadius;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CapsuleController::resize(PxReal height)
|
||||
{
|
||||
const float oldHeight = getHeight();
|
||||
setHeight(height);
|
||||
|
||||
const float delta = height - oldHeight;
|
||||
PxExtendedVec3 pos = getPosition();
|
||||
add(pos, mUserParams.mUpDirection * delta * 0.5f);
|
||||
setPosition(pos);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
109
engine/third_party/physx/source/physxcharacterkinematic/src/CctCapsuleController.h
vendored
Normal file
109
engine/third_party/physx/source/physxcharacterkinematic/src/CctCapsuleController.h
vendored
Normal 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.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef CCT_CAPSULE_CONTROLLER
|
||||
#define CCT_CAPSULE_CONTROLLER
|
||||
|
||||
/* Exclude from documentation */
|
||||
/** \cond */
|
||||
|
||||
#include "characterkinematic/PxCapsuleController.h"
|
||||
|
||||
#include "CctController.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxPhysics;
|
||||
|
||||
namespace Cct
|
||||
{
|
||||
class CapsuleController : public PxCapsuleController, public Controller
|
||||
{
|
||||
public:
|
||||
CapsuleController(const PxControllerDesc& desc, PxPhysics& sdk, PxScene* scene);
|
||||
virtual ~CapsuleController();
|
||||
|
||||
// Controller
|
||||
virtual PxF32 getHalfHeightInternal() const PX_OVERRIDE PX_FINAL { return mRadius+mHeight*0.5f; }
|
||||
virtual bool getWorldBox(PxExtendedBounds3& box) const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxController* getPxController() PX_OVERRIDE PX_FINAL { return this; }
|
||||
//~Controller
|
||||
|
||||
// PxController
|
||||
virtual PxControllerShapeType::Enum getType() const PX_OVERRIDE PX_FINAL { return mType; }
|
||||
virtual void release() PX_OVERRIDE PX_FINAL { releaseInternal(); }
|
||||
virtual PxControllerCollisionFlags move(const PxVec3& disp, PxF32 minDist, PxF32 elapsedTime, const PxControllerFilters& filters, const PxObstacleContext* obstacles) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setPosition(const PxExtendedVec3& position) PX_OVERRIDE PX_FINAL { return setPos(position); }
|
||||
virtual const PxExtendedVec3& getPosition() const PX_OVERRIDE PX_FINAL { return mPosition; }
|
||||
virtual bool setFootPosition(const PxExtendedVec3& position) PX_OVERRIDE PX_FINAL;
|
||||
virtual PxExtendedVec3 getFootPosition() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxRigidDynamic* getActor() const PX_OVERRIDE PX_FINAL { return mKineActor; }
|
||||
virtual void setStepOffset(const float offset) PX_OVERRIDE PX_FINAL { if(offset>=0.0f)
|
||||
mUserParams.mStepOffset = offset; }
|
||||
virtual PxF32 getStepOffset() const PX_OVERRIDE PX_FINAL { return mUserParams.mStepOffset; }
|
||||
virtual void setNonWalkableMode(PxControllerNonWalkableMode::Enum flag) PX_OVERRIDE PX_FINAL { mUserParams.mNonWalkableMode = flag; }
|
||||
virtual PxControllerNonWalkableMode::Enum getNonWalkableMode() const PX_OVERRIDE PX_FINAL { return mUserParams.mNonWalkableMode; }
|
||||
virtual PxF32 getContactOffset() const PX_OVERRIDE PX_FINAL { return mUserParams.mContactOffset; }
|
||||
virtual void setContactOffset(PxF32 offset) PX_OVERRIDE PX_FINAL { if(offset>0.0f)
|
||||
mUserParams.mContactOffset = offset;}
|
||||
virtual PxVec3 getUpDirection() const PX_OVERRIDE PX_FINAL { return mUserParams.mUpDirection; }
|
||||
virtual void setUpDirection(const PxVec3& up) PX_OVERRIDE PX_FINAL { setUpDirectionInternal(up); }
|
||||
virtual PxF32 getSlopeLimit() const PX_OVERRIDE PX_FINAL { return mUserParams.mSlopeLimit; }
|
||||
virtual void setSlopeLimit(PxF32 slopeLimit) PX_OVERRIDE PX_FINAL { if(slopeLimit>0.0f)
|
||||
mUserParams.mSlopeLimit = slopeLimit;}
|
||||
virtual void invalidateCache() PX_OVERRIDE PX_FINAL;
|
||||
virtual PxScene* getScene() PX_OVERRIDE PX_FINAL { return mScene; }
|
||||
virtual void* getUserData() const PX_OVERRIDE PX_FINAL { return mUserData; }
|
||||
virtual void setUserData(void* userData) PX_OVERRIDE PX_FINAL { mUserData = userData; }
|
||||
virtual void getState(PxControllerState& state) const PX_OVERRIDE PX_FINAL { return getInternalState(state); }
|
||||
virtual void getStats(PxControllerStats& stats) const PX_OVERRIDE PX_FINAL { return getInternalStats(stats); }
|
||||
virtual void resize(PxReal height) PX_OVERRIDE PX_FINAL;
|
||||
//~PxController
|
||||
|
||||
// PxCapsuleController
|
||||
virtual PxF32 getRadius() const PX_OVERRIDE PX_FINAL { return mRadius; }
|
||||
virtual PxF32 getHeight() const PX_OVERRIDE PX_FINAL { return mHeight; }
|
||||
virtual PxCapsuleClimbingMode::Enum getClimbingMode() const PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setRadius(PxF32 radius) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setHeight(PxF32 height) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool setClimbingMode(PxCapsuleClimbingMode::Enum) PX_OVERRIDE PX_FINAL;
|
||||
//~ PxCapsuleController
|
||||
|
||||
void getCapsule(PxExtendedCapsule& capsule) const;
|
||||
|
||||
PxF32 mRadius;
|
||||
PxF32 mHeight;
|
||||
PxCapsuleClimbingMode::Enum mClimbingMode;
|
||||
};
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
/** \endcond */
|
||||
#endif
|
||||
2622
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterController.cpp
vendored
Normal file
2622
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterController.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
474
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterController.h
vendored
Normal file
474
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterController.h
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
// 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 CCT_CHARACTER_CONTROLLER
|
||||
#define CCT_CHARACTER_CONTROLLER
|
||||
|
||||
//#define USE_CONTACT_NORMAL_FOR_SLOPE_TEST
|
||||
|
||||
#include "geometry/PxTriangle.h"
|
||||
#include "foundation/PxHashSet.h"
|
||||
#include "characterkinematic/PxController.h"
|
||||
#include "characterkinematic/PxControllerObstacles.h"
|
||||
#include "CctCharacterControllerManager.h"
|
||||
#include "CctUtils.h"
|
||||
#include "foundation/PxArray.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
struct PxFilterData;
|
||||
class PxQueryFilterCallback;
|
||||
class PxObstacle;
|
||||
class RenderBuffer;
|
||||
|
||||
namespace Cct
|
||||
{
|
||||
struct CCTParams
|
||||
{
|
||||
CCTParams();
|
||||
|
||||
PxControllerNonWalkableMode::Enum mNonWalkableMode;
|
||||
PxQuat mQuatFromUp;
|
||||
PxVec3 mUpDirection;
|
||||
PxF32 mSlopeLimit;
|
||||
PxF32 mContactOffset;
|
||||
PxF32 mStepOffset;
|
||||
PxF32 mInvisibleWallHeight;
|
||||
PxF32 mMaxJumpHeight;
|
||||
PxF32 mMaxEdgeLength2;
|
||||
bool mTessellation;
|
||||
bool mHandleSlope; // True to handle walkable parts according to slope
|
||||
bool mOverlapRecovery;
|
||||
bool mPreciseSweeps;
|
||||
bool mPreventVerticalSlidingAgainstCeiling;
|
||||
};
|
||||
|
||||
// typedef PxArray<PxTriangle> TriArray;
|
||||
typedef PxArray<PxU32> IntArray;
|
||||
|
||||
// PT: using private inheritance to control access, and make sure allocations are SIMD friendly
|
||||
class TriArray : private PxArray<PxTriangle>
|
||||
{
|
||||
public:
|
||||
|
||||
PX_FORCE_INLINE PxTriangle* reserve(PxU32 nbTris)
|
||||
{
|
||||
// PT: customized version of "reserveContainerMemory"
|
||||
|
||||
const PxU32 maxNbEntries = PxArray<PxTriangle>::capacity();
|
||||
const PxU32 realRequiredSize = PxArray<PxTriangle>::size() + nbTris;
|
||||
// PT: allocate one more tri to make sure we can safely V4Load the last one...
|
||||
const PxU32 requiredSize = realRequiredSize + 1;
|
||||
|
||||
if(requiredSize>maxNbEntries)
|
||||
{
|
||||
// PT: ok so the commented out growing policy was introduced by PX-837 but it produces
|
||||
// large memory usage regressions (see PX-881) while not actually making things run
|
||||
// faster. Our benchmarks show no performance difference, but up to +38% more memory
|
||||
// used with this "standard" growing policy. So for now we just go back to the initial
|
||||
// growing policy. It should be fine since PX-837 was not actually reported by a customer,
|
||||
// it was just a concern that appeared while looking at the code. Ideally we'd use a pool
|
||||
// with fixed-size slabs to get the best of both worlds but it would make iterating over
|
||||
// triangles more complicated and would need more refactoring. So for now we don't bother,
|
||||
// but we'll keep this note here for the next time this problem shows up.
|
||||
// PT: new August 2018: turns out PX-837 was correct. Not doing this produces very large
|
||||
// performance problems (like: the app freezes!) in SampleCCT. We didn't see it because
|
||||
// it's an internal sample that it rarely used these days...
|
||||
const PxU32 naturalGrowthSize = maxNbEntries ? maxNbEntries*2 : 2;
|
||||
const PxU32 newSize = PxMax(requiredSize, naturalGrowthSize);
|
||||
// const PxU32 newSize = requiredSize;
|
||||
|
||||
PxArray<PxTriangle>::reserve(newSize);
|
||||
}
|
||||
|
||||
PxTriangle* buf = PxArray<PxTriangle>::end();
|
||||
// ...but we still want the size to reflect the correct number
|
||||
PxArray<PxTriangle>::forceSize_Unsafe(realRequiredSize);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void pushBack(const PxTriangle& tri)
|
||||
{
|
||||
PxTriangle* memory = reserve(1);
|
||||
memory->verts[0] = tri.verts[0];
|
||||
memory->verts[1] = tri.verts[1];
|
||||
memory->verts[2] = tri.verts[2];
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxU32 size() const
|
||||
{
|
||||
return PxArray<PxTriangle>::size();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const PxTriangle* begin() const
|
||||
{
|
||||
return PxArray<PxTriangle>::begin();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void clear()
|
||||
{
|
||||
PxArray<PxTriangle>::clear();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void forceSize_Unsafe(PxU32 size)
|
||||
{
|
||||
PxArray<PxTriangle>::forceSize_Unsafe(size);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const PxTriangle& getTriangle(PxU32 index) const
|
||||
{
|
||||
return (*this)[index];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Exclude from documentation */
|
||||
/** \cond */
|
||||
|
||||
struct TouchedGeomType
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
eUSER_BOX,
|
||||
eUSER_CAPSULE,
|
||||
eMESH,
|
||||
eBOX,
|
||||
eSPHERE,
|
||||
eCAPSULE,
|
||||
eCUSTOM,
|
||||
|
||||
eLAST,
|
||||
|
||||
eFORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
};
|
||||
|
||||
class SweptVolume;
|
||||
|
||||
struct TouchedGeom
|
||||
{
|
||||
TouchedGeomType::Enum mType;
|
||||
const void* mTGUserData; // PxController or PxShape pointer
|
||||
const PxRigidActor* mActor; // PxActor for PxShape pointers (mandatory with shared shapes)
|
||||
PxExtendedVec3 mOffset; // Local origin, typically the center of the world bounds around the character. We translate both
|
||||
// touched shapes & the character so that they are nearby this PxVec3, then add the offset back to
|
||||
// computed "world" impacts.
|
||||
protected:
|
||||
~TouchedGeom(){}
|
||||
};
|
||||
|
||||
struct TouchedUserBox : public TouchedGeom
|
||||
{
|
||||
PxExtendedBox mBox;
|
||||
};
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(TouchedUserBox)==sizeof(TouchedGeom)+sizeof(PxExtendedBox));
|
||||
|
||||
struct TouchedUserCapsule : public TouchedGeom
|
||||
{
|
||||
PxExtendedCapsule mCapsule;
|
||||
};
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(TouchedUserCapsule)==sizeof(TouchedGeom)+sizeof(PxExtendedCapsule));
|
||||
|
||||
struct TouchedMesh : public TouchedGeom
|
||||
{
|
||||
PxU32 mNbTris;
|
||||
PxU32 mIndexWorldTriangles;
|
||||
};
|
||||
|
||||
struct TouchedBox : public TouchedGeom
|
||||
{
|
||||
PxVec3 mCenter;
|
||||
PxVec3 mExtents;
|
||||
PxQuat mRot;
|
||||
};
|
||||
|
||||
struct TouchedSphere : public TouchedGeom
|
||||
{
|
||||
PxVec3 mCenter; //!< Sphere's center
|
||||
PxF32 mRadius; //!< Sphere's radius
|
||||
};
|
||||
|
||||
struct TouchedCustom : public TouchedGeom
|
||||
{
|
||||
PxVec3 mCenter; //!< Custom geometry's center
|
||||
PxCustomGeometry::Callbacks* mCustomCallbacks; //!< Custom geometry's callback object
|
||||
};
|
||||
|
||||
struct TouchedCapsule : public TouchedGeom
|
||||
{
|
||||
PxVec3 mP0; //!< Start of segment
|
||||
PxVec3 mP1; //!< End of segment
|
||||
PxF32 mRadius; //!< Capsule's radius
|
||||
};
|
||||
|
||||
struct SweptContact
|
||||
{
|
||||
PxExtendedVec3 mWorldPos; // Contact position in world space
|
||||
PxVec3 mWorldNormal; // Contact normal in world space
|
||||
PxF32 mDistance; // Contact distance
|
||||
PxU32 mInternalIndex; // Reserved for internal usage
|
||||
PxU32 mTriangleIndex; // Triangle index for meshes/heightfields
|
||||
TouchedGeom* mGeom;
|
||||
|
||||
PX_FORCE_INLINE void setWorldPos(const PxVec3& localImpact, const PxExtendedVec3& offset)
|
||||
{
|
||||
mWorldPos.x = PxExtended(localImpact.x) + offset.x;
|
||||
mWorldPos.y = PxExtended(localImpact.y) + offset.y;
|
||||
mWorldPos.z = PxExtended(localImpact.z) + offset.z;
|
||||
}
|
||||
};
|
||||
|
||||
// PT: user-defined obstacles. Note that "user" is from the SweepTest class' point of view,
|
||||
// i.e. the PhysX CCT module is the user in this case. This is to limit coupling between the
|
||||
// core CCT module and the PhysX classes.
|
||||
struct UserObstacles// : PxObstacleContext
|
||||
{
|
||||
PxU32 mNbBoxes;
|
||||
const PxExtendedBox* mBoxes;
|
||||
const void** mBoxUserData;
|
||||
|
||||
PxU32 mNbCapsules;
|
||||
const PxExtendedCapsule* mCapsules;
|
||||
const void** mCapsuleUserData;
|
||||
};
|
||||
|
||||
struct InternalCBData_OnHit{};
|
||||
struct InternalCBData_FindTouchedGeom{};
|
||||
|
||||
enum SweepTestFlag
|
||||
{
|
||||
STF_HIT_NON_WALKABLE = (1<<0),
|
||||
STF_WALK_EXPERIMENT = (1<<1),
|
||||
STF_VALIDATE_TRIANGLE_DOWN = (1<<2), // Validate touched triangle data (down pass)
|
||||
STF_VALIDATE_TRIANGLE_SIDE = (1<<3), // Validate touched triangle data (side pass)
|
||||
STF_TOUCH_OTHER_CCT = (1<<4), // Are we standing on another CCT or not? (only updated for down pass)
|
||||
STF_TOUCH_OBSTACLE = (1<<5), // Are we standing on an obstacle or not? (only updated for down pass)
|
||||
STF_NORMALIZE_RESPONSE = (1<<6),
|
||||
STF_FIRST_UPDATE = (1<<7),
|
||||
STF_IS_MOVING_UP = (1<<8)
|
||||
};
|
||||
|
||||
enum SweepPass
|
||||
{
|
||||
SWEEP_PASS_UP,
|
||||
SWEEP_PASS_SIDE,
|
||||
SWEEP_PASS_DOWN,
|
||||
SWEEP_PASS_SENSOR
|
||||
};
|
||||
|
||||
class Controller;
|
||||
|
||||
template<class T>
|
||||
struct TouchedObject
|
||||
{
|
||||
TouchedObject(bool regDl)
|
||||
: mTouchedObject(NULL), mRegisterDeletionListener(regDl), mCctManager(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const T* operator->() const { return mTouchedObject; }
|
||||
PX_FORCE_INLINE bool operator==(const TouchedObject& otherObject) { return mTouchedObject == otherObject.mTouchedObject; }
|
||||
PX_FORCE_INLINE bool operator==(const T* otherObject) { return mTouchedObject == otherObject; }
|
||||
PX_FORCE_INLINE bool operator==(const PxBase* otherObject) { return mTouchedObject == otherObject; }
|
||||
PX_FORCE_INLINE operator bool() const { return mTouchedObject != NULL; }
|
||||
PX_FORCE_INLINE TouchedObject& operator=(const T* assignedObject)
|
||||
{
|
||||
if(mRegisterDeletionListener && (mTouchedObject != assignedObject))
|
||||
{
|
||||
if(mTouchedObject)
|
||||
mCctManager->unregisterObservedObject(mTouchedObject);
|
||||
|
||||
if(assignedObject)
|
||||
mCctManager->registerObservedObject(assignedObject);
|
||||
}
|
||||
mTouchedObject = assignedObject;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T* get() const { return mTouchedObject; }
|
||||
|
||||
void setCctManager(CharacterControllerManager* cm) { mCctManager = cm; }
|
||||
|
||||
private:
|
||||
TouchedObject& operator=(const TouchedObject&);
|
||||
|
||||
const T* mTouchedObject;
|
||||
bool mRegisterDeletionListener;
|
||||
CharacterControllerManager* mCctManager;
|
||||
};
|
||||
|
||||
class SweepTest
|
||||
{
|
||||
PX_NOCOPY(SweepTest)
|
||||
public:
|
||||
SweepTest(bool registerDeletionListener);
|
||||
~SweepTest();
|
||||
|
||||
PxControllerCollisionFlags moveCharacter( const InternalCBData_FindTouchedGeom* userData,
|
||||
InternalCBData_OnHit* user_data2,
|
||||
SweptVolume& volume,
|
||||
const PxVec3& direction,
|
||||
const UserObstacles& userObstacles,
|
||||
PxF32 min_dist,
|
||||
const PxControllerFilters& filters,
|
||||
bool constrainedClimbingMode,
|
||||
bool standingOnMoving,
|
||||
const PxRigidActor*& touchedActor,
|
||||
const PxShape*& touchedShape,
|
||||
PxU64 contextID);
|
||||
|
||||
bool doSweepTest(const InternalCBData_FindTouchedGeom* userDataTouchedGeom,
|
||||
InternalCBData_OnHit* userDataOnHit,
|
||||
const UserObstacles& userObstacles,
|
||||
SweptVolume& swept_volume,
|
||||
const PxVec3& direction, const PxVec3& sideVector, PxU32 max_iter,
|
||||
PxU32* nb_collisions, PxF32 min_dist, const PxControllerFilters& filters, SweepPass sweepPass,
|
||||
const PxRigidActor*& touchedActor, const PxShape*& touchedShape, PxU64 contextID);
|
||||
|
||||
void findTouchedObstacles(const UserObstacles& userObstacles, const PxExtendedBounds3& world_box);
|
||||
|
||||
void voidTestCache();
|
||||
void onRelease(const PxBase& observed);
|
||||
void updateCachedShapesRegistration(PxU32 startIndex, bool unregister);
|
||||
|
||||
// observer notifications
|
||||
void onObstacleRemoved(PxObstacleHandle index);
|
||||
void onObstacleUpdated(PxObstacleHandle index, const PxObstacleContext* context, const PxVec3& origin, const PxVec3& unitDir, PxReal distance);
|
||||
void onObstacleAdded(PxObstacleHandle index, const PxObstacleContext* context, const PxVec3& origin, const PxVec3& unitDir, PxReal distance);
|
||||
|
||||
void onOriginShift(const PxVec3& shift);
|
||||
|
||||
PxRenderBuffer* mRenderBuffer;
|
||||
PxU32 mRenderFlags;
|
||||
TriArray mWorldTriangles;
|
||||
IntArray mTriangleIndices;
|
||||
IntArray mGeomStream;
|
||||
PxExtendedBounds3 mCacheBounds;
|
||||
PxU32 mCachedTriIndexIndex;
|
||||
mutable PxU32 mCachedTriIndex[3];
|
||||
PxU32 mNbCachedStatic;
|
||||
PxU32 mNbCachedT;
|
||||
public:
|
||||
#ifdef USE_CONTACT_NORMAL_FOR_SLOPE_TEST
|
||||
PxVec3 mContactNormalDownPass;
|
||||
#else
|
||||
PxVec3 mContactNormalDownPass;
|
||||
PxVec3 mContactNormalSidePass;
|
||||
float mTouchedTriMin;
|
||||
float mTouchedTriMax;
|
||||
//PxTriangle mTouchedTriangle;
|
||||
#endif
|
||||
//
|
||||
TouchedObject<PxShape> mTouchedShape; // Shape on which the CCT is standing
|
||||
TouchedObject<PxRigidActor> mTouchedActor; // Actor from touched shape
|
||||
PxObstacleHandle mTouchedObstacleHandle; // Obstacle on which the CCT is standing
|
||||
PxVec3 mTouchedPos; // Last known position of mTouchedShape/mTouchedObstacle
|
||||
// PT: TODO: union those
|
||||
PxVec3 mTouchedPosShape_Local;
|
||||
PxVec3 mTouchedPosShape_World;
|
||||
PxVec3 mTouchedPosObstacle_Local;
|
||||
PxVec3 mTouchedPosObstacle_World;
|
||||
//
|
||||
CCTParams mUserParams;
|
||||
PxF32 mVolumeGrowth; // Must be >1.0f and not too big
|
||||
PxF32 mContactPointHeight; // UBI
|
||||
PxU32 mSQTimeStamp;
|
||||
PxU16 mNbFullUpdates;
|
||||
PxU16 mNbPartialUpdates;
|
||||
PxU16 mNbTessellation;
|
||||
PxU16 mNbIterations;
|
||||
PxU32 mFlags;
|
||||
bool mRegisterDeletionListener;
|
||||
|
||||
PX_FORCE_INLINE void resetStats()
|
||||
{
|
||||
mNbFullUpdates = 0;
|
||||
mNbPartialUpdates = 0;
|
||||
mNbTessellation = 0;
|
||||
mNbIterations = 0;
|
||||
}
|
||||
|
||||
void setCctManager(CharacterControllerManager* cm)
|
||||
{
|
||||
mCctManager = cm;
|
||||
mTouchedActor.setCctManager(cm);
|
||||
mTouchedShape.setCctManager(cm);
|
||||
}
|
||||
|
||||
private:
|
||||
void updateTouchedGeoms( const InternalCBData_FindTouchedGeom* userData, const UserObstacles& userObstacles,
|
||||
const PxExtendedBounds3& worldBox, const PxControllerFilters& filters, const PxVec3& sideVector);
|
||||
|
||||
CharacterControllerManager* mCctManager;
|
||||
};
|
||||
|
||||
class CCTFilter // PT: internal filter data, could be replaced with PxControllerFilters eventually
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE CCTFilter() :
|
||||
mFilterData (NULL),
|
||||
mFilterCallback (NULL),
|
||||
mStaticShapes (false),
|
||||
mDynamicShapes (false),
|
||||
mPreFilter (false),
|
||||
mPostFilter (false),
|
||||
mCCTShapes (NULL)
|
||||
{
|
||||
}
|
||||
const PxFilterData* mFilterData;
|
||||
PxQueryFilterCallback* mFilterCallback;
|
||||
bool mStaticShapes;
|
||||
bool mDynamicShapes;
|
||||
bool mPreFilter;
|
||||
bool mPostFilter;
|
||||
PxHashSet<PxShape>* mCCTShapes;
|
||||
};
|
||||
|
||||
PxU32 getSceneTimestamp(const InternalCBData_FindTouchedGeom* userData);
|
||||
|
||||
void findTouchedGeometry(const InternalCBData_FindTouchedGeom* userData,
|
||||
const PxExtendedBounds3& world_aabb,
|
||||
|
||||
TriArray& world_triangles,
|
||||
IntArray& triIndicesArray,
|
||||
IntArray& geomStream,
|
||||
|
||||
const CCTFilter& filter,
|
||||
const CCTParams& params,
|
||||
PxU16& nbTessellation);
|
||||
|
||||
PxU32 shapeHitCallback(const InternalCBData_OnHit* userData, const SweptContact& contact, const PxVec3& dir, PxF32 length);
|
||||
PxU32 userHitCallback(const InternalCBData_OnHit* userData, const SweptContact& contact, const PxVec3& dir, PxF32 length);
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
/** \endcond */
|
||||
#endif
|
||||
1131
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterControllerCallbacks.cpp
vendored
Normal file
1131
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterControllerCallbacks.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
715
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.cpp
vendored
Normal file
715
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.cpp
vendored
Normal file
@@ -0,0 +1,715 @@
|
||||
// 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 "CctCharacterControllerManager.h"
|
||||
#include "CctBoxController.h"
|
||||
#include "CctCapsuleController.h"
|
||||
#include "CctObstacleContext.h"
|
||||
#include "GuDistanceSegmentSegment.h"
|
||||
#include "GuDistanceSegmentBox.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxScene.h"
|
||||
#include "PxPhysics.h"
|
||||
#include "CmRenderBuffer.h"
|
||||
#include "CmRadixSort.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
static const PxF32 gMaxOverlapRecover = 4.0f; // PT: TODO: expose this
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CharacterControllerManager::CharacterControllerManager(PxScene& scene, bool lockingEnabled) :
|
||||
mScene (scene),
|
||||
mRenderBuffer (NULL),
|
||||
mDebugRenderingFlags (0),
|
||||
mMaxEdgeLength (1.0f),
|
||||
mTessellation (false),
|
||||
mOverlapRecovery (true),
|
||||
mPreciseSweeps (true),
|
||||
mPreventVerticalSlidingAgainstCeiling (false),
|
||||
mLockingEnabled (lockingEnabled)
|
||||
{
|
||||
// PT: register ourself as a deletion listener, to be called by the SDK whenever an object is deleted
|
||||
PxPhysics& physics = scene.getPhysics();
|
||||
physics.registerDeletionListener(*this, PxDeletionEventFlag::eUSER_RELEASE);
|
||||
}
|
||||
|
||||
CharacterControllerManager::~CharacterControllerManager()
|
||||
{
|
||||
PX_DELETE(mRenderBuffer);
|
||||
}
|
||||
|
||||
static PxArray<CharacterControllerManager*>* gControllerManagers = NULL;
|
||||
|
||||
void CharacterControllerManager::release()
|
||||
{
|
||||
if(gControllerManagers)
|
||||
{
|
||||
const bool found = gControllerManagers->findAndReplaceWithLast(this);
|
||||
PX_ASSERT(found);
|
||||
PX_UNUSED(found);
|
||||
|
||||
if(!gControllerManagers->size())
|
||||
{
|
||||
PX_DELETE(gControllerManagers);
|
||||
}
|
||||
}
|
||||
|
||||
// PT: TODO: use non virtual calls & move to dtor
|
||||
while(getNbControllers()!= 0)
|
||||
releaseController(*getController(0));
|
||||
|
||||
while(getNbObstacleContexts()!= 0)
|
||||
mObstacleContexts[0]->release();
|
||||
|
||||
PxPhysics& physics = mScene.getPhysics();
|
||||
physics.unregisterDeletionListener(*this);
|
||||
|
||||
PX_DELETE_THIS;
|
||||
|
||||
PxDecFoundationRefCount();
|
||||
}
|
||||
|
||||
PX_C_EXPORT PxControllerManager* PX_CALL_CONV PxCreateControllerManager(PxScene& scene, bool lockingEnabled)
|
||||
{
|
||||
if(gControllerManagers)
|
||||
{
|
||||
// PT: make sure we cannot create two controller managers for the same scene
|
||||
const PxU32 nbManagers = gControllerManagers->size();
|
||||
for(PxU32 i=0;i<nbManagers;i++)
|
||||
{
|
||||
if(&scene==&(*gControllerManagers)[i]->getScene())
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PxIncFoundationRefCount();
|
||||
CharacterControllerManager* controllerManager = PX_NEW(CharacterControllerManager)(scene, lockingEnabled);
|
||||
|
||||
if(!gControllerManagers)
|
||||
gControllerManagers = new PxArray<CharacterControllerManager*>;
|
||||
gControllerManagers->pushBack(controllerManager);
|
||||
|
||||
return controllerManager;
|
||||
}
|
||||
|
||||
PxScene& CharacterControllerManager::getScene() const
|
||||
{
|
||||
return mScene;
|
||||
}
|
||||
|
||||
PxRenderBuffer& CharacterControllerManager::getRenderBuffer()
|
||||
{
|
||||
if(!mRenderBuffer)
|
||||
mRenderBuffer = PX_NEW(Cm::RenderBuffer);
|
||||
|
||||
return *mRenderBuffer;
|
||||
}
|
||||
|
||||
void CharacterControllerManager::setDebugRenderingFlags(PxControllerDebugRenderFlags flags)
|
||||
{
|
||||
mDebugRenderingFlags = flags;
|
||||
|
||||
if(!flags)
|
||||
{
|
||||
PX_DELETE(mRenderBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
PxU32 CharacterControllerManager::getNbControllers() const
|
||||
{
|
||||
return mControllers.size();
|
||||
}
|
||||
|
||||
Controller** CharacterControllerManager::getControllers()
|
||||
{
|
||||
return mControllers.begin();
|
||||
}
|
||||
|
||||
PxController* CharacterControllerManager::getController(PxU32 index)
|
||||
{
|
||||
if(index>=mControllers.size())
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_PARAMETER, PX_FL, "PxControllerManager::getController(): out-of-range index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PX_ASSERT(mControllers[index]);
|
||||
return mControllers[index]->getPxController();
|
||||
}
|
||||
|
||||
PxController* CharacterControllerManager::createController(const PxControllerDesc& desc)
|
||||
{
|
||||
if(!desc.isValid())
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_PARAMETER, PX_FL, "PxControllerManager::createController(): desc.isValid() fails.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Controller* newController = NULL;
|
||||
|
||||
PxController* N = NULL;
|
||||
if(desc.getType()==PxControllerShapeType::eBOX)
|
||||
{
|
||||
BoxController* boxController = PX_NEW(BoxController)(desc, mScene.getPhysics(), &mScene);
|
||||
newController = boxController;
|
||||
N = boxController;
|
||||
}
|
||||
else if(desc.getType()==PxControllerShapeType::eCAPSULE)
|
||||
{
|
||||
CapsuleController* capsuleController = PX_NEW(CapsuleController)(desc, mScene.getPhysics(), &mScene);
|
||||
newController = capsuleController;
|
||||
N = capsuleController;
|
||||
}
|
||||
else PX_ALWAYS_ASSERT_MESSAGE( "INTERNAL ERROR - invalid CCT type, should have been caught by isValid().");
|
||||
|
||||
if(newController)
|
||||
{
|
||||
mControllers.pushBack(newController);
|
||||
newController->setCctManager(this);
|
||||
|
||||
PxShape* shape = NULL;
|
||||
PxU32 nb = N->getActor()->getShapes(&shape, 1);
|
||||
PX_ASSERT(nb==1);
|
||||
PX_UNUSED(nb);
|
||||
mCCTShapes.insert(shape);
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
void CharacterControllerManager::releaseController(PxController& controller)
|
||||
{
|
||||
for(PxU32 i = 0; i<mControllers.size(); i++)
|
||||
{
|
||||
if(mControllers[i]->getPxController() == &controller)
|
||||
{
|
||||
mControllers.replaceWithLast(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PxShape* shape = NULL;
|
||||
PxU32 nb = controller.getActor()->getShapes(&shape, 1);
|
||||
PX_ASSERT(nb==1);
|
||||
PX_UNUSED(nb);
|
||||
mCCTShapes.erase(shape);
|
||||
|
||||
if(controller.getType() == PxControllerShapeType::eCAPSULE)
|
||||
{
|
||||
CapsuleController* cc = static_cast<CapsuleController*>(&controller);
|
||||
PX_DELETE(cc);
|
||||
}
|
||||
else if(controller.getType() == PxControllerShapeType::eBOX)
|
||||
{
|
||||
BoxController* bc = static_cast<BoxController*>(&controller);
|
||||
PX_DELETE(bc);
|
||||
}
|
||||
else PX_ASSERT(0);
|
||||
}
|
||||
|
||||
void CharacterControllerManager::purgeControllers()
|
||||
{
|
||||
while(mControllers.size())
|
||||
releaseController(*mControllers[0]->getPxController());
|
||||
}
|
||||
|
||||
void CharacterControllerManager::onRelease(const PxBase* observed, void* , PxDeletionEventFlag::Enum deletionEvent)
|
||||
{
|
||||
PX_ASSERT(deletionEvent == PxDeletionEventFlag::eUSER_RELEASE); // the only type we registered for
|
||||
PX_UNUSED(deletionEvent);
|
||||
|
||||
const PxType type = observed->getConcreteType();
|
||||
|
||||
if(type!=PxConcreteType:: eRIGID_DYNAMIC && type!=PxConcreteType:: eRIGID_STATIC && type!=PxConcreteType::eSHAPE && type!=PxConcreteType::eARTICULATION_LINK)
|
||||
return;
|
||||
|
||||
// check if object was registered
|
||||
if(mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
const ObservedRefCountMap::Entry* releaseEntry = mObservedRefCountMap.find(observed);
|
||||
|
||||
if(mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
|
||||
if(releaseEntry)
|
||||
{
|
||||
const PxU32 size = mControllers.size();
|
||||
for(PxU32 i=0; i<size; i++)
|
||||
{
|
||||
Controller* controller = mControllers[i];
|
||||
if(mLockingEnabled)
|
||||
controller->mWriteLock.lock();
|
||||
|
||||
controller->onRelease(*observed);
|
||||
|
||||
if(mLockingEnabled)
|
||||
controller->mWriteLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterControllerManager::registerObservedObject(const PxBase* obj)
|
||||
{
|
||||
if(mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
mObservedRefCountMap[obj].refCount++;
|
||||
|
||||
if(mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
void CharacterControllerManager::unregisterObservedObject(const PxBase* obj)
|
||||
{
|
||||
if(mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
ObservedRefCounter& refCounter = mObservedRefCountMap[obj];
|
||||
PX_ASSERT(refCounter.refCount);
|
||||
refCounter.refCount--;
|
||||
if(!refCounter.refCount)
|
||||
mObservedRefCountMap.erase(obj);
|
||||
|
||||
if(mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
PxU32 CharacterControllerManager::getNbObstacleContexts() const
|
||||
{
|
||||
return mObstacleContexts.size();
|
||||
}
|
||||
|
||||
PxObstacleContext* CharacterControllerManager::getObstacleContext(PxU32 index)
|
||||
{
|
||||
if(index>=mObstacleContexts.size())
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_PARAMETER, PX_FL, "PxControllerManager::getObstacleContext(): out-of-range index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PX_ASSERT(mObstacleContexts[index]);
|
||||
return mObstacleContexts[index];
|
||||
}
|
||||
|
||||
PxObstacleContext* CharacterControllerManager::createObstacleContext()
|
||||
{
|
||||
ObstacleContext* oc = PX_NEW(ObstacleContext)(*this);
|
||||
|
||||
mObstacleContexts.pushBack(oc);
|
||||
|
||||
return oc;
|
||||
}
|
||||
|
||||
void CharacterControllerManager::releaseObstacleContext(ObstacleContext& oc)
|
||||
{
|
||||
PX_ASSERT(mObstacleContexts.find(&oc) != mObstacleContexts.end());
|
||||
mObstacleContexts.findAndReplaceWithLast(&oc);
|
||||
|
||||
ObstacleContext* ptr = &oc;
|
||||
PX_DELETE(ptr);
|
||||
}
|
||||
|
||||
void CharacterControllerManager::onObstacleRemoved(PxObstacleHandle index) const
|
||||
{
|
||||
for(PxU32 i = 0; i<mControllers.size(); i++)
|
||||
{
|
||||
mControllers[i]->mCctModule.onObstacleRemoved(index);
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterControllerManager::onObstacleUpdated(PxObstacleHandle index, const PxObstacleContext* context) const
|
||||
{
|
||||
for(PxU32 i = 0; i<mControllers.size(); i++)
|
||||
{
|
||||
mControllers[i]->mCctModule.onObstacleUpdated(index,context, toVec3(mControllers[i]->mPosition), -mControllers[i]->mUserParams.mUpDirection, mControllers[i]->getHalfHeightInternal());
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterControllerManager::onObstacleAdded(PxObstacleHandle index, const PxObstacleContext* context) const
|
||||
{
|
||||
for(PxU32 i = 0; i<mControllers.size(); i++)
|
||||
{
|
||||
mControllers[i]->mCctModule.onObstacleAdded(index,context, toVec3(mControllers[i]->mPosition), -mControllers[i]->mUserParams.mUpDirection, mControllers[i]->getHalfHeightInternal());
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterControllerManager::resetObstaclesBuffers()
|
||||
{
|
||||
mBoxUserData.resetOrClear();
|
||||
mBoxes.resetOrClear();
|
||||
mCapsuleUserData.resetOrClear();
|
||||
mCapsules.resetOrClear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CharacterControllerManager::setTessellation(bool flag, float maxEdgeLength)
|
||||
{
|
||||
mTessellation = flag;
|
||||
mMaxEdgeLength = maxEdgeLength;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CharacterControllerManager::setOverlapRecoveryModule(bool flag)
|
||||
{
|
||||
mOverlapRecovery = flag;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CharacterControllerManager::setPreciseSweeps(bool flag)
|
||||
{
|
||||
mPreciseSweeps = flag;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CharacterControllerManager::setPreventVerticalSlidingAgainstCeiling(bool flag)
|
||||
{
|
||||
mPreventVerticalSlidingAgainstCeiling = flag;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CharacterControllerManager::shiftOrigin(const PxVec3& shift)
|
||||
{
|
||||
for(PxU32 i=0; i < mControllers.size(); i++)
|
||||
{
|
||||
mControllers[i]->onOriginShift(shift);
|
||||
}
|
||||
|
||||
for(PxU32 i=0; i < mObstacleContexts.size(); i++)
|
||||
{
|
||||
mObstacleContexts[i]->onOriginShift(shift);
|
||||
}
|
||||
|
||||
if(mRenderBuffer)
|
||||
mRenderBuffer->shift(-shift);
|
||||
|
||||
// assumption is that these are just used for temporary stuff
|
||||
PX_ASSERT(!mBoxes.size());
|
||||
PX_ASSERT(!mCapsules.size());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool computeMTD(PxVec3& mtd, PxF32& depth, const PxVec3& e0, const PxVec3& c0, const PxMat33& r0, const PxVec3& e1, const PxVec3& c1, const PxMat33& r1)
|
||||
{
|
||||
// Translation, in parent frame
|
||||
const PxVec3 v = c1 - c0;
|
||||
// Translation, in A's frame
|
||||
const PxVec3 T(v.dot(r0[0]), v.dot(r0[1]), v.dot(r0[2]));
|
||||
|
||||
// B's basis with respect to A's local frame
|
||||
PxReal R[3][3];
|
||||
PxReal FR[3][3];
|
||||
PxReal ra, rb, t, d;
|
||||
|
||||
PxReal overlap[15];
|
||||
|
||||
// Calculate rotation matrix
|
||||
for(PxU32 i=0;i<3;i++)
|
||||
{
|
||||
for(PxU32 k=0;k<3;k++)
|
||||
{
|
||||
R[i][k] = r0[i].dot(r1[k]);
|
||||
FR[i][k] = 1e-6f + PxAbs(R[i][k]); // Precompute fabs matrix
|
||||
}
|
||||
}
|
||||
|
||||
// A's basis vectors
|
||||
for(PxU32 i=0;i<3;i++)
|
||||
{
|
||||
ra = e0[i];
|
||||
rb = e1[0]*FR[i][0] + e1[1]*FR[i][1] + e1[2]*FR[i][2];
|
||||
t = PxAbs(T[i]);
|
||||
|
||||
d = ra + rb - t;
|
||||
if(d<0.0f)
|
||||
return false;
|
||||
|
||||
overlap[i] = d;
|
||||
}
|
||||
|
||||
// B's basis vectors
|
||||
for(PxU32 k=0;k<3;k++)
|
||||
{
|
||||
ra = e0[0]*FR[0][k] + e0[1]*FR[1][k] + e0[2]*FR[2][k];
|
||||
rb = e1[k];
|
||||
t = PxAbs(T[0]*R[0][k] + T[1]*R[1][k] + T[2]*R[2][k]);
|
||||
|
||||
d = ra + rb - t;
|
||||
if(d<0.0f)
|
||||
return false;
|
||||
|
||||
overlap[k+3] = d;
|
||||
}
|
||||
|
||||
// PT: edge-edge tests are skipped, by design
|
||||
|
||||
PxU32 minIndex=0;
|
||||
PxReal minD = overlap[0];
|
||||
for(PxU32 i=1;i<6;i++)
|
||||
{
|
||||
if(overlap[i]<minD)
|
||||
{
|
||||
minD = overlap[i];
|
||||
minIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
depth = minD;
|
||||
|
||||
switch(minIndex)
|
||||
{
|
||||
case 0: mtd = r0.column0; break;
|
||||
case 1: mtd = r0.column1; break;
|
||||
case 2: mtd = r0.column2; break;
|
||||
case 3: mtd = r1.column0; break;
|
||||
case 4: mtd = r1.column1; break;
|
||||
case 5: mtd = r1.column2; break;
|
||||
default: PX_ASSERT(0); break;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
static PxVec3 fixDir(const PxVec3& dir, const PxVec3& up)
|
||||
{
|
||||
PxVec3 normalCompo, tangentCompo;
|
||||
decomposeVector(normalCompo, tangentCompo, dir, up);
|
||||
return tangentCompo.getNormalized();
|
||||
}
|
||||
|
||||
static void InteractionCharacterCharacter(Controller* entity0, Controller* entity1, PxF32 elapsedTime)
|
||||
{
|
||||
PX_ASSERT(entity0);
|
||||
PX_ASSERT(entity1);
|
||||
|
||||
PxF32 overlap=0.0f;
|
||||
PxVec3 dir(0.0f);
|
||||
|
||||
if(entity0->mType>entity1->mType)
|
||||
PxSwap(entity0, entity1);
|
||||
|
||||
if(entity0->mType==PxControllerShapeType::eCAPSULE && entity1->mType==PxControllerShapeType::eCAPSULE)
|
||||
{
|
||||
CapsuleController* cc0 = static_cast<CapsuleController*>(entity0);
|
||||
CapsuleController* cc1 = static_cast<CapsuleController*>(entity1);
|
||||
|
||||
PxExtendedCapsule capsule0;
|
||||
cc0->getCapsule(capsule0);
|
||||
|
||||
PxExtendedCapsule capsule1;
|
||||
cc1->getCapsule(capsule1);
|
||||
|
||||
const PxF32 r = capsule0.radius + capsule1.radius;
|
||||
|
||||
const PxVec3 p00 = toVec3(capsule0.p0);
|
||||
const PxVec3 p01 = toVec3(capsule0.p1);
|
||||
const PxVec3 p10 = toVec3(capsule1.p0);
|
||||
const PxVec3 p11 = toVec3(capsule1.p1);
|
||||
|
||||
PxF32 s,t;
|
||||
const PxF32 d = sqrtf(Gu::distanceSegmentSegmentSquared(p00, p01 - p00, p10, p11 - p10, &s, &t));
|
||||
if(d<r)
|
||||
{
|
||||
const PxVec3 center0 = s * p00 + (1.0f - s) * p01;
|
||||
const PxVec3 center1 = t * p10 + (1.0f - t) * p11;
|
||||
const PxVec3 up = entity0->mCctModule.mUserParams.mUpDirection;
|
||||
dir = fixDir(center0 - center1, up);
|
||||
overlap = r - d;
|
||||
}
|
||||
}
|
||||
else if(entity0->mType==PxControllerShapeType::eBOX && entity1->mType==PxControllerShapeType::eCAPSULE)
|
||||
{
|
||||
BoxController* cc0 = static_cast<BoxController*>(entity0);
|
||||
CapsuleController* cc1 = static_cast<CapsuleController*>(entity1);
|
||||
|
||||
PxExtendedBox obb;
|
||||
cc0->getOBB(obb);
|
||||
|
||||
PxExtendedCapsule capsule;
|
||||
cc1->getCapsule(capsule);
|
||||
const PxVec3 p0 = toVec3(capsule.p0);
|
||||
const PxVec3 p1 = toVec3(capsule.p1);
|
||||
|
||||
PxF32 t;
|
||||
PxVec3 p;
|
||||
const PxMat33 M(obb.rot);
|
||||
const PxVec3 boxCenter = toVec3(obb.center);
|
||||
const PxF32 d = sqrtf(Gu::distanceSegmentBoxSquared(p0, p1, boxCenter, obb.extents, M, &t, &p));
|
||||
if(d<capsule.radius)
|
||||
{
|
||||
// const PxVec3 center0 = M.transform(p) + boxCenter;
|
||||
// const PxVec3 center1 = t * p0 + (1.0f - t) * p1;
|
||||
const PxVec3 center0 = boxCenter;
|
||||
const PxVec3 center1 = (p0 + p1)*0.5f;
|
||||
const PxVec3 up = entity0->mCctModule.mUserParams.mUpDirection;
|
||||
dir = fixDir(center0 - center1, up);
|
||||
overlap = capsule.radius - d;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(entity0->mType==PxControllerShapeType::eBOX);
|
||||
PX_ASSERT(entity1->mType==PxControllerShapeType::eBOX);
|
||||
BoxController* cc0 = static_cast<BoxController*>(entity0);
|
||||
BoxController* cc1 = static_cast<BoxController*>(entity1);
|
||||
|
||||
PxExtendedBox obb0;
|
||||
cc0->getOBB(obb0);
|
||||
|
||||
PxExtendedBox obb1;
|
||||
cc1->getOBB(obb1);
|
||||
|
||||
PxVec3 mtd;
|
||||
PxF32 depth;
|
||||
if(computeMTD( mtd, depth,
|
||||
obb0.extents, toVec3(obb0.center), PxMat33(obb0.rot),
|
||||
obb1.extents, toVec3(obb1.center), PxMat33(obb1.rot)))
|
||||
{
|
||||
const PxVec3 center0 = toVec3(obb0.center);
|
||||
const PxVec3 center1 = toVec3(obb1.center);
|
||||
const PxVec3 witness = center0 - center1;
|
||||
if(mtd.dot(witness)<0.0f)
|
||||
dir = -mtd;
|
||||
else
|
||||
dir = mtd;
|
||||
const PxVec3 up = entity0->mCctModule.mUserParams.mUpDirection;
|
||||
dir = fixDir(dir, up);
|
||||
overlap = depth;
|
||||
}
|
||||
}
|
||||
|
||||
if(overlap!=0.0f)
|
||||
{
|
||||
// We want to limit this to some reasonable amount, to avoid obvious "popping".
|
||||
const PxF32 maxOverlap = gMaxOverlapRecover * elapsedTime;
|
||||
if(overlap>maxOverlap)
|
||||
overlap=maxOverlap;
|
||||
|
||||
const PxVec3 sep = dir * overlap * 0.5f;
|
||||
entity0->mOverlapRecover += sep;
|
||||
entity1->mOverlapRecover -= sep;
|
||||
}
|
||||
}
|
||||
|
||||
// PT: TODO: this is the very old version, revisit with newer one
|
||||
static void completeBoxPruning(const PxBounds3* bounds, PxU32 nb, PxArray<PxU32>& pairs)
|
||||
{
|
||||
if(!nb)
|
||||
return;
|
||||
|
||||
pairs.clear();
|
||||
|
||||
float* PosList = PX_ALLOCATE(float, nb, "completeBoxPruning");
|
||||
|
||||
for(PxU32 i=0;i<nb;i++)
|
||||
PosList[i] = bounds[i].minimum.x;
|
||||
|
||||
/*static*/ Cm::RadixSortBuffered RS; // Static for coherence
|
||||
const PxU32* Sorted = RS.Sort(PosList, nb).GetRanks();
|
||||
|
||||
const PxU32* const LastSorted = &Sorted[nb];
|
||||
const PxU32* RunningAddress = Sorted;
|
||||
PxU32 Index0, Index1;
|
||||
while(RunningAddress<LastSorted && Sorted<LastSorted)
|
||||
{
|
||||
Index0 = *Sorted++;
|
||||
|
||||
while(RunningAddress<LastSorted && PosList[*RunningAddress++]<PosList[Index0]);
|
||||
|
||||
const PxU32* RunningAddress2 = RunningAddress;
|
||||
|
||||
while(RunningAddress2<LastSorted && PosList[Index1 = *RunningAddress2++]<=bounds[Index0].maximum.x)
|
||||
{
|
||||
if(Index0!=Index1)
|
||||
{
|
||||
if(bounds[Index0].intersects(bounds[Index1]))
|
||||
{
|
||||
pairs.pushBack(Index0);
|
||||
pairs.pushBack(Index1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PX_FREE(PosList);
|
||||
}
|
||||
|
||||
void CharacterControllerManager::computeInteractions(PxF32 elapsedTime, PxControllerFilterCallback* cctFilterCb)
|
||||
{
|
||||
PxU32 nbControllers = mControllers.size();
|
||||
Controller** controllers = mControllers.begin();
|
||||
|
||||
PxBounds3* boxes = PX_ALLOCATE(PxBounds3, nbControllers, "CharacterControllerManager::computeInteractions"); // PT: TODO: get rid of alloc
|
||||
PxBounds3* runningBoxes = boxes;
|
||||
|
||||
while(nbControllers--)
|
||||
{
|
||||
Controller* current = *controllers++;
|
||||
|
||||
PxExtendedBounds3 extBox;
|
||||
current->getWorldBox(extBox);
|
||||
|
||||
*runningBoxes++ = PxBounds3(toVec3(extBox.minimum), toVec3(extBox.maximum)); // ### LOSS OF ACCURACY
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
const PxU32 nbEntities = PxU32(runningBoxes - boxes);
|
||||
|
||||
PxArray<PxU32> pairs; // PT: TODO: get rid of alloc
|
||||
completeBoxPruning(boxes, nbEntities, pairs);
|
||||
|
||||
PxU32 nbPairs = pairs.size()>>1;
|
||||
const PxU32* indices = pairs.begin();
|
||||
while(nbPairs--)
|
||||
{
|
||||
const PxU32 index0 = *indices++;
|
||||
const PxU32 index1 = *indices++;
|
||||
Controller* ctrl0 = mControllers[index0];
|
||||
Controller* ctrl1 = mControllers[index1];
|
||||
|
||||
bool keep=true;
|
||||
if(cctFilterCb)
|
||||
keep = cctFilterCb->filter(*ctrl0->getPxController(), *ctrl1->getPxController());
|
||||
|
||||
if(keep)
|
||||
InteractionCharacterCharacter(ctrl0, ctrl1, elapsedTime);
|
||||
}
|
||||
|
||||
PX_FREE(boxes);
|
||||
}
|
||||
|
||||
146
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.h
vendored
Normal file
146
engine/third_party/physx/source/physxcharacterkinematic/src/CctCharacterControllerManager.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
// 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 CCT_CHARACTER_CONTROLLER_MANAGER
|
||||
#define CCT_CHARACTER_CONTROLLER_MANAGER
|
||||
|
||||
//Exclude file from docs
|
||||
/** \cond */
|
||||
|
||||
#include "geometry/PxMeshQuery.h"
|
||||
#include "common/PxRenderBuffer.h"
|
||||
#include "foundation/PxHashSet.h"
|
||||
#include "foundation/PxHashMap.h"
|
||||
#include "characterkinematic/PxControllerManager.h"
|
||||
#include "characterkinematic/PxControllerObstacles.h"
|
||||
#include "PxDeletionListener.h"
|
||||
#include "CctUtils.h"
|
||||
#include "foundation/PxMutex.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Cct
|
||||
{
|
||||
class Controller;
|
||||
class ObstacleContext;
|
||||
|
||||
struct ObservedRefCounter
|
||||
{
|
||||
ObservedRefCounter(): refCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
PxU32 refCount;
|
||||
};
|
||||
|
||||
typedef PxHashMap<const PxBase*, ObservedRefCounter> ObservedRefCountMap;
|
||||
|
||||
//Implements the PxControllerManager interface, this class used to be called ControllerManager
|
||||
class CharacterControllerManager : public PxControllerManager, public PxUserAllocated, public PxDeletionListener
|
||||
{
|
||||
PX_NOCOPY(CharacterControllerManager)
|
||||
public:
|
||||
CharacterControllerManager(PxScene& scene, bool lockingEnabled = false);
|
||||
private:
|
||||
virtual ~CharacterControllerManager();
|
||||
public:
|
||||
|
||||
// PxControllerManager
|
||||
virtual void release() PX_OVERRIDE PX_FINAL;
|
||||
virtual PxScene& getScene() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxU32 getNbControllers() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxController* getController(PxU32 index) PX_OVERRIDE PX_FINAL;
|
||||
virtual PxController* createController(const PxControllerDesc& desc) PX_OVERRIDE PX_FINAL;
|
||||
|
||||
virtual void purgeControllers() PX_OVERRIDE PX_FINAL;
|
||||
virtual PxRenderBuffer& getRenderBuffer() PX_OVERRIDE PX_FINAL;
|
||||
virtual void setDebugRenderingFlags(PxControllerDebugRenderFlags flags) PX_OVERRIDE PX_FINAL;
|
||||
virtual PxU32 getNbObstacleContexts() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxObstacleContext* getObstacleContext(PxU32 index) PX_OVERRIDE PX_FINAL;
|
||||
virtual PxObstacleContext* createObstacleContext() PX_OVERRIDE PX_FINAL;
|
||||
virtual void computeInteractions(PxF32 elapsedTime, PxControllerFilterCallback* cctFilterCb) PX_OVERRIDE PX_FINAL;
|
||||
virtual void setTessellation(bool flag, float maxEdgeLength) PX_OVERRIDE PX_FINAL;
|
||||
virtual void setOverlapRecoveryModule(bool flag) PX_OVERRIDE PX_FINAL;
|
||||
virtual void setPreciseSweeps(bool flag) PX_OVERRIDE PX_FINAL;
|
||||
virtual void setPreventVerticalSlidingAgainstCeiling(bool flag) PX_OVERRIDE PX_FINAL;
|
||||
virtual void shiftOrigin(const PxVec3& shift) PX_OVERRIDE PX_FINAL;
|
||||
//~PxControllerManager
|
||||
|
||||
// PxDeletionListener
|
||||
virtual void onRelease(const PxBase* observed, void* userData, PxDeletionEventFlag::Enum deletionEvent) PX_OVERRIDE PX_FINAL;
|
||||
//~PxDeletionListener
|
||||
void registerObservedObject(const PxBase* obj);
|
||||
void unregisterObservedObject(const PxBase* obj);
|
||||
|
||||
// ObstacleContextNotifications
|
||||
void onObstacleRemoved(PxObstacleHandle index) const;
|
||||
void onObstacleUpdated(PxObstacleHandle index, const PxObstacleContext* ) const;
|
||||
void onObstacleAdded(PxObstacleHandle index, const PxObstacleContext*) const;
|
||||
|
||||
void releaseController(PxController& controller);
|
||||
Controller** getControllers();
|
||||
void releaseObstacleContext(ObstacleContext& oc);
|
||||
void resetObstaclesBuffers();
|
||||
|
||||
PxScene& mScene;
|
||||
|
||||
PxRenderBuffer* mRenderBuffer;
|
||||
PxControllerDebugRenderFlags mDebugRenderingFlags;
|
||||
// Shared buffers for obstacles
|
||||
PxArray<const void*> mBoxUserData;
|
||||
PxArray<PxExtendedBox> mBoxes;
|
||||
|
||||
PxArray<const void*> mCapsuleUserData;
|
||||
PxArray<PxExtendedCapsule> mCapsules;
|
||||
|
||||
PxArray<Controller*> mControllers;
|
||||
PxHashSet<PxShape*> mCCTShapes;
|
||||
|
||||
PxArray<ObstacleContext*> mObstacleContexts;
|
||||
|
||||
float mMaxEdgeLength;
|
||||
bool mTessellation;
|
||||
|
||||
bool mOverlapRecovery;
|
||||
bool mPreciseSweeps;
|
||||
bool mPreventVerticalSlidingAgainstCeiling;
|
||||
|
||||
bool mLockingEnabled;
|
||||
private:
|
||||
ObservedRefCountMap mObservedRefCountMap;
|
||||
mutable PxMutex mWriteLock; // Lock used for guarding pointers in observedrefcountmap
|
||||
};
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
/** \endcond */
|
||||
#endif //CCT_CHARACTER_CONTROLLER_MANAGER
|
||||
238
engine/third_party/physx/source/physxcharacterkinematic/src/CctController.cpp
vendored
Normal file
238
engine/third_party/physx/source/physxcharacterkinematic/src/CctController.cpp
vendored
Normal file
@@ -0,0 +1,238 @@
|
||||
// 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/PxMathUtils.h"
|
||||
#include "extensions/PxRigidBodyExt.h"
|
||||
#include "characterkinematic/PxController.h"
|
||||
#include "PxPhysics.h"
|
||||
#include "PxScene.h"
|
||||
#include "PxRigidDynamic.h"
|
||||
#include "PxShape.h"
|
||||
|
||||
#include "CctController.h"
|
||||
#include "CctBoxController.h"
|
||||
#include "CctCharacterControllerManager.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Controller::Controller(const PxControllerDesc& desc, PxScene* s) :
|
||||
mCctModule (desc.registerDeletionListener),
|
||||
mScene (s),
|
||||
mPreviousSceneTimestamp (0xffffffff),
|
||||
mGlobalTime (0.0),
|
||||
mPreviousGlobalTime (0.0),
|
||||
mProxyDensity (0.0f),
|
||||
mProxyScaleCoeff (0.0f),
|
||||
mCollisionFlags (0),
|
||||
mCachedStandingOnMoving (false),
|
||||
mManager (NULL)
|
||||
{
|
||||
mType = PxControllerShapeType::eFORCE_DWORD;
|
||||
|
||||
mUserParams.mNonWalkableMode = desc.nonWalkableMode;
|
||||
mUserParams.mSlopeLimit = desc.slopeLimit;
|
||||
mUserParams.mContactOffset = desc.contactOffset;
|
||||
mUserParams.mStepOffset = desc.stepOffset;
|
||||
mUserParams.mInvisibleWallHeight = desc.invisibleWallHeight;
|
||||
mUserParams.mMaxJumpHeight = desc.maxJumpHeight;
|
||||
mUserParams.mHandleSlope = desc.slopeLimit!=0.0f;
|
||||
|
||||
mReportCallback = desc.reportCallback;
|
||||
mBehaviorCallback = desc.behaviorCallback;
|
||||
mUserData = desc.userData;
|
||||
|
||||
mKineActor = NULL;
|
||||
mPosition = desc.position;
|
||||
mProxyDensity = desc.density;
|
||||
mProxyScaleCoeff = desc.scaleCoeff;
|
||||
|
||||
mCctModule.mVolumeGrowth = desc.volumeGrowth;
|
||||
|
||||
mRegisterDeletionListener = desc.registerDeletionListener;
|
||||
|
||||
mDeltaXP = PxVec3(0);
|
||||
mOverlapRecover = PxVec3(0);
|
||||
|
||||
mUserParams.mUpDirection = PxVec3(0.0f);
|
||||
setUpDirectionInternal(desc.upDirection);
|
||||
}
|
||||
|
||||
Controller::~Controller()
|
||||
{
|
||||
if(mScene)
|
||||
{
|
||||
if(mKineActor)
|
||||
mKineActor->release();
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Controller::onRelease(const PxBase& observed)
|
||||
{
|
||||
mCctModule.onRelease(observed);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Controller::onOriginShift(const PxVec3& shift)
|
||||
{
|
||||
sub(mPosition, shift);
|
||||
|
||||
if(mManager && mManager->mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
mCctModule.onOriginShift(shift);
|
||||
|
||||
if(mManager && mManager->mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Controller::setUpDirectionInternal(const PxVec3& up)
|
||||
{
|
||||
PX_CHECK_MSG(up.isNormalized(), "CCT: up direction must be normalized");
|
||||
|
||||
if(mUserParams.mUpDirection==up)
|
||||
return;
|
||||
|
||||
const PxQuat q = PxShortestRotation(PxVec3(1.0f, 0.0f, 0.0f), up);
|
||||
|
||||
mUserParams.mQuatFromUp = q;
|
||||
mUserParams.mUpDirection = up;
|
||||
|
||||
// Update kinematic actor
|
||||
/*if(mKineActor)
|
||||
{
|
||||
PxTransform pose = mKineActor->getGlobalPose();
|
||||
pose.q = q;
|
||||
mKineActor->setGlobalPose(pose);
|
||||
}*/
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Controller::releaseInternal()
|
||||
{
|
||||
mManager->releaseController(*getPxController());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Controller::getInternalState(PxControllerState& state) const
|
||||
{
|
||||
if(mManager->mLockingEnabled)
|
||||
mWriteLock.lock();
|
||||
|
||||
state.deltaXP = mDeltaXP;
|
||||
state.touchedShape = const_cast<PxShape*>(mCctModule.mTouchedShape.get());
|
||||
state.touchedActor = const_cast<PxRigidActor*>(mCctModule.mTouchedActor.get());
|
||||
state.touchedObstacleHandle = mCctModule.mTouchedObstacleHandle;
|
||||
state.standOnAnotherCCT = (mCctModule.mFlags & STF_TOUCH_OTHER_CCT)!=0;
|
||||
state.standOnObstacle = (mCctModule.mFlags & STF_TOUCH_OBSTACLE)!=0;
|
||||
state.isMovingUp = (mCctModule.mFlags & STF_IS_MOVING_UP)!=0;
|
||||
state.collisionFlags = mCollisionFlags;
|
||||
|
||||
if(mManager->mLockingEnabled)
|
||||
mWriteLock.unlock();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void Controller::getInternalStats(PxControllerStats& stats) const
|
||||
{
|
||||
stats.nbFullUpdates = mCctModule.mNbFullUpdates;
|
||||
stats.nbPartialUpdates = mCctModule.mNbPartialUpdates;
|
||||
stats.nbIterations = mCctModule.mNbIterations;
|
||||
stats.nbTessellation = mCctModule.mNbTessellation;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Controller::setPos(const PxExtendedVec3& pos)
|
||||
{
|
||||
mPosition = pos;
|
||||
|
||||
// Update kinematic actor
|
||||
if(mKineActor)
|
||||
{
|
||||
PxTransform targetPose = mKineActor->getGlobalPose();
|
||||
targetPose.p = toVec3(mPosition); // LOSS OF ACCURACY
|
||||
targetPose.q = mUserParams.mQuatFromUp;
|
||||
mKineActor->setKinematicTarget(targetPose);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool Controller::createProxyActor(PxPhysics& sdk, const PxGeometry& geometry, const PxMaterial& material, PxClientID clientID)
|
||||
{
|
||||
// PT: we don't disable raycasting or CD because:
|
||||
// - raycasting is needed for visibility queries (the SDK otherwise doesn't know about the CCTS)
|
||||
// - collision is needed because the only reason we create actors there is to handle collisions with dynamic shapes
|
||||
// So it's actually wrong to disable any of those.
|
||||
|
||||
PxTransform globalPose;
|
||||
globalPose.p = toVec3(mPosition); // LOSS OF ACCURACY
|
||||
globalPose.q = mUserParams.mQuatFromUp;
|
||||
|
||||
mKineActor = sdk.createRigidDynamic(globalPose);
|
||||
if(!mKineActor)
|
||||
return false;
|
||||
|
||||
PxShape* shape = sdk.createShape(geometry, material, true);
|
||||
mKineActor->attachShape(*shape);
|
||||
shape->release();
|
||||
mKineActor->setRigidBodyFlag(PxRigidBodyFlag::eKINEMATIC, true);
|
||||
|
||||
PxRigidBodyExt::updateMassAndInertia(*mKineActor, mProxyDensity);
|
||||
|
||||
if(clientID!=PX_DEFAULT_CLIENT)
|
||||
mKineActor->setOwnerClient(clientID);
|
||||
|
||||
mScene->addActor(*mKineActor);
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxShape* Controller::getKineShape() const
|
||||
{
|
||||
// PT: TODO: cache this and avoid the virtual call
|
||||
PxShape* shape = NULL;
|
||||
PxU32 nb = mKineActor->getShapes(&shape, 1);
|
||||
PX_ASSERT(nb==1);
|
||||
PX_UNUSED(nb);
|
||||
return shape;
|
||||
}
|
||||
129
engine/third_party/physx/source/physxcharacterkinematic/src/CctController.h
vendored
Normal file
129
engine/third_party/physx/source/physxcharacterkinematic/src/CctController.h
vendored
Normal 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.
|
||||
|
||||
#ifndef CCT_CONTROLLER
|
||||
#define CCT_CONTROLLER
|
||||
|
||||
/* Exclude from documentation */
|
||||
/** \cond */
|
||||
|
||||
#include "CctCharacterController.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxMutex.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
class PxPhysics;
|
||||
class PxScene;
|
||||
class PxRigidDynamic;
|
||||
class PxGeometry;
|
||||
class PxMaterial;
|
||||
|
||||
namespace Cct
|
||||
{
|
||||
class CharacterControllerManager;
|
||||
|
||||
class Controller : public PxUserAllocated
|
||||
{
|
||||
PX_NOCOPY(Controller)
|
||||
public:
|
||||
Controller(const PxControllerDesc& desc, PxScene* scene);
|
||||
virtual ~Controller();
|
||||
|
||||
void releaseInternal();
|
||||
void getInternalState(PxControllerState& state) const;
|
||||
void getInternalStats(PxControllerStats& stats) const;
|
||||
|
||||
virtual PxF32 getHalfHeightInternal() const = 0;
|
||||
virtual bool getWorldBox(PxExtendedBounds3& box) const = 0;
|
||||
virtual PxController* getPxController() = 0;
|
||||
|
||||
void onOriginShift(const PxVec3& shift);
|
||||
|
||||
void onRelease(const PxBase& observed);
|
||||
|
||||
void setCctManager(CharacterControllerManager* cm)
|
||||
{
|
||||
mManager = cm;
|
||||
mCctModule.setCctManager(cm);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE CharacterControllerManager* getCctManager() { return mManager; }
|
||||
PX_FORCE_INLINE PxU64 getContextId() const { return PxU64(mScene); }
|
||||
|
||||
PxControllerShapeType::Enum mType;
|
||||
// User params
|
||||
CCTParams mUserParams;
|
||||
PxUserControllerHitReport* mReportCallback;
|
||||
PxControllerBehaviorCallback* mBehaviorCallback;
|
||||
void* mUserData;
|
||||
// Internal data
|
||||
SweepTest mCctModule; // Internal CCT object. Optim test for Ubi.
|
||||
PxRigidDynamic* mKineActor; // Associated kinematic actor
|
||||
PxExtendedVec3 mPosition; // Current position
|
||||
PxVec3 mDeltaXP;
|
||||
PxVec3 mOverlapRecover;
|
||||
PxScene* mScene; // Handy scene owner
|
||||
PxU32 mPreviousSceneTimestamp;
|
||||
PxF64 mGlobalTime;
|
||||
PxF64 mPreviousGlobalTime;
|
||||
PxF32 mProxyDensity; // Density for proxy actor
|
||||
PxF32 mProxyScaleCoeff; // Scale coeff for proxy actor
|
||||
PxControllerCollisionFlags mCollisionFlags; // Last known collision flags (PxControllerCollisionFlag)
|
||||
bool mCachedStandingOnMoving;
|
||||
bool mRegisterDeletionListener;
|
||||
mutable PxMutex mWriteLock; // Lock used for guarding touched pointers and cache data from overwriting
|
||||
// during onRelease call.
|
||||
protected:
|
||||
// Internal methods
|
||||
void setUpDirectionInternal(const PxVec3& up);
|
||||
PxShape* getKineShape() const;
|
||||
bool createProxyActor(PxPhysics& sdk, const PxGeometry& geometry, const PxMaterial& material, PxClientID clientID);
|
||||
bool setPos(const PxExtendedVec3& pos);
|
||||
void findTouchedObject(const PxControllerFilters& filters, const PxObstacleContext* obstacleContext, const PxVec3& upDirection);
|
||||
bool rideOnTouchedObject(SweptVolume& volume, const PxVec3& upDirection, PxVec3& disp, const PxObstacleContext* obstacleContext);
|
||||
PxControllerCollisionFlags move(SweptVolume& volume, const PxVec3& disp, PxF32 minDist, PxF32 elapsedTime, const PxControllerFilters& filters, const PxObstacleContext* obstacles, bool constrainedClimbingMode);
|
||||
bool filterTouchedShape(const PxControllerFilters& filters);
|
||||
|
||||
PX_FORCE_INLINE float computeTimeCoeff()
|
||||
{
|
||||
const float elapsedTime = float(mGlobalTime - mPreviousGlobalTime);
|
||||
mPreviousGlobalTime = mGlobalTime;
|
||||
return 1.0f / elapsedTime;
|
||||
}
|
||||
|
||||
CharacterControllerManager* mManager; // Owner manager
|
||||
};
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
/** \endcond */
|
||||
#endif
|
||||
84
engine/third_party/physx/source/physxcharacterkinematic/src/CctInternalStructs.h
vendored
Normal file
84
engine/third_party/physx/source/physxcharacterkinematic/src/CctInternalStructs.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
// 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 CCT_INTERNAL_STRUCTS_H
|
||||
#define CCT_INTERNAL_STRUCTS_H
|
||||
|
||||
#include "CctController.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxObstacle; // (*)
|
||||
|
||||
namespace Cct
|
||||
{
|
||||
class ObstacleContext;
|
||||
|
||||
enum UserObjectType
|
||||
{
|
||||
USER_OBJECT_CCT = 0,
|
||||
USER_OBJECT_BOX_OBSTACLE = 1,
|
||||
USER_OBJECT_CAPSULE_OBSTACLE = 2
|
||||
};
|
||||
|
||||
PX_FORCE_INLINE PxU32 encodeUserObject(PxU32 index, UserObjectType type)
|
||||
{
|
||||
PX_ASSERT(index<=0xffff);
|
||||
PX_ASSERT(PxU32(type)<=0xffff);
|
||||
return (PxU16(index)<<16)|PxU32(type);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE UserObjectType decodeType(PxU32 code)
|
||||
{
|
||||
return UserObjectType(code & 0xffff);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxU32 decodeIndex(PxU32 code)
|
||||
{
|
||||
return code>>16;
|
||||
}
|
||||
|
||||
struct PxInternalCBData_OnHit : InternalCBData_OnHit
|
||||
{
|
||||
Controller* controller;
|
||||
const ObstacleContext* obstacles;
|
||||
const PxObstacle* touchedObstacle;
|
||||
PxObstacleHandle touchedObstacleHandle;
|
||||
};
|
||||
|
||||
struct PxInternalCBData_FindTouchedGeom : InternalCBData_FindTouchedGeom
|
||||
{
|
||||
PxScene* scene;
|
||||
PxRenderBuffer* renderBuffer; // Render buffer from controller manager, not the one from the scene
|
||||
|
||||
PxHashSet<PxShape*>* cctShapeHashSet;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
536
engine/third_party/physx/source/physxcharacterkinematic/src/CctObstacleContext.cpp
vendored
Normal file
536
engine/third_party/physx/source/physxcharacterkinematic/src/CctObstacleContext.cpp
vendored
Normal file
@@ -0,0 +1,536 @@
|
||||
// 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 "CctObstacleContext.h"
|
||||
#include "CctCharacterControllerManager.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
//! Initial list size
|
||||
#define DEFAULT_HANDLEMANAGER_SIZE 2
|
||||
|
||||
HandleManager::HandleManager() : mCurrentNbObjects(0), mNbFreeIndices(0)
|
||||
{
|
||||
mMaxNbObjects = DEFAULT_HANDLEMANAGER_SIZE;
|
||||
mObjects = PX_ALLOCATE(void*, mMaxNbObjects, "HandleManager");
|
||||
mOutToIn = PX_ALLOCATE(PxU16, mMaxNbObjects, "HandleManager");
|
||||
mInToOut = PX_ALLOCATE(PxU16, mMaxNbObjects, "HandleManager");
|
||||
mStamps = PX_ALLOCATE(PxU16, mMaxNbObjects, "HandleManager");
|
||||
PxMemSet(mOutToIn, 0xff, mMaxNbObjects*sizeof(PxU16));
|
||||
PxMemSet(mInToOut, 0xff, mMaxNbObjects*sizeof(PxU16));
|
||||
PxMemZero(mStamps, mMaxNbObjects*sizeof(PxU16));
|
||||
}
|
||||
|
||||
HandleManager::~HandleManager()
|
||||
{
|
||||
SetupLists();
|
||||
}
|
||||
|
||||
bool HandleManager::SetupLists(void** objects, PxU16* oti, PxU16* ito, PxU16* stamps)
|
||||
{
|
||||
// Release old data
|
||||
PX_FREE(mStamps);
|
||||
PX_FREE(mInToOut);
|
||||
PX_FREE(mOutToIn);
|
||||
PX_FREE(mObjects);
|
||||
// Assign new data
|
||||
mObjects = objects;
|
||||
mOutToIn = oti;
|
||||
mInToOut = ito;
|
||||
mStamps = stamps;
|
||||
return true;
|
||||
}
|
||||
|
||||
Handle HandleManager::Add(void* object)
|
||||
{
|
||||
// Are there any free indices I should recycle?
|
||||
if(mNbFreeIndices)
|
||||
{
|
||||
const PxU16 FreeIndex = mInToOut[mCurrentNbObjects];// Get the recycled virtual index
|
||||
mObjects[mCurrentNbObjects] = object; // The physical location is always at the end of the list (it never has holes).
|
||||
mOutToIn[FreeIndex] = PxTo16(mCurrentNbObjects++); // Update virtual-to-physical remapping table.
|
||||
mNbFreeIndices--;
|
||||
return Handle((mStamps[FreeIndex]<<16)|FreeIndex); // Return virtual index (handle) to the client app
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT_WITH_MESSAGE(mCurrentNbObjects<0xffff ,"Internal error - 64K objects in HandleManager!");
|
||||
|
||||
// Is the array large enough for another entry?
|
||||
if(mCurrentNbObjects==mMaxNbObjects)
|
||||
{
|
||||
// Nope! Resize all arrays (could be avoided with linked lists... one day)
|
||||
mMaxNbObjects<<=1; // The more you eat, the more you're given
|
||||
if(mMaxNbObjects>0xffff) mMaxNbObjects = 0xffff; // Clamp to 64K
|
||||
void** NewList = PX_ALLOCATE(void*, mMaxNbObjects, "HandleManager"); // New physical list
|
||||
PxU16* NewOTI = PX_ALLOCATE(PxU16, mMaxNbObjects, "HandleManager"); // New remapping table
|
||||
PxU16* NewITO = PX_ALLOCATE(PxU16, mMaxNbObjects, "HandleManager"); // New remapping table
|
||||
PxU16* NewStamps = PX_ALLOCATE(PxU16, mMaxNbObjects, "HandleManager"); // New stamps
|
||||
PxMemCopy(NewList, mObjects, mCurrentNbObjects*sizeof(void*)); // Copy old data
|
||||
PxMemCopy(NewOTI, mOutToIn, mCurrentNbObjects*sizeof(PxU16)); // Copy old data
|
||||
PxMemCopy(NewITO, mInToOut, mCurrentNbObjects*sizeof(PxU16)); // Copy old data
|
||||
PxMemCopy(NewStamps, mStamps, mCurrentNbObjects*sizeof(PxU16)); // Copy old data
|
||||
PxMemSet(NewOTI+mCurrentNbObjects, 0xff, (mMaxNbObjects-mCurrentNbObjects)*sizeof(PxU16));
|
||||
PxMemSet(NewITO+mCurrentNbObjects, 0xff, (mMaxNbObjects-mCurrentNbObjects)*sizeof(PxU16));
|
||||
PxMemZero(NewStamps+mCurrentNbObjects, (mMaxNbObjects-mCurrentNbObjects)*sizeof(PxU16));
|
||||
SetupLists(NewList, NewOTI, NewITO, NewStamps);
|
||||
}
|
||||
|
||||
mObjects[mCurrentNbObjects] = object; // Store object at mCurrentNbObjects = physical index = virtual index
|
||||
mOutToIn[mCurrentNbObjects] = PxTo16(mCurrentNbObjects); // Update virtual-to-physical remapping table.
|
||||
mInToOut[mCurrentNbObjects] = PxTo16(mCurrentNbObjects); // Update physical-to-virtual remapping table.
|
||||
PxU32 tmp = mCurrentNbObjects++;
|
||||
return (mStamps[tmp]<<16)|tmp; // Return virtual index (handle) to the client app
|
||||
}
|
||||
}
|
||||
|
||||
void HandleManager::Remove(Handle handle)
|
||||
{
|
||||
const PxU16 VirtualIndex = PxU16(handle);
|
||||
if(VirtualIndex>=mMaxNbObjects) return; // Invalid handle
|
||||
const PxU16 PhysicalIndex = mOutToIn[VirtualIndex]; // Get the physical index
|
||||
if(PhysicalIndex==0xffff) return; // Value has already been deleted
|
||||
if(PhysicalIndex>=mMaxNbObjects) return; // Invalid index
|
||||
|
||||
// There must be at least one valid entry.
|
||||
if(mCurrentNbObjects)
|
||||
{
|
||||
if(mStamps[VirtualIndex]!=handle>>16) return; // Stamp mismatch => index has been recycled
|
||||
|
||||
// Update list so that there's no hole
|
||||
mObjects[PhysicalIndex] = mObjects[--mCurrentNbObjects];// Move the real object so that the array has no holes.
|
||||
mOutToIn[mInToOut[mCurrentNbObjects]] = PhysicalIndex; // Update virtual-to-physical remapping table.
|
||||
mInToOut[PhysicalIndex] = mInToOut[mCurrentNbObjects]; // Update physical-to-virtual remapping table.
|
||||
// Keep track of the recyclable virtual index
|
||||
mInToOut[mCurrentNbObjects] = VirtualIndex; // Store the free virtual index/handle at the end of mInToOut
|
||||
mOutToIn[VirtualIndex] = 0xffff; // Invalidate the entry
|
||||
mNbFreeIndices++; // One more free index
|
||||
mStamps[VirtualIndex]++; // Update stamp
|
||||
}
|
||||
}
|
||||
|
||||
void* HandleManager::GetObject(Handle handle) const
|
||||
{
|
||||
const PxU16 VirtualIndex = PxU16(handle);
|
||||
if(VirtualIndex>=mMaxNbObjects) return NULL; // Invalid handle
|
||||
const PxU16 PhysicalIndex = mOutToIn[VirtualIndex]; // Get physical index
|
||||
if(PhysicalIndex==0xffff) return NULL; // Object has been deleted
|
||||
if(PhysicalIndex>=mMaxNbObjects) return NULL; // Index is invalid
|
||||
if(mStamps[VirtualIndex]!=handle>>16) return NULL; // Index has been recycled
|
||||
return mObjects[PhysicalIndex]; // Returns stored pointer
|
||||
}
|
||||
|
||||
bool HandleManager::UpdateObject(Handle handle, void* object)
|
||||
{
|
||||
const PxU16 VirtualIndex = PxU16(handle);
|
||||
if(VirtualIndex>=mMaxNbObjects) return false; // Invalid handle
|
||||
const PxU16 PhysicalIndex = mOutToIn[VirtualIndex]; // Get physical index
|
||||
if(PhysicalIndex==0xffff) return false; // Object has been deleted
|
||||
if(PhysicalIndex>=mMaxNbObjects) return false; // Index is invalid
|
||||
if(mStamps[VirtualIndex]!=handle>>16) return false; // Index has been recycled
|
||||
mObjects[PhysicalIndex] = object; // Updates stored pointer
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// PT: please do not expose these functions outside of this class,
|
||||
// as we want to retain the ability to easily modify the handle format if necessary.
|
||||
|
||||
#define NEW_ENCODING
|
||||
#ifdef NEW_ENCODING
|
||||
static PX_FORCE_INLINE void* encodeInternalHandle(PxU32 index, PxGeometryType::Enum type)
|
||||
{
|
||||
PX_ASSERT(index<=0xffff);
|
||||
PX_ASSERT(PxU32(type)<=0xffff);
|
||||
// PT: we do type+1 to ban internal handles with a 0 value, since it's reserved for NULL pointers
|
||||
return reinterpret_cast<void*>((size_t(index)<<16)|(size_t(type)+1));
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE PxGeometryType::Enum decodeInternalType(void* handle)
|
||||
{
|
||||
return PxGeometryType::Enum((PxU32(size_t(handle)) & 0xffff)-1);
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE PxU32 decodeInternalIndex(void* handle)
|
||||
{
|
||||
return (PxU32(size_t(handle)))>>16;
|
||||
}
|
||||
#else
|
||||
static PX_FORCE_INLINE ObstacleHandle encodeHandle(PxU32 index, PxGeometryType::Enum type)
|
||||
{
|
||||
PX_ASSERT(index<=0xffff);
|
||||
PX_ASSERT(type<=0xffff);
|
||||
return (PxU16(index)<<16)|PxU32(type);
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE PxGeometryType::Enum decodeType(ObstacleHandle handle)
|
||||
{
|
||||
return PxGeometryType::Enum(handle & 0xffff);
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE PxU32 decodeIndex(ObstacleHandle handle)
|
||||
{
|
||||
return handle>>16;
|
||||
}
|
||||
#endif
|
||||
|
||||
ObstacleContext::ObstacleContext(CharacterControllerManager& cctMan)
|
||||
: mCCTManager(cctMan)
|
||||
{
|
||||
}
|
||||
|
||||
ObstacleContext::~ObstacleContext()
|
||||
{
|
||||
}
|
||||
|
||||
void ObstacleContext::release()
|
||||
{
|
||||
mCCTManager.releaseObstacleContext(*this);
|
||||
}
|
||||
|
||||
PxControllerManager& ObstacleContext::getControllerManager() const
|
||||
{
|
||||
return mCCTManager;
|
||||
}
|
||||
|
||||
PxObstacleHandle ObstacleContext::addObstacle(const PxObstacle& obstacle)
|
||||
{
|
||||
const PxGeometryType::Enum type = obstacle.getType();
|
||||
if(type==PxGeometryType::eBOX)
|
||||
{
|
||||
const PxU32 index = mBoxObstacles.size();
|
||||
#ifdef NEW_ENCODING
|
||||
const PxObstacleHandle handle = mHandleManager.Add(encodeInternalHandle(index, type));
|
||||
#else
|
||||
const PxObstacleHandle handle = encodeHandle(index, type);
|
||||
#endif
|
||||
mBoxObstacles.pushBack(InternalBoxObstacle(handle, static_cast<const PxBoxObstacle&>(obstacle)));
|
||||
mCCTManager.onObstacleAdded(handle, this);
|
||||
return handle;
|
||||
}
|
||||
else if(type==PxGeometryType::eCAPSULE)
|
||||
{
|
||||
const PxU32 index = mCapsuleObstacles.size();
|
||||
#ifdef NEW_ENCODING
|
||||
const PxObstacleHandle handle = mHandleManager.Add(encodeInternalHandle(index, type));
|
||||
#else
|
||||
const PxObstacleHandle handle = encodeHandle(index, type);
|
||||
#endif
|
||||
mCapsuleObstacles.pushBack(InternalCapsuleObstacle(handle, static_cast<const PxCapsuleObstacle&>(obstacle)));
|
||||
mCCTManager.onObstacleAdded(handle, this);
|
||||
return handle;
|
||||
}
|
||||
else return PX_INVALID_OBSTACLE_HANDLE;
|
||||
}
|
||||
|
||||
#ifdef NEW_ENCODING
|
||||
template<class T>
|
||||
static PX_FORCE_INLINE void remove(HandleManager& manager, void* object, PxObstacleHandle handle, PxU32 index, PxU32 size, const PxArray<T>& obstacles)
|
||||
{
|
||||
manager.Remove(handle);
|
||||
if(index!=size-1)
|
||||
{
|
||||
bool status = manager.UpdateObject(obstacles[size-1].mHandle, object);
|
||||
PX_ASSERT(status);
|
||||
PX_UNUSED(status);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ObstacleContext::removeObstacle(PxObstacleHandle handle)
|
||||
{
|
||||
#ifdef NEW_ENCODING
|
||||
void* object = mHandleManager.GetObject(handle);
|
||||
if(!object)
|
||||
return false;
|
||||
const PxGeometryType::Enum type = decodeInternalType(object);
|
||||
const PxU32 index = decodeInternalIndex(object);
|
||||
#else
|
||||
const PxGeometryType::Enum type = decodeType(handle);
|
||||
const PxU32 index = decodeIndex(handle);
|
||||
#endif
|
||||
|
||||
if(type==PxGeometryType::eBOX)
|
||||
{
|
||||
const PxU32 size = mBoxObstacles.size();
|
||||
PX_ASSERT(index<size);
|
||||
if(index>=size)
|
||||
return false;
|
||||
|
||||
#ifdef NEW_ENCODING
|
||||
remove<InternalBoxObstacle>(mHandleManager, object, handle, index, size, mBoxObstacles);
|
||||
#endif
|
||||
mBoxObstacles.replaceWithLast(index);
|
||||
#ifdef NEW_ENCODING
|
||||
mCCTManager.onObstacleRemoved(handle);
|
||||
#else
|
||||
mCCTManager.onObstacleRemoved(handle, encodeHandle(size-1, type));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else if(type==PxGeometryType::eCAPSULE)
|
||||
{
|
||||
const PxU32 size = mCapsuleObstacles.size();
|
||||
PX_ASSERT(index<size);
|
||||
if(index>=size)
|
||||
return false;
|
||||
|
||||
#ifdef NEW_ENCODING
|
||||
remove<InternalCapsuleObstacle>(mHandleManager, object, handle, index, size, mCapsuleObstacles);
|
||||
#endif
|
||||
|
||||
mCapsuleObstacles.replaceWithLast(index);
|
||||
#ifdef NEW_ENCODING
|
||||
mCCTManager.onObstacleRemoved(handle);
|
||||
#else
|
||||
mCCTManager.onObstacleRemoved(handle, encodeHandle(size-1, type));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
bool ObstacleContext::updateObstacle(PxObstacleHandle handle, const PxObstacle& obstacle)
|
||||
{
|
||||
#ifdef NEW_ENCODING
|
||||
void* object = mHandleManager.GetObject(handle);
|
||||
if(!object)
|
||||
return false;
|
||||
const PxGeometryType::Enum type = decodeInternalType(object);
|
||||
PX_ASSERT(type==obstacle.getType());
|
||||
if(type!=obstacle.getType())
|
||||
return false;
|
||||
const PxU32 index = decodeInternalIndex(object);
|
||||
#else
|
||||
const PxGeometryType::Enum type = decodeType(handle);
|
||||
PX_ASSERT(type==obstacle.getType());
|
||||
if(type!=obstacle.getType())
|
||||
return false;
|
||||
const PxU32 index = decodeIndex(handle);
|
||||
#endif
|
||||
|
||||
if(type==PxGeometryType::eBOX)
|
||||
{
|
||||
const PxU32 size = mBoxObstacles.size();
|
||||
PX_ASSERT(index<size);
|
||||
if(index>=size)
|
||||
return false;
|
||||
|
||||
mBoxObstacles[index].mData = static_cast<const PxBoxObstacle&>(obstacle);
|
||||
mCCTManager.onObstacleUpdated(handle,this);
|
||||
return true;
|
||||
}
|
||||
else if(type==PxGeometryType::eCAPSULE)
|
||||
{
|
||||
const PxU32 size = mCapsuleObstacles.size();
|
||||
PX_ASSERT(index<size);
|
||||
if(index>=size)
|
||||
return false;
|
||||
|
||||
mCapsuleObstacles[index].mData = static_cast<const PxCapsuleObstacle&>(obstacle);
|
||||
mCCTManager.onObstacleUpdated(handle,this);
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
PxU32 ObstacleContext::getNbObstacles() const
|
||||
{
|
||||
return mBoxObstacles.size() + mCapsuleObstacles.size();
|
||||
}
|
||||
|
||||
const PxObstacle* ObstacleContext::getObstacle(PxU32 i) const
|
||||
{
|
||||
const PxU32 nbBoxes = mBoxObstacles.size();
|
||||
if(i<nbBoxes)
|
||||
return &mBoxObstacles[i].mData;
|
||||
i -= nbBoxes;
|
||||
|
||||
const PxU32 nbCapsules = mCapsuleObstacles.size();
|
||||
if(i<nbCapsules)
|
||||
return &mCapsuleObstacles[i].mData;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const PxObstacle* ObstacleContext::getObstacleByHandle(PxObstacleHandle handle) const
|
||||
{
|
||||
#ifdef NEW_ENCODING
|
||||
void* object = mHandleManager.GetObject(handle);
|
||||
if(!object)
|
||||
return NULL;
|
||||
const PxGeometryType::Enum type = decodeInternalType(object);
|
||||
const PxU32 index = decodeInternalIndex(object);
|
||||
#else
|
||||
const PxGeometryType::Enum type = decodeType(handle);
|
||||
const PxU32 index = decodeIndex(handle);
|
||||
#endif
|
||||
|
||||
if(type == PxGeometryType::eBOX)
|
||||
{
|
||||
const PxU32 size = mBoxObstacles.size();
|
||||
if(index>=size)
|
||||
return NULL;
|
||||
PX_ASSERT(mBoxObstacles[index].mHandle==handle);
|
||||
return &mBoxObstacles[index].mData;
|
||||
}
|
||||
else if(type==PxGeometryType::eCAPSULE)
|
||||
{
|
||||
const PxU32 size = mCapsuleObstacles.size();
|
||||
if(index>=size)
|
||||
return NULL;
|
||||
PX_ASSERT(mCapsuleObstacles[index].mHandle==handle);
|
||||
return &mCapsuleObstacles[index].mData;
|
||||
}
|
||||
else return NULL;
|
||||
}
|
||||
|
||||
#include "GuRaycastTests.h"
|
||||
#include "geometry/PxBoxGeometry.h"
|
||||
#include "geometry/PxCapsuleGeometry.h"
|
||||
using namespace Gu;
|
||||
const PxObstacle* ObstacleContext::raycastSingle(PxGeomRaycastHit& hit, const PxVec3& origin, const PxVec3& unitDir, PxReal distance, PxObstacleHandle& obstacleHandle) const
|
||||
{
|
||||
PxGeomRaycastHit localHit;
|
||||
PxF32 t = FLT_MAX;
|
||||
const PxObstacle* touchedObstacle = NULL;
|
||||
|
||||
const PxHitFlags hitFlags = PxHitFlags(0);
|
||||
|
||||
{
|
||||
const RaycastFunc raycastFunc = Gu::getRaycastFuncTable()[PxGeometryType::eBOX];
|
||||
PX_ASSERT(raycastFunc);
|
||||
|
||||
const PxU32 nbExtraBoxes = mBoxObstacles.size();
|
||||
for(PxU32 i=0;i<nbExtraBoxes;i++)
|
||||
{
|
||||
const PxBoxObstacle& userBoxObstacle = mBoxObstacles[i].mData;
|
||||
|
||||
PxU32 status = raycastFunc( PxBoxGeometry(userBoxObstacle.mHalfExtents),
|
||||
PxTransform(toVec3(userBoxObstacle.mPos), userBoxObstacle.mRot),
|
||||
origin, unitDir, distance,
|
||||
hitFlags,
|
||||
1, &localHit, sizeof(PxGeomRaycastHit), UNUSED_RAYCAST_THREAD_CONTEXT);
|
||||
if(status && localHit.distance<t)
|
||||
{
|
||||
t = localHit.distance;
|
||||
hit = localHit;
|
||||
obstacleHandle = mBoxObstacles[i].mHandle;
|
||||
touchedObstacle = &userBoxObstacle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const RaycastFunc raycastFunc = Gu::getRaycastFuncTable()[PxGeometryType::eCAPSULE];
|
||||
PX_ASSERT(raycastFunc);
|
||||
|
||||
const PxU32 nbExtraCapsules = mCapsuleObstacles.size();
|
||||
for(PxU32 i=0;i<nbExtraCapsules;i++)
|
||||
{
|
||||
const PxCapsuleObstacle& userCapsuleObstacle = mCapsuleObstacles[i].mData;
|
||||
|
||||
PxU32 status = raycastFunc( PxCapsuleGeometry(userCapsuleObstacle.mRadius, userCapsuleObstacle.mHalfHeight),
|
||||
PxTransform(toVec3(userCapsuleObstacle.mPos), userCapsuleObstacle.mRot),
|
||||
origin, unitDir, distance,
|
||||
hitFlags,
|
||||
1, &localHit, sizeof(PxGeomRaycastHit), UNUSED_RAYCAST_THREAD_CONTEXT);
|
||||
if(status && localHit.distance<t)
|
||||
{
|
||||
t = localHit.distance;
|
||||
hit = localHit;
|
||||
obstacleHandle = mCapsuleObstacles[i].mHandle;
|
||||
touchedObstacle = &userCapsuleObstacle;
|
||||
}
|
||||
}
|
||||
}
|
||||
return touchedObstacle;
|
||||
}
|
||||
|
||||
|
||||
const PxObstacle* ObstacleContext::raycastSingle(PxGeomRaycastHit& hit, const PxObstacleHandle& obstacleHandle, const PxVec3& origin, const PxVec3& unitDir, PxReal distance) const
|
||||
{
|
||||
const PxHitFlags hitFlags = PxHitFlags(0);
|
||||
|
||||
#ifdef NEW_ENCODING
|
||||
void* object = mHandleManager.GetObject(obstacleHandle);
|
||||
if(!object)
|
||||
return NULL;
|
||||
const PxGeometryType::Enum geomType = decodeInternalType(object);
|
||||
const PxU32 index = decodeInternalIndex(object);
|
||||
#else
|
||||
const PxGeometryType::Enum geomType = decodeType(obstacleHandle);
|
||||
const PxU32 index = decodeIndex(obstacleHandle);
|
||||
#endif
|
||||
if(geomType == PxGeometryType::eBOX)
|
||||
{
|
||||
const PxBoxObstacle& userBoxObstacle = mBoxObstacles[index].mData;
|
||||
|
||||
PxU32 status = Gu::getRaycastFuncTable()[PxGeometryType::eBOX](
|
||||
PxBoxGeometry(userBoxObstacle.mHalfExtents),
|
||||
PxTransform(toVec3(userBoxObstacle.mPos), userBoxObstacle.mRot),
|
||||
origin, unitDir, distance,
|
||||
hitFlags,
|
||||
1, &hit, sizeof(PxGeomRaycastHit), UNUSED_RAYCAST_THREAD_CONTEXT);
|
||||
|
||||
if(status)
|
||||
{
|
||||
return &userBoxObstacle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(geomType == PxGeometryType::eCAPSULE);
|
||||
const PxCapsuleObstacle& userCapsuleObstacle = mCapsuleObstacles[index].mData;
|
||||
|
||||
PxU32 status = Gu::getRaycastFuncTable()[PxGeometryType::eCAPSULE](
|
||||
PxCapsuleGeometry(userCapsuleObstacle.mRadius, userCapsuleObstacle.mHalfHeight),
|
||||
PxTransform(toVec3(userCapsuleObstacle.mPos), userCapsuleObstacle.mRot),
|
||||
origin, unitDir, distance,
|
||||
hitFlags,
|
||||
1, &hit, sizeof(PxGeomRaycastHit), UNUSED_RAYCAST_THREAD_CONTEXT);
|
||||
if(status)
|
||||
{
|
||||
return &userCapsuleObstacle;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ObstacleContext::onOriginShift(const PxVec3& shift)
|
||||
{
|
||||
for(PxU32 i=0; i < mBoxObstacles.size(); i++)
|
||||
sub(mBoxObstacles[i].mData.mPos, shift);
|
||||
|
||||
for(PxU32 i=0; i < mCapsuleObstacles.size(); i++)
|
||||
sub(mCapsuleObstacles[i].mData.mPos, shift);
|
||||
}
|
||||
134
engine/third_party/physx/source/physxcharacterkinematic/src/CctObstacleContext.h
vendored
Normal file
134
engine/third_party/physx/source/physxcharacterkinematic/src/CctObstacleContext.h
vendored
Normal 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.
|
||||
|
||||
#ifndef CCT_OBSTACLE_CONTEXT
|
||||
#define CCT_OBSTACLE_CONTEXT
|
||||
|
||||
/* Exclude from documentation */
|
||||
/** \cond */
|
||||
|
||||
#include "characterkinematic/PxControllerObstacles.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxArray.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
struct PxGeomRaycastHit;
|
||||
|
||||
namespace Cct
|
||||
{
|
||||
class CharacterControllerManager;
|
||||
|
||||
typedef PxU32 Handle;
|
||||
class HandleManager : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
HandleManager();
|
||||
~HandleManager();
|
||||
|
||||
Handle Add(void* object);
|
||||
void Remove(Handle handle);
|
||||
void* GetObject(Handle handle) const; // Returns object according to handle.
|
||||
bool UpdateObject(Handle handle, void* object);
|
||||
|
||||
PX_FORCE_INLINE PxU32 GetMaxNbObjects() const { return mMaxNbObjects; } //!< Returns max number of objects
|
||||
PX_FORCE_INLINE PxU32 GetNbObjects() const { return mCurrentNbObjects; } //!< Returns current number of objects
|
||||
PX_FORCE_INLINE void** GetObjects() const { return mObjects; } //!< Gets the complete list of objects
|
||||
PX_FORCE_INLINE void* PickObject(Handle handle) const { return mObjects[mOutToIn[PxU16(handle)]]; }
|
||||
|
||||
private:
|
||||
// Physical list
|
||||
void** mObjects; //!< Physical list, with no holes but unsorted.
|
||||
PxU32 mCurrentNbObjects; //!< Current number of objects in the physical list.
|
||||
PxU32 mMaxNbObjects; //!< Maximum possible number of objects in the physical list.
|
||||
|
||||
// Cross-references
|
||||
PxU16* mOutToIn; //!< Maps virtual indices (handles) to real ones.
|
||||
PxU16* mInToOut; //!< Maps real indices to virtual ones (handles).
|
||||
PxU16* mStamps;
|
||||
|
||||
// Recycled locations
|
||||
PxU32 mNbFreeIndices; //!< Current number of free indices
|
||||
|
||||
// Internal methods
|
||||
bool SetupLists(void** objects=NULL, PxU16* oti=NULL, PxU16* ito=NULL, PxU16* stamps=NULL);
|
||||
};
|
||||
|
||||
class ObstacleContext : public PxObstacleContext, public PxUserAllocated
|
||||
{
|
||||
PX_NOCOPY(ObstacleContext)
|
||||
public:
|
||||
ObstacleContext(CharacterControllerManager& );
|
||||
virtual ~ObstacleContext();
|
||||
|
||||
// PxObstacleContext
|
||||
virtual void release() PX_OVERRIDE PX_FINAL;
|
||||
virtual PxControllerManager& getControllerManager() const PX_OVERRIDE PX_FINAL;
|
||||
virtual PxObstacleHandle addObstacle(const PxObstacle& obstacle) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool removeObstacle(PxObstacleHandle handle) PX_OVERRIDE PX_FINAL;
|
||||
virtual bool updateObstacle(PxObstacleHandle handle, const PxObstacle& obstacle) PX_OVERRIDE PX_FINAL;
|
||||
virtual PxU32 getNbObstacles() const PX_OVERRIDE PX_FINAL;
|
||||
virtual const PxObstacle* getObstacle(PxU32 i) const PX_OVERRIDE PX_FINAL;
|
||||
virtual const PxObstacle* getObstacleByHandle(PxObstacleHandle handle) const PX_OVERRIDE PX_FINAL;
|
||||
//~PxObstacleContext
|
||||
|
||||
const PxObstacle* raycastSingle(PxGeomRaycastHit& hit, const PxVec3& origin, const PxVec3& unitDir, PxReal distance, PxObstacleHandle& obstacleHandle) const;
|
||||
const PxObstacle* raycastSingle(PxGeomRaycastHit& hit, const PxObstacleHandle& obstacleHandle, const PxVec3& origin, const PxVec3& unitDir, PxReal distance) const; // raycast just one obstacle handle
|
||||
|
||||
void onOriginShift(const PxVec3& shift);
|
||||
|
||||
struct InternalBoxObstacle
|
||||
{
|
||||
InternalBoxObstacle(PxObstacleHandle handle, const PxBoxObstacle& data) : mHandle(handle), mData(data) {}
|
||||
|
||||
PxObstacleHandle mHandle;
|
||||
PxBoxObstacle mData;
|
||||
};
|
||||
PxArray<InternalBoxObstacle> mBoxObstacles;
|
||||
|
||||
struct InternalCapsuleObstacle
|
||||
{
|
||||
InternalCapsuleObstacle(PxObstacleHandle handle, const PxCapsuleObstacle& data) : mHandle(handle), mData(data) {}
|
||||
|
||||
PxObstacleHandle mHandle;
|
||||
PxCapsuleObstacle mData;
|
||||
};
|
||||
PxArray<InternalCapsuleObstacle> mCapsuleObstacles;
|
||||
|
||||
private:
|
||||
HandleManager mHandleManager;
|
||||
CharacterControllerManager& mCCTManager;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
/** \endcond */
|
||||
#endif
|
||||
49
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptBox.cpp
vendored
Normal file
49
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptBox.cpp
vendored
Normal 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 "CctSweptBox.h"
|
||||
#include "CctCharacterController.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
SweptBox::SweptBox()
|
||||
{
|
||||
mType = SweptVolumeType::eBOX;
|
||||
}
|
||||
|
||||
SweptBox::~SweptBox()
|
||||
{
|
||||
}
|
||||
|
||||
void SweptBox::computeTemporalBox(const SweepTest& test, PxExtendedBounds3& box, const PxExtendedVec3& center, const PxVec3& direction) const
|
||||
{
|
||||
const float radius = PxMax(mExtents.y, mExtents.z);
|
||||
const float height = 2.0f * mExtents.x;
|
||||
Cct::computeTemporalBox(box, radius, height, test.mUserParams.mContactOffset, test.mUserParams.mMaxJumpHeight, test.mUserParams.mUpDirection, center, direction);
|
||||
}
|
||||
53
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptBox.h
vendored
Normal file
53
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptBox.h
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
// 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 CCT_SWEPT_BOX
|
||||
#define CCT_SWEPT_BOX
|
||||
|
||||
#include "CctSweptVolume.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Cct
|
||||
{
|
||||
class SweptBox : public SweptVolume
|
||||
{
|
||||
public:
|
||||
SweptBox();
|
||||
virtual ~SweptBox();
|
||||
|
||||
virtual void computeTemporalBox(const SweepTest&, PxExtendedBounds3& box, const PxExtendedVec3& center, const PxVec3& direction) const PX_OVERRIDE PX_FINAL;
|
||||
|
||||
PxVec3 mExtents;
|
||||
};
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
47
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptCapsule.cpp
vendored
Normal file
47
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptCapsule.cpp
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 "CctSweptCapsule.h"
|
||||
#include "CctCharacterController.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
SweptCapsule::SweptCapsule()
|
||||
{
|
||||
mType = SweptVolumeType::eCAPSULE;
|
||||
}
|
||||
|
||||
SweptCapsule::~SweptCapsule()
|
||||
{
|
||||
}
|
||||
|
||||
void SweptCapsule::computeTemporalBox(const SweepTest& test, PxExtendedBounds3& box, const PxExtendedVec3& center, const PxVec3& direction) const
|
||||
{
|
||||
Cct::computeTemporalBox(box, mRadius, mHeight, test.mUserParams.mContactOffset, test.mUserParams.mMaxJumpHeight, test.mUserParams.mUpDirection, center, direction);
|
||||
}
|
||||
54
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptCapsule.h
vendored
Normal file
54
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptCapsule.h
vendored
Normal 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 CCT_SWEPT_CAPSULE
|
||||
#define CCT_SWEPT_CAPSULE
|
||||
|
||||
#include "CctSweptVolume.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Cct
|
||||
{
|
||||
class SweptCapsule : public SweptVolume
|
||||
{
|
||||
public:
|
||||
SweptCapsule();
|
||||
virtual ~SweptCapsule();
|
||||
|
||||
virtual void computeTemporalBox(const SweepTest&, PxExtendedBounds3& box, const PxExtendedVec3& center, const PxVec3& direction) const PX_OVERRIDE PX_FINAL;
|
||||
|
||||
PxF32 mRadius;
|
||||
PxF32 mHeight;
|
||||
};
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
73
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptVolume.cpp
vendored
Normal file
73
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptVolume.cpp
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
// 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 "CctSweptVolume.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cct;
|
||||
|
||||
SweptVolume::SweptVolume()
|
||||
{
|
||||
mType = SweptVolumeType::eLAST;
|
||||
}
|
||||
|
||||
SweptVolume::~SweptVolume()
|
||||
{
|
||||
}
|
||||
|
||||
void Cct::computeTemporalBox(PxExtendedBounds3& _box, float radius, float height, float contactOffset, float maxJumpHeight, const PxVec3& upDirection, const PxExtendedVec3& center, const PxVec3& direction)
|
||||
{
|
||||
const float r = radius + contactOffset;
|
||||
PxVec3 extents(r);
|
||||
const float halfHeight = height*0.5f;
|
||||
extents.x += fabsf(upDirection.x)*halfHeight;
|
||||
extents.y += fabsf(upDirection.y)*halfHeight;
|
||||
extents.z += fabsf(upDirection.z)*halfHeight;
|
||||
|
||||
PxExtendedBounds3 box;
|
||||
setCenterExtents(box, center, extents);
|
||||
|
||||
{
|
||||
PxExtendedBounds3 destBox;
|
||||
PxExtendedVec3 tmp = center;
|
||||
add(tmp, direction);
|
||||
setCenterExtents(destBox, tmp, extents);
|
||||
add(box, destBox);
|
||||
}
|
||||
|
||||
if(maxJumpHeight!=0.0f)
|
||||
{
|
||||
PxExtendedBounds3 destBox;
|
||||
PxExtendedVec3 tmp = center;
|
||||
sub(tmp, upDirection * maxJumpHeight);
|
||||
setCenterExtents(destBox, tmp, extents);
|
||||
add(box, destBox);
|
||||
}
|
||||
|
||||
_box = box;
|
||||
}
|
||||
74
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptVolume.h
vendored
Normal file
74
engine/third_party/physx/source/physxcharacterkinematic/src/CctSweptVolume.h
vendored
Normal 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 CCT_SWEPT_VOLUME
|
||||
#define CCT_SWEPT_VOLUME
|
||||
|
||||
#include "CctUtils.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Cct
|
||||
{
|
||||
struct SweptVolumeType
|
||||
{
|
||||
enum Enum
|
||||
{
|
||||
eBOX,
|
||||
eCAPSULE,
|
||||
|
||||
eLAST
|
||||
};
|
||||
};
|
||||
|
||||
class SweepTest;
|
||||
|
||||
class SweptVolume
|
||||
{
|
||||
public:
|
||||
SweptVolume();
|
||||
virtual ~SweptVolume();
|
||||
|
||||
virtual void computeTemporalBox(const SweepTest& test, PxExtendedBounds3& box, const PxExtendedVec3& center, const PxVec3& direction) const = 0;
|
||||
|
||||
PX_FORCE_INLINE SweptVolumeType::Enum getType() const { return mType; }
|
||||
|
||||
PxExtendedVec3 mCenter;
|
||||
PxF32 mHalfHeight; // UBI
|
||||
protected:
|
||||
SweptVolumeType::Enum mType;
|
||||
};
|
||||
|
||||
void computeTemporalBox(PxExtendedBounds3& _box, float radius, float height, float contactOffset, float maxJumpHeight, const PxVec3& upDirection, const PxExtendedVec3& center, const PxVec3& direction);
|
||||
|
||||
} // namespace Cct
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
236
engine/third_party/physx/source/physxcharacterkinematic/src/CctUtils.h
vendored
Normal file
236
engine/third_party/physx/source/physxcharacterkinematic/src/CctUtils.h
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
// 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 CCT_UTILS
|
||||
#define CCT_UTILS
|
||||
|
||||
#include "extensions/PxShapeExt.h"
|
||||
#include "characterkinematic/PxExtended.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
PX_FORCE_INLINE bool testSlope(const PxVec3& normal, const PxVec3& upDirection, PxF32 slopeLimit)
|
||||
{
|
||||
const float dp = normal.dot(upDirection);
|
||||
return dp>=0.0f && dp<slopeLimit;
|
||||
}
|
||||
|
||||
PX_INLINE PxTransform getShapeGlobalPose(const PxShape& shape, const PxRigidActor& actor)
|
||||
{
|
||||
return PxShapeExt::getGlobalPose(shape, actor);
|
||||
}
|
||||
|
||||
PX_INLINE void decomposeVector(PxVec3& normalCompo, PxVec3& tangentCompo, const PxVec3& outwardDir,
|
||||
const PxVec3& outwardNormal)
|
||||
{
|
||||
normalCompo = outwardNormal * (outwardDir.dot(outwardNormal));
|
||||
tangentCompo = outwardDir - normalCompo;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool isAlmostZero(const PxVec3& v)
|
||||
{
|
||||
if (PxAbs(v.x) > 1e-6f || PxAbs(v.y) > 1e-6f || PxAbs(v.z) > 1e-6f)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef PX_BIG_WORLDS
|
||||
|
||||
PX_INLINE void add(PxExtendedVec3& p, const PxVec3& e)
|
||||
{
|
||||
p += PxExtendedVec3(PxExtended(e.x), PxExtended(e.y), PxExtended(e.z));
|
||||
}
|
||||
|
||||
PX_INLINE void sub(PxExtendedVec3& p, const PxVec3& e)
|
||||
{
|
||||
p -= PxExtendedVec3(PxExtended(e.x), PxExtended(e.y), PxExtended(e.z));
|
||||
}
|
||||
|
||||
PX_INLINE PxExtended dot(const PxExtendedVec3& p, const PxVec3& e)
|
||||
{
|
||||
return p.dot(PxExtendedVec3(PxExtended(e.x), PxExtended(e.y), PxExtended(e.z)));
|
||||
}
|
||||
|
||||
class PxExtendedBox
|
||||
{
|
||||
public:
|
||||
PX_INLINE PxExtendedBox() {}
|
||||
PX_INLINE PxExtendedBox(const PxExtendedVec3& _center, const PxVec3& _extents, const PxQuat& _rot) : center(_center), extents(_extents), rot(_rot){}
|
||||
PX_INLINE ~PxExtendedBox() {}
|
||||
|
||||
PxExtendedVec3 center;
|
||||
PxVec3 extents;
|
||||
PxQuat rot;
|
||||
};
|
||||
|
||||
class PxExtendedSphere
|
||||
{
|
||||
public:
|
||||
PX_INLINE PxExtendedSphere() {}
|
||||
PX_INLINE ~PxExtendedSphere() {}
|
||||
PX_INLINE PxExtendedSphere(const PxExtendedVec3& _center, PxF32 _radius) : center(_center), radius(_radius) {}
|
||||
PX_INLINE PxExtendedSphere(const PxExtendedSphere& sphere) : center(sphere.center), radius(sphere.radius) {}
|
||||
|
||||
PxExtendedVec3 center; //!< Sphere's center
|
||||
PxF32 radius; //!< Sphere's radius
|
||||
};
|
||||
|
||||
struct PxExtendedSegment
|
||||
{
|
||||
PX_INLINE const PxExtendedVec3& getOrigin() const
|
||||
{
|
||||
return p0;
|
||||
}
|
||||
|
||||
PX_INLINE void computeDirection(PxVec3& dir) const
|
||||
{
|
||||
dir = diff(p1, p0);
|
||||
}
|
||||
|
||||
PX_INLINE void computePoint(PxExtendedVec3& pt, PxExtended t) const
|
||||
{
|
||||
pt.x = p0.x + t * (p1.x - p0.x);
|
||||
pt.y = p0.y + t * (p1.y - p0.y);
|
||||
pt.z = p0.z + t * (p1.z - p0.z);
|
||||
}
|
||||
|
||||
PxExtendedVec3 p0; //!< Start of segment
|
||||
PxExtendedVec3 p1; //!< End of segment
|
||||
};
|
||||
|
||||
struct PxExtendedCapsule : public PxExtendedSegment
|
||||
{
|
||||
PxReal radius;
|
||||
};
|
||||
|
||||
struct PxExtendedBounds3
|
||||
{
|
||||
PX_INLINE PxExtendedBounds3()
|
||||
{
|
||||
}
|
||||
|
||||
PX_INLINE void setEmpty()
|
||||
{
|
||||
// We now use this particular pattern for empty boxes
|
||||
set(PX_MAX_EXTENDED, PX_MAX_EXTENDED, PX_MAX_EXTENDED,
|
||||
-PX_MAX_EXTENDED, -PX_MAX_EXTENDED, -PX_MAX_EXTENDED);
|
||||
}
|
||||
|
||||
PX_INLINE void set(PxExtended minx, PxExtended miny, PxExtended minz, PxExtended maxx, PxExtended maxy, PxExtended maxz)
|
||||
{
|
||||
minimum = PxExtendedVec3(minx, miny, minz);
|
||||
maximum = PxExtendedVec3(maxx, maxy, maxz);
|
||||
}
|
||||
|
||||
PX_INLINE bool isInside(const PxExtendedBounds3& box) const
|
||||
{
|
||||
if(box.minimum.x > minimum.x) return false;
|
||||
if(box.minimum.y > minimum.y) return false;
|
||||
if(box.minimum.z > minimum.z) return false;
|
||||
if(box.maximum.x < maximum.x) return false;
|
||||
if(box.maximum.y < maximum.y) return false;
|
||||
if(box.maximum.z < maximum.z) return false;
|
||||
return true;
|
||||
}
|
||||
PxExtendedVec3 minimum, maximum;
|
||||
};
|
||||
|
||||
PX_INLINE void getCenter(const PxExtendedBounds3& b, PxExtendedVec3& center)
|
||||
{
|
||||
center = b.minimum + b.maximum;
|
||||
center *= 0.5;
|
||||
}
|
||||
|
||||
PX_INLINE void getExtents(const PxExtendedBounds3& b, PxVec3& extents)
|
||||
{
|
||||
extents = diff(b.maximum, b.minimum);
|
||||
extents *= 0.5f;
|
||||
}
|
||||
|
||||
PX_INLINE void setCenterExtents(PxExtendedBounds3& b, const PxExtendedVec3& c, const PxVec3& e)
|
||||
{
|
||||
const PxExtendedVec3 eExt(PxExtended(e.x), PxExtended(e.y), PxExtended(e.z));
|
||||
b.minimum = c - eExt;
|
||||
b.maximum = c + eExt;
|
||||
}
|
||||
|
||||
PX_INLINE void add(PxExtendedBounds3& b, const PxExtendedBounds3& b2)
|
||||
{
|
||||
// - if we're empty, minimum = MAX,MAX,MAX => minimum will be b2 in all cases => it will copy b2, ok
|
||||
// - if b2 is empty, the opposite happens => keep us unchanged => ok
|
||||
// => same behaviour as before, automatically
|
||||
b.minimum = b.minimum.minimum(b2.minimum);
|
||||
b.maximum = b.maximum.maximum(b2.maximum);
|
||||
}
|
||||
#else
|
||||
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "GuBox.h"
|
||||
#include "GuCapsule.h"
|
||||
#include "GuPlane.h"
|
||||
|
||||
typedef Gu::Box PxExtendedBox;
|
||||
typedef Gu::Sphere PxExtendedSphere;
|
||||
typedef Gu::Segment PxExtendedSegment;
|
||||
typedef Gu::Capsule PxExtendedCapsule;
|
||||
typedef PxBounds3 PxExtendedBounds3;
|
||||
|
||||
PX_INLINE void getCenter(const PxBounds3& b, PxVec3& center)
|
||||
{
|
||||
center = b.minimum + b.maximum;
|
||||
center *= 0.5;
|
||||
}
|
||||
|
||||
PX_INLINE void getExtents(const PxBounds3& b, PxVec3& extents)
|
||||
{
|
||||
extents = b.maximum - b.minimum;
|
||||
extents *= 0.5f;
|
||||
}
|
||||
|
||||
PX_INLINE void setCenterExtents(PxBounds3& b, const PxVec3& center, const PxVec3& extents)
|
||||
{
|
||||
b.minimum = center - extents;
|
||||
b.maximum = center + extents;
|
||||
}
|
||||
|
||||
PX_INLINE void add(PxBounds3& b, const PxBounds3& b2)
|
||||
{
|
||||
// - if we're empty, minimum = MAX,MAX,MAX => minimum will be b2 in all cases => it will copy b2, ok
|
||||
// - if b2 is empty, the opposite happens => keep us unchanged => ok
|
||||
// => same behaviour as before, automatically
|
||||
b.minimum = b.minimum.minimum(b2.minimum);
|
||||
b.maximum = b.maximum.maximum(b2.maximum);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user