Files
XCEngine/engine/third_party/physx/source/geomutils/include/GuBounds.h

204 lines
8.1 KiB
C++

// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_BOUNDS_H
#define GU_BOUNDS_H
#include "foundation/PxBounds3.h"
#include "foundation/PxFlags.h"
#include "foundation/PxVecMath.h"
#include "geometry/PxGeometry.h"
#include "geometry/PxCapsuleGeometry.h"
#include <stddef.h>
#include "GuBox.h"
#include "GuCenterExtents.h"
#include "GuSphere.h"
#include "GuCapsule.h"
// PT: the PX_MAX_BOUNDS_EXTENTS value is too large and produces INF floats when the box values are squared in
// some collision routines. Thus, for the SQ subsystem we use this alternative (smaller) value to mark empty bounds.
// See PX-954 for details.
#define GU_EMPTY_BOUNDS_EXTENTS PxSqrt(0.25f * 1e33f)
namespace physx
{
class PxMeshScale;
namespace Gu
{
PX_FORCE_INLINE void computeCapsuleBounds(PxBounds3& bounds, const PxCapsuleGeometry& capsuleGeom, const PxTransform& pose, float contactOffset=0.0f, float inflation=1.0f)
{
const PxVec3 d = pose.q.getBasisVector0();
PxVec3 extents;
for(PxU32 ax = 0; ax<3; ax++)
extents[ax] = (PxAbs(d[ax]) * capsuleGeom.halfHeight + capsuleGeom.radius + contactOffset)*inflation;
bounds.minimum = pose.p - extents;
bounds.maximum = pose.p + extents;
}
//'contactOffset' and 'inflation' should not be used at the same time, i.e. either contactOffset==0.0f, or inflation==1.0f
PX_PHYSX_COMMON_API void computeBounds(PxBounds3& bounds, const PxGeometry& geometry, const PxTransform& transform, float contactOffset, float inflation); //AABB in world space.
PX_FORCE_INLINE PxBounds3 computeBounds(const PxGeometry& geometry, const PxTransform& pose)
{
PxBounds3 bounds;
computeBounds(bounds, geometry, pose, 0.0f, 1.0f);
return bounds;
}
void computeGlobalBox(PxBounds3& bounds, PxU32 nbPrims, const PxBounds3* PX_RESTRICT boxes, const PxU32* PX_RESTRICT primitives);
PX_PHYSX_COMMON_API void computeBoundsAroundVertices(PxBounds3& bounds, PxU32 nbVerts, const PxVec3* PX_RESTRICT verts);
PX_PHYSX_COMMON_API void computeTightBounds(PxBounds3& bounds, PxU32 nbVerts, const PxVec3* PX_RESTRICT verts, const PxTransform& pose, const PxMeshScale& scale, float contactOffset, float inflation);
PX_PHYSX_COMMON_API void computeLocalBoundsAndGeomEpsilon(const PxVec3* vertices, PxU32 nbVerties, PxBounds3& localBounds, PxReal& geomEpsilon);
#define StoreBounds(bounds, minV, maxV) \
V4StoreU(minV, &bounds.minimum.x); \
PX_ALIGN(16, PxVec4) max4; \
V4StoreA(maxV, &max4.x); \
bounds.maximum = PxVec3(max4.x, max4.y, max4.z);
// PT: TODO: - refactor with "inflateBounds" in GuBounds.cpp if possible
template<const bool useSIMD>
PX_FORCE_INLINE void inflateBounds(PxBounds3& dst, const PxBounds3& src, float enlargement)
{
const float coeff = 0.5f * enlargement;
if(useSIMD)
{
using namespace physx::aos;
Vec4V minV = V4LoadU(&src.minimum.x);
Vec4V maxV = V4LoadU(&src.maximum.x);
const Vec4V eV = V4Scale(V4Sub(maxV, minV), FLoad(coeff));
minV = V4Sub(minV, eV);
maxV = V4Add(maxV, eV);
StoreBounds(dst, minV, maxV);
}
else
{
// PT: this clumsy but necessary second codepath is used to read the last bound of the array
// (making sure we don't V4LoadU invalid memory). Implementation must stay in sync with the
// main codepath above. No, this is not very nice.
const PxVec3& minV = src.minimum;
const PxVec3& maxV = src.maximum;
const PxVec3 eV = (maxV - minV) * coeff;
dst.minimum = minV - eV;
dst.maximum = maxV + eV;
}
}
class ShapeData
{
public:
PX_PHYSX_COMMON_API ShapeData(const PxGeometry& g, const PxTransform& t, PxReal inflation);
// PT: used by overlaps (box, capsule, convex)
PX_FORCE_INLINE const PxVec3& getPrunerBoxGeomExtentsInflated() const { return mPrunerBoxGeomExtents; }
// PT: used by overlaps (box, capsule, convex)
PX_FORCE_INLINE const PxVec3& getPrunerWorldPos() const { return mGuBox.center; }
PX_FORCE_INLINE const PxBounds3& getPrunerInflatedWorldAABB() const { return mPrunerInflatedAABB; }
// PT: used by overlaps (box, capsule, convex)
PX_FORCE_INLINE const PxMat33& getPrunerWorldRot33() const { return mGuBox.rot; }
// PT: this one only used by overlaps so far (for sphere shape, pruner level)
PX_FORCE_INLINE const Gu::Sphere& getGuSphere() const
{
PX_ASSERT(mType == PxGeometryType::eSPHERE);
return reinterpret_cast<const Gu::Sphere&>(mGuSphere);
}
// PT: this one only used by sweeps so far (for box shape, NP level)
PX_FORCE_INLINE const Gu::Box& getGuBox() const
{
PX_ASSERT(mType == PxGeometryType::eBOX);
return mGuBox;
}
// PT: this one used by sweeps (NP level) and overlaps (pruner level) - for capsule shape
PX_FORCE_INLINE const Gu::Capsule& getGuCapsule() const
{
PX_ASSERT(mType == PxGeometryType::eCAPSULE);
return reinterpret_cast<const Gu::Capsule&>(mGuCapsule);
}
PX_FORCE_INLINE float getCapsuleHalfHeight() const
{
PX_ASSERT(mType == PxGeometryType::eCAPSULE);
return mGuBox.extents.x;
}
PX_FORCE_INLINE PxU32 isOBB() const { return PxU32(mIsOBB); }
PX_FORCE_INLINE PxGeometryType::Enum getType() const { return PxGeometryType::Enum(mType); }
PX_NOCOPY(ShapeData)
private:
// PT: box: pre-inflated box extents
// capsule: pre-inflated extents of box-around-capsule
// convex: pre-inflated extents of box-around-convex
// sphere: not used
PxVec3 mPrunerBoxGeomExtents; // used for pruners. This volume encloses but can differ from the original shape
// PT:
//
// box center = unchanged copy of initial shape's position, except for convex (position of box around convex)
// SIMD code will load it as a V4 (safe because member is not last of Gu structure)
//
// box rot = precomputed PxMat33 version of initial shape's rotation, except for convex (rotation of box around convex)
// SIMD code will load it as V4s (safe because member is not last of Gu structure)
//
// box extents = non-inflated initial box extents for box shape, half-height for capsule, otherwise not used
Gu::Box mGuBox;
PxBounds3 mPrunerInflatedAABB; // precomputed AABB for the pruner shape
PxU16 mIsOBB; // true for OBB, false for AABB. Also used as padding for mPrunerInflatedAABB, don't move.
PxU16 mType; // shape's type
// these union Gu shapes are only precomputed for narrow phase (not pruners), can be different from mPrunerVolume
// so need separate storage
union
{
PxU8 mGuCapsule[sizeof(Gu::Capsule)]; // 28
PxU8 mGuSphere[sizeof(Gu::Sphere)]; // 16
};
};
// PT: please make sure it fits in "one" cache line
PX_COMPILE_TIME_ASSERT(sizeof(ShapeData)==128);
} // namespace Gu
}
#endif