feat(physics): wire physx sdk into build

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

View File

@@ -0,0 +1,202 @@
// 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/PxIntrinsics.h"
#include "foundation/PxUserAllocated.h"
#include "foundation/PxAllocator.h"
#include "GuBigConvexData2.h"
#include "GuCubeIndex.h"
#include "CmUtils.h"
#include "CmSerialize.h"
#include "foundation/PxUtilities.h"
using namespace physx;
using namespace Gu;
using namespace Cm;
BigConvexData::BigConvexData() : mVBuffer(NULL)
{
mData.mSubdiv = 0;
mData.mNbSamples = 0;
mData.mSamples = NULL;
//////
mData.mNbVerts = 0;
mData.mNbAdjVerts = 0;
mData.mValencies = NULL;
mData.mAdjacentVerts = NULL;
}
BigConvexData::~BigConvexData()
{
PX_FREE(mData.mSamples);
///////////
if(mVBuffer)
{
PX_FREE(mVBuffer);
}
else
{
// Allocated from somewhere else!!
PX_FREE(mData.mValencies);
PX_FREE(mData.mAdjacentVerts);
}
}
void BigConvexData::CreateOffsets()
{
// Create offsets (radix style)
mData.mValencies[0].mOffset = 0;
for(PxU32 i=1;i<mData.mNbVerts;i++)
mData.mValencies[i].mOffset = PxU16(mData.mValencies[i-1].mOffset + mData.mValencies[i-1].mCount);
}
bool BigConvexData::VLoad(PxInputStream& stream)
{
// Import header
PxU32 Version;
bool Mismatch;
if(!ReadHeader('V', 'A', 'L', 'E', Version, Mismatch, stream))
return false;
mData.mNbVerts = readDword(Mismatch, stream);
mData.mNbAdjVerts = readDword(Mismatch, stream);
PX_FREE(mVBuffer);
// PT: align Gu::Valency?
const PxU32 numVerts = (mData.mNbVerts+3)&~3;
const PxU32 TotalSize = sizeof(Gu::Valency)*numVerts + sizeof(PxU8)*mData.mNbAdjVerts;
mVBuffer = PX_ALLOC(TotalSize, "BigConvexData data");
mData.mValencies = reinterpret_cast<Gu::Valency*>(mVBuffer);
mData.mAdjacentVerts = (reinterpret_cast<PxU8*>(mVBuffer)) + sizeof(Gu::Valency)*numVerts;
PX_ASSERT(0 == (size_t(mData.mAdjacentVerts) & 0xf));
PX_ASSERT(Version==2);
{
PxU16* temp = reinterpret_cast<PxU16*>(mData.mValencies);
PxU32 MaxIndex = readDword(Mismatch, stream);
ReadIndices(PxTo16(MaxIndex), mData.mNbVerts, temp, stream, Mismatch);
// We transform from:
//
// |5555|4444|3333|2222|1111|----|----|----|----|----|
//
// to:
//
// |5555|4444|4444|2222|3333|----|2222|----|1111|----|
//
for(PxU32 i=0;i<mData.mNbVerts;i++)
mData.mValencies[mData.mNbVerts-i-1].mCount = temp[mData.mNbVerts-i-1];
}
stream.read(mData.mAdjacentVerts, mData.mNbAdjVerts);
// Recreate offsets
CreateOffsets();
return true;
}
PxU32 BigConvexData::ComputeOffset(const PxVec3& dir) const
{
return ComputeCubemapOffset(dir, mData.mSubdiv);
}
PxU32 BigConvexData::ComputeNearestOffset(const PxVec3& dir) const
{
return ComputeCubemapNearestOffset(dir, mData.mSubdiv);
}
bool BigConvexData::Load(PxInputStream& stream)
{
// Import header
PxU32 Version;
bool Mismatch;
if(!ReadHeader('S', 'U', 'P', 'M', Version, Mismatch, stream))
return false;
// Load base gaussmap
// if(!GaussMap::Load(stream)) return false;
// Import header
if(!ReadHeader('G', 'A', 'U', 'S', Version, Mismatch, stream))
return false;
// Import basic info
mData.mSubdiv = PxTo16(readDword(Mismatch, stream));
mData.mNbSamples = PxTo16(readDword(Mismatch, stream));
// Load map data
mData.mSamples = reinterpret_cast<PxU8*>(PX_ALLOC(sizeof(PxU8)*mData.mNbSamples*2, "BigConvex Samples Data"));
// These byte buffers shouldn't need converting
stream.read(mData.mSamples, sizeof(PxU8)*mData.mNbSamples*2);
//load the valencies
return VLoad(stream);
}
// PX_SERIALIZATION
void BigConvexData::exportExtraData(PxSerializationContext& stream)
{
if(mData.mSamples)
{
stream.alignData(PX_SERIAL_ALIGN);
stream.writeData(mData.mSamples, sizeof(PxU8)*mData.mNbSamples*2);
}
if(mData.mValencies)
{
stream.alignData(PX_SERIAL_ALIGN);
PxU32 numVerts = (mData.mNbVerts+3)&~3;
const PxU32 TotalSize = sizeof(Gu::Valency)*numVerts + sizeof(PxU8)*mData.mNbAdjVerts;
stream.writeData(mData.mValencies, TotalSize);
}
}
void BigConvexData::importExtraData(PxDeserializationContext& context)
{
if(mData.mSamples)
mData.mSamples = context.readExtraData<PxU8, PX_SERIAL_ALIGN>(PxU32(mData.mNbSamples*2));
if(mData.mValencies)
{
context.alignExtraData();
PxU32 numVerts = (mData.mNbVerts+3)&~3;
mData.mValencies = context.readExtraData<Gu::Valency>(numVerts);
mData.mAdjacentVerts = context.readExtraData<PxU8>(mData.mNbAdjVerts);
}
}
//~PX_SERIALIZATION

View File

@@ -0,0 +1,83 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_BIG_CONVEX_DATA_H
#define GU_BIG_CONVEX_DATA_H
#include "foundation/PxSimpleTypes.h"
namespace physx
{
class BigConvexDataBuilder;
class PxcHillClimb;
class BigConvexData;
// Data
namespace Gu
{
struct Valency
{
PxU16 mCount;
PxU16 mOffset;
};
PX_COMPILE_TIME_ASSERT(sizeof(Gu::Valency) == 4);
struct BigConvexRawData
{
// Support vertex map
PxU16 mSubdiv; // "Gaussmap" subdivision
PxU16 mNbSamples; // Total #samples in gaussmap PT: this is not even needed at runtime!
PxU8* mSamples;
PX_FORCE_INLINE const PxU8* getSamples2() const
{
return mSamples + mNbSamples;
}
//~Support vertex map
// Valencies data
PxU32 mNbVerts; //!< Number of vertices
PxU32 mNbAdjVerts; //!< Total number of adjacent vertices ### PT: this is useless at runtime and should not be stored here
Gu::Valency* mValencies; //!< A list of mNbVerts valencies (= number of neighbors)
PxU8* mAdjacentVerts; //!< List of adjacent vertices
//~Valencies data
};
#if PX_P64_FAMILY
PX_COMPILE_TIME_ASSERT(sizeof(Gu::BigConvexRawData) == 40);
#else
PX_COMPILE_TIME_ASSERT(sizeof(Gu::BigConvexRawData) == 24);
#endif
} // namespace Gu
}
#endif

View File

@@ -0,0 +1,88 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_BIG_CONVEX_DATA2_H
#define GU_BIG_CONVEX_DATA2_H
#include "foundation/PxVec3.h"
#include "common/PxPhysXCommonConfig.h"
#include "GuBigConvexData.h"
namespace physx
{
class PxSerializationContext;
class PxDeserializationContext;
class PX_PHYSX_COMMON_API BigConvexData : public PxUserAllocated
{
public:
// PX_SERIALIZATION
BigConvexData(const PxEMPTY) {}
//~PX_SERIALIZATION
BigConvexData();
~BigConvexData();
// Support vertex map
bool Load(PxInputStream& stream);
PxU32 ComputeOffset(const PxVec3& dir) const;
PxU32 ComputeNearestOffset(const PxVec3& dir) const;
// Data access
PX_INLINE PxU32 GetSubdiv() const { return mData.mSubdiv; }
PX_INLINE PxU32 GetNbSamples() const { return mData.mNbSamples; }
//~Support vertex map
// Valencies
// Data access
PX_INLINE PxU32 GetNbVerts() const { return mData.mNbVerts; }
PX_INLINE const Gu::Valency* GetValencies() const { return mData.mValencies; }
PX_INLINE PxU16 GetValency(PxU32 i) const { return mData.mValencies[i].mCount; }
PX_INLINE PxU16 GetOffset(PxU32 i) const { return mData.mValencies[i].mOffset; }
PX_INLINE const PxU8* GetAdjacentVerts() const { return mData.mAdjacentVerts; }
PX_INLINE PxU16 GetNbNeighbors(PxU32 i) const { return mData.mValencies[i].mCount; }
PX_INLINE const PxU8* GetNeighbors(PxU32 i) const { return &mData.mAdjacentVerts[mData.mValencies[i].mOffset]; }
// PX_SERIALIZATION
void exportExtraData(PxSerializationContext& stream);
void importExtraData(PxDeserializationContext& context);
//~PX_SERIALIZATION
Gu::BigConvexRawData mData;
protected:
void* mVBuffer;
// Internal methods
void CreateOffsets();
bool VLoad(PxInputStream& stream);
//~Valencies
friend class BigConvexDataBuilder;
};
}
#endif // BIG_CONVEX_DATA_H

View File

@@ -0,0 +1,82 @@
// 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_CONVEX_EDGE_FLAGS_H
#define GU_CONVEX_EDGE_FLAGS_H
#include "foundation/PxSimpleTypes.h"
namespace physx
{
namespace Gu
{
enum ExtraTrigDataFlag
{
ETD_SILHOUETTE_EDGE_01 = (1 << 0), //First edge is a silhouette edge
ETD_SILHOUETTE_EDGE_12 = (1 << 1), //Second edge is a silhouette edge
ETD_SILHOUETTE_EDGE_20 = (1 << 2), //Third edge is a silhouette edge
ETD_CONVEX_EDGE_01 = (1<<3), // PT: important value, don't change
ETD_CONVEX_EDGE_12 = (1<<4), // PT: important value, don't change
ETD_CONVEX_EDGE_20 = (1<<5), // PT: important value, don't change
ETD_CONVEX_EDGE_ALL = ETD_CONVEX_EDGE_01|ETD_CONVEX_EDGE_12|ETD_CONVEX_EDGE_20
};
// PT: helper function to make sure we use the proper default flags everywhere
PX_FORCE_INLINE PxU8 getConvexEdgeFlags(const PxU8* extraTrigData, PxU32 triangleIndex)
{
return extraTrigData ? extraTrigData[triangleIndex] : PxU8(ETD_CONVEX_EDGE_ALL);
}
PX_FORCE_INLINE void flipConvexEdgeFlags(PxU8& extraData)
{
// PT: this is a fix for PX-2327. When we flip the winding we also need to flip the precomputed edge flags.
// 01 => 02
// 12 => 21
// 20 => 10
const PxU8 convex01 = extraData & Gu::ETD_CONVEX_EDGE_01;
const PxU8 convex12 = extraData & Gu::ETD_CONVEX_EDGE_12;
const PxU8 convex20 = extraData & Gu::ETD_CONVEX_EDGE_20;
const PxU8 silhouette01 = extraData & Gu::ETD_SILHOUETTE_EDGE_01;
const PxU8 silhouette12 = extraData & Gu::ETD_SILHOUETTE_EDGE_12;
const PxU8 silhouette20 = extraData & Gu::ETD_SILHOUETTE_EDGE_20;
extraData = convex12|silhouette12;
if(convex01)
extraData |= Gu::ETD_CONVEX_EDGE_20;
if(convex20)
extraData |= Gu::ETD_CONVEX_EDGE_01;
if(silhouette01)
extraData |= Gu::ETD_SILHOUETTE_EDGE_20;
if(silhouette20)
extraData |= Gu::ETD_SILHOUETTE_EDGE_01;
}
}
}
#endif

View File

@@ -0,0 +1,135 @@
// 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/PxUtilities.h"
#include "GuConvexHelper.h"
#include "GuInternal.h"
#include "GuConvexMesh.h"
using namespace physx;
using namespace Gu;
// PT: we can't call alloca in a function and we want to avoid defines or duplicating the code. This makes it a bit tricky to write.
void Gu::getScaledConvex( PxVec3*& scaledVertices, PxU8*& scaledIndices, PxVec3* dstVertices, PxU8* dstIndices,
bool idtConvexScale, const PxVec3* srcVerts, const PxU8* srcIndices, PxU32 nbVerts, const Cm::FastVertex2ShapeScaling& convexScaling)
{
//pretransform convex polygon if we have scaling!
if(idtConvexScale) // PT: the scale is always 1 for boxes so no need to test the type
{
scaledVertices = const_cast<PxVec3*>(srcVerts);
scaledIndices = const_cast<PxU8*>(srcIndices);
}
else
{
scaledIndices = dstIndices;
scaledVertices = dstVertices;
for(PxU32 i=0; i<nbVerts; i++)
{
scaledIndices[i] = PxTo8(i); //generate trivial indexing.
scaledVertices[i] = convexScaling * srcVerts[srcIndices[i]];
}
}
}
bool Gu::getConvexData(const PxConvexMeshGeometry& shapeConvex, Cm::FastVertex2ShapeScaling& scaling, PxBounds3& bounds, PolygonalData& polyData)
{
const bool idtScale = shapeConvex.scale.isIdentity();
if(!idtScale)
scaling.init(shapeConvex.scale);
// PT: this version removes all the FCMPs and almost all LHS. This is temporary until
// the legacy 3x3 matrix totally vanishes but meanwhile do NOT do useless matrix conversions,
// it's a perfect recipe for LHS.
const ConvexHullData* hullData = _getHullData(shapeConvex);
PX_ASSERT(!hullData->mAABB.isEmpty());
bounds = hullData->mAABB.transformFast(scaling.getVertex2ShapeSkew());
getPolygonalData_Convex(&polyData, hullData, scaling);
// PT: non-uniform scaling invalidates the "internal objects" optimization, since our internal sphere
// might become an ellipsoid or something. Just disable the optimization if scaling is used...
if(!idtScale)
polyData.mInternal.reset();
return idtScale;
}
PxU32 Gu::findUniqueConvexEdges(PxU32 maxNbEdges, ConvexEdge* PX_RESTRICT edges, PxU32 numPolygons, const Gu::HullPolygonData* PX_RESTRICT polygons, const PxU8* PX_RESTRICT vertexData)
{
PxU32 nbEdges = 0;
while(numPolygons--)
{
const HullPolygonData& polygon = *polygons++;
const PxU8* vRefBase = vertexData + polygon.mVRef8;
PxU32 numEdges = polygon.mNbVerts;
PxU32 a = numEdges - 1;
PxU32 b = 0;
while(numEdges--)
{
PxU8 vi0 = vRefBase[a];
PxU8 vi1 = vRefBase[b];
if(vi1 < vi0)
{
PxU8 tmp = vi0;
vi0 = vi1;
vi1 = tmp;
}
bool found=false;
for(PxU32 i=0;i<nbEdges;i++)
{
if(edges[i].vref0==vi0 && edges[i].vref1==vi1)
{
found = true;
edges[i].normal += polygon.mPlane.n;
break;
}
}
if(!found)
{
if(nbEdges==maxNbEdges)
{
PX_ALWAYS_ASSERT_MESSAGE("Internal error: max nb edges reached. This shouldn't be possible...");
return nbEdges;
}
edges[nbEdges].vref0 = vi0;
edges[nbEdges].vref1 = vi1;
edges[nbEdges].normal = polygon.mPlane.n;
nbEdges++;
}
a = b;
b++;
}
}
return nbEdges;
}

View File

@@ -0,0 +1,64 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_CONVEXHELPER_H
#define GU_CONVEXHELPER_H
#include "GuShapeConvex.h"
namespace physx
{
class PxConvexMeshGeometry;
namespace Gu
{
///////////////////////////////////////////////////////////////////////////
void getScaledConvex( PxVec3*& scaledVertices, PxU8*& scaledIndices, PxVec3* dstVertices, PxU8* dstIndices,
bool idtConvexScale, const PxVec3* srcVerts, const PxU8* srcIndices, PxU32 nbVerts, const Cm::FastVertex2ShapeScaling& convexScaling);
// PT: calling this correctly isn't trivial so let's macroize it. At least we limit the damage since it immediately calls a real function.
#define GET_SCALEX_CONVEX(scaledVertices, stackIndices, idtScaling, nbVerts, scaling, srcVerts, srcIndices) \
getScaledConvex(scaledVertices, stackIndices, \
idtScaling ? NULL : reinterpret_cast<PxVec3*>(PxAlloca(nbVerts * sizeof(PxVec3))), \
idtScaling ? NULL : reinterpret_cast<PxU8*>(PxAlloca(nbVerts * sizeof(PxU8))), \
idtScaling, srcVerts, srcIndices, nbVerts, scaling);
bool getConvexData(const PxConvexMeshGeometry& shapeConvex, Cm::FastVertex2ShapeScaling& scaling, PxBounds3& bounds, PolygonalData& polyData);
struct ConvexEdge
{
PxU8 vref0;
PxU8 vref1;
PxVec3 normal; // warning: non-unit vector!
};
PxU32 findUniqueConvexEdges(PxU32 maxNbEdges, ConvexEdge* PX_RESTRICT edges, PxU32 numPolygons, const Gu::HullPolygonData* PX_RESTRICT polygons, const PxU8* PX_RESTRICT vertexData);
}
}
#endif

View File

@@ -0,0 +1,473 @@
// 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/PxFoundation.h"
#include "GuConvexMesh.h"
#include "GuBigConvexData2.h"
#include "GuMeshFactory.h"
using namespace physx;
using namespace Gu;
using namespace Cm;
bool ConvexMesh::getPolygonData(PxU32 i, PxHullPolygon& data) const
{
if(i>=mHullData.mNbPolygons)
return false;
const HullPolygonData& poly = mHullData.mPolygons[i];
data.mPlane[0] = poly.mPlane.n.x;
data.mPlane[1] = poly.mPlane.n.y;
data.mPlane[2] = poly.mPlane.n.z;
data.mPlane[3] = poly.mPlane.d;
data.mNbVerts = poly.mNbVerts;
data.mIndexBase = poly.mVRef8;
return true;
}
static void initConvexHullData(ConvexHullData& data)
{
data.mAABB.setEmpty();
data.mCenterOfMass = PxVec3(0);
data.mNbEdges = PxBitAndWord();
data.mNbHullVertices = 0;
data.mNbPolygons = 0;
data.mPolygons = NULL;
data.mBigConvexRawData = NULL;
data.mInternal.mInternalExtents = PxVec3(0.0f);
data.mInternal.mInternalRadius = 0.0f;
}
ConvexMesh::ConvexMesh(MeshFactory* factory) :
PxConvexMesh (PxConcreteType::eCONVEX_MESH, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE),
mNb (0),
mSdfData (NULL),
mBigConvexData (NULL),
mMass (0),
mInertia (PxMat33(PxIdentity)),
mMeshFactory (factory)
{
initConvexHullData(mHullData);
}
ConvexMesh::ConvexMesh(MeshFactory* factory, ConvexHullInitData& data) :
PxConvexMesh (PxConcreteType::eCONVEX_MESH, PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE),
mNb (data.mNb),
mSdfData (data.mSdfData),
mBigConvexData (data.mBigConvexData),
mMass (data.mMass),
mInertia (data.mInertia),
mMeshFactory (factory)
{
mHullData = data.mHullData;
// this constructor takes ownership of memory from the data object
data.mSdfData = NULL;
data.mBigConvexData = NULL;
}
ConvexMesh::~ConvexMesh()
{
if(getBaseFlags()&PxBaseFlag::eOWNS_MEMORY)
{
PX_FREE(mHullData.mPolygons);
PX_DELETE(mBigConvexData);
PX_DELETE(mSdfData);
}
}
bool ConvexMesh::isGpuCompatible() const
{
return mHullData.mNbHullVertices <= 64 &&
mHullData.mNbPolygons <= 64 &&
mHullData.mPolygons[0].mNbVerts <= 32 &&
mHullData.mNbEdges.isBitSet() &&
mHullData.checkExtentRadiusRatio();
}
void ConvexMesh::exportExtraData(PxSerializationContext& context)
{
context.alignData(PX_SERIAL_ALIGN);
const PxU32 bufferSize = computeBufferSize(mHullData, getNb());
context.writeData(mHullData.mPolygons, bufferSize);
if (mSdfData)
{
context.alignData(PX_SERIAL_ALIGN);
context.writeData(mSdfData, sizeof(SDF));
mSdfData->exportExtraData(context);
}
if(mBigConvexData)
{
context.alignData(PX_SERIAL_ALIGN);
context.writeData(mBigConvexData, sizeof(BigConvexData));
mBigConvexData->exportExtraData(context);
}
}
void ConvexMesh::importExtraData(PxDeserializationContext& context)
{
const PxU32 bufferSize = computeBufferSize(mHullData, getNb());
mHullData.mPolygons = reinterpret_cast<HullPolygonData*>(context.readExtraData<PxU8, PX_SERIAL_ALIGN>(bufferSize));
if (mSdfData)
{
mSdfData = context.readExtraData<SDF, PX_SERIAL_ALIGN>();
PX_PLACEMENT_NEW(mSdfData, SDF(PxEmpty));
mSdfData->importExtraData(context);
}
if(mBigConvexData)
{
mBigConvexData = context.readExtraData<BigConvexData, PX_SERIAL_ALIGN>();
PX_PLACEMENT_NEW(mBigConvexData, BigConvexData(PxEmpty));
mBigConvexData->importExtraData(context);
mHullData.mBigConvexRawData = &mBigConvexData->mData;
}
}
ConvexMesh* ConvexMesh::createObject(PxU8*& address, PxDeserializationContext& context)
{
ConvexMesh* obj = PX_PLACEMENT_NEW(address, ConvexMesh(PxBaseFlag::eIS_RELEASABLE));
address += sizeof(ConvexMesh);
obj->importExtraData(context);
obj->resolveReferences(context);
return obj;
}
static bool convexHullLoad(ConvexHullData& data, PxInputStream& stream, PxBitAndDword& bufferSize)
{
PxU32 version;
bool Mismatch;
if(!ReadHeader('C', 'L', 'H', 'L', version, Mismatch, stream))
return false;
if(version<=8)
{
if(!ReadHeader('C', 'V', 'H', 'L', version, Mismatch, stream))
return false;
}
PxU32 Nb;
// Import figures
{
PxU32 tmp[4];
ReadDwordBuffer(tmp, 4, Mismatch, stream);
data.mNbHullVertices = PxTo8(tmp[0]);
data.mNbEdges = PxTo16(tmp[1]);
data.mNbPolygons = PxTo8(tmp[2]);
Nb = tmp[3];
}
//AM: In practice the old aligner approach wastes 20 bytes and there is no reason to 20 byte align this data.
//I changed the code to just 4 align for the time being.
//On consoles if anything we will need to make this stuff 16 byte align vectors to have any sense, which will have to be done by padding data structures.
PX_ASSERT(sizeof(HullPolygonData) % sizeof(PxReal) == 0); //otherwise please pad it.
PX_ASSERT(sizeof(PxVec3) % sizeof(PxReal) == 0);
PxU32 bytesNeeded = computeBufferSize(data, Nb);
PX_FREE(data.mPolygons); // Load() can be called for an existing convex mesh. In that case we need to free the memory first.
bufferSize = Nb;
void* mDataMemory = PX_ALLOC(bytesNeeded, "ConvexHullData data");
PxU8* address = reinterpret_cast<PxU8*>(mDataMemory);
PX_ASSERT(address);
data.mPolygons = reinterpret_cast<HullPolygonData*>(address); address += sizeof(HullPolygonData) * data.mNbPolygons;
PxVec3* mDataHullVertices = reinterpret_cast<PxVec3*>(address); address += sizeof(PxVec3) * data.mNbHullVertices;
PxU8* mDataFacesByEdges8 = address; address += sizeof(PxU8) * data.mNbEdges * 2;
PxU8* mDataFacesByVertices8 = address; address += sizeof(PxU8) * data.mNbHullVertices * 3;
PxU16* mEdges = reinterpret_cast<PxU16*>(address); address += data.mNbEdges.isBitSet() ? (sizeof(PxU16) * data.mNbEdges * 2) : 0;
PxU8* mDataVertexData8 = address; address += sizeof(PxU8) * Nb; // PT: leave that one last, so that we don't need to serialize "Nb"
PX_ASSERT(!(size_t(mDataHullVertices) % sizeof(PxReal)));
PX_ASSERT(!(size_t(data.mPolygons) % sizeof(PxReal)));
PX_ASSERT(size_t(address)<=size_t(mDataMemory)+bytesNeeded);
// Import vertices
readFloatBuffer(&mDataHullVertices->x, PxU32(3*data.mNbHullVertices), Mismatch, stream);
if(version<=6)
{
PxU16 useUnquantizedNormals = readWord(Mismatch, stream);
PX_UNUSED(useUnquantizedNormals);
}
// Import polygons
stream.read(data.mPolygons, data.mNbPolygons*sizeof(HullPolygonData));
if(Mismatch)
{
for(PxU32 i=0;i<data.mNbPolygons;i++)
flipData(data.mPolygons[i]);
}
stream.read(mDataVertexData8, Nb);
stream.read(mDataFacesByEdges8, PxU32(data.mNbEdges*2));
if(version <= 5)
{
//KS - we need to compute faces-by-vertices here
bool noPlaneShift = false;
for(PxU32 i=0; i< data.mNbHullVertices; ++i)
{
PxU32 count = 0;
PxU8 inds[3];
for(PxU32 j=0; j<data.mNbPolygons; ++j)
{
HullPolygonData& polygon = data.mPolygons[j];
for(PxU32 k=0; k< polygon.mNbVerts; ++k)
{
PxU8 index = mDataVertexData8[polygon.mVRef8 + k];
if(i == index)
{
//Found a polygon
inds[count++] = PxTo8(j);
break;
}
}
if(count == 3)
break;
}
//We have 3 indices
//PX_ASSERT(count == 3);
//Do something here
if(count == 3)
{
mDataFacesByVertices8[i*3+0] = inds[0];
mDataFacesByVertices8[i*3+1] = inds[1];
mDataFacesByVertices8[i*3+2] = inds[2];
}
else
{
noPlaneShift = true;
break;
}
}
if(noPlaneShift)
{
for(PxU32 a = 0; a < data.mNbHullVertices; ++a)
{
mDataFacesByVertices8[a*3] = 0xFF;
mDataFacesByVertices8[a*3+1] = 0xFF;
mDataFacesByVertices8[a*3+2] = 0xFF;
}
}
}
else
stream.read(mDataFacesByVertices8, PxU32(data.mNbHullVertices * 3));
if (data.mNbEdges.isBitSet())
{
if (version <= 7)
{
for (PxU32 a = 0; a < PxU32(data.mNbEdges * 2); ++a)
{
mEdges[a] = 0xFFFF;
}
}
else
{
readWordBuffer(mEdges, PxU32(data.mNbEdges * 2), Mismatch, stream);
}
}
return true;
}
bool ConvexMesh::load(PxInputStream& stream)
{
// Import header
PxU32 version;
bool mismatch;
if(!readHeader('C', 'V', 'X', 'M', version, mismatch, stream))
return false;
// Check if old (incompatible) mesh format is loaded
if (version < PX_CONVEX_VERSION)
return PxGetFoundation().error(PxErrorCode::eINTERNAL_ERROR, PX_FL, "Loading convex mesh failed: Deprecated mesh cooking format.");
// Import serialization flags
PxU32 serialFlags = readDword(mismatch, stream);
PX_UNUSED(serialFlags);
if(!convexHullLoad(mHullData, stream, mNb))
return false;
// Import local bounds
float tmp[8];
readFloatBuffer(tmp, 8, mismatch, stream);
// geomEpsilon = tmp[0];
mHullData.mAABB = PxBounds3(PxVec3(tmp[1], tmp[2], tmp[3]), PxVec3(tmp[4],tmp[5],tmp[6]));
// Import mass info
mMass = tmp[7];
if(mMass!=-1.0f)
{
readFloatBuffer(&mInertia(0,0), 9, mismatch, stream);
readFloatBuffer(&mHullData.mCenterOfMass.x, 3, mismatch, stream);
}
// Import gaussmaps
PxF32 gaussMapFlag = readFloat(mismatch, stream);
if(gaussMapFlag != -1.0f)
{
PX_ASSERT(gaussMapFlag == 1.0f); //otherwise file is corrupt
PX_DELETE(mBigConvexData);
PX_NEW_SERIALIZED(mBigConvexData, BigConvexData);
if(mBigConvexData)
{
mBigConvexData->Load(stream);
mHullData.mBigConvexRawData = &mBigConvexData->mData;
}
}
//Import Sdf data
PxF32 sdfFlag = readFloat(mismatch, stream);
if (sdfFlag != -1.0f)
{
PX_ASSERT(sdfFlag == 1.0f); //otherwise file is corrupt
PX_DELETE(mSdfData);
PX_NEW_SERIALIZED(mSdfData, SDF);
if (mSdfData)
{
// Import sdf values
mSdfData->mMeshLower.x = readFloat(mismatch, stream);
mSdfData->mMeshLower.y = readFloat(mismatch, stream);
mSdfData->mMeshLower.z = readFloat(mismatch, stream);
mSdfData->mSpacing = readFloat(mismatch, stream);
mSdfData->mDims.x = readDword(mismatch, stream);
mSdfData->mDims.y = readDword(mismatch, stream);
mSdfData->mDims.z = readDword(mismatch, stream);
mSdfData->mNumSdfs = readDword(mismatch, stream);
mSdfData->mNumSubgridSdfs = readDword(mismatch, stream);
mSdfData->mNumStartSlots = readDword(mismatch, stream);
mSdfData->mSubgridSize = readDword(mismatch, stream);
mSdfData->mSdfSubgrids3DTexBlockDim.x = readDword(mismatch, stream);
mSdfData->mSdfSubgrids3DTexBlockDim.y = readDword(mismatch, stream);
mSdfData->mSdfSubgrids3DTexBlockDim.z = readDword(mismatch, stream);
mSdfData->mSubgridsMinSdfValue = readFloat(mismatch, stream);
mSdfData->mSubgridsMaxSdfValue = readFloat(mismatch, stream);
mSdfData->mBytesPerSparsePixel = readDword(mismatch, stream);
//allocate sdf
mSdfData->allocateSdfs(mSdfData->mMeshLower, mSdfData->mSpacing, mSdfData->mDims.x, mSdfData->mDims.y, mSdfData->mDims.z,
mSdfData->mSubgridSize, mSdfData->mSdfSubgrids3DTexBlockDim.x, mSdfData->mSdfSubgrids3DTexBlockDim.y, mSdfData->mSdfSubgrids3DTexBlockDim.z,
mSdfData->mSubgridsMinSdfValue, mSdfData->mSubgridsMaxSdfValue, mSdfData->mBytesPerSparsePixel);
readFloatBuffer(mSdfData->mSdf, mSdfData->mNumSdfs, mismatch, stream);
readByteBuffer(mSdfData->mSubgridSdf, mSdfData->mNumSubgridSdfs, stream);
readIntBuffer(mSdfData->mSubgridStartSlots, mSdfData->mNumStartSlots, mismatch, stream);
mHullData.mSdfData = mSdfData;
}
}
/*
printf("\n\n");
printf("COM: %f %f %f\n", massInfo.centerOfMass.x, massInfo.centerOfMass.y, massInfo.centerOfMass.z);
printf("BND: %f %f %f\n", mHullData.aabb.getCenter().x, mHullData.aabb.getCenter().y, mHullData.aabb.getCenter().z);
printf("CNT: %f %f %f\n", mHullData.mCenterxx.x, mHullData.mCenterxx.y, mHullData.mCenterxx.z);
printf("COM-BND: %f BND-CNT: %f, CNT-COM: %f\n", (massInfo.centerOfMass - mHullData.aabb.getCenter()).magnitude(), (mHullData.aabb.getCenter() - mHullData.mCenterxx).magnitude(), (mHullData.mCenterxx - massInfo.centerOfMass).magnitude());
*/
// TEST_INTERNAL_OBJECTS
// PT: this data was saved in ConvexMeshBuilder::save(), in this order: 'radius' first then 'extents'.
// That order matched the previous in-memory data structure, but it changed later. So we read the data to a temp buffer and copy it afterwards.
float internalObjectsData[4];
readFloatBuffer(internalObjectsData, 4, mismatch, stream);
mHullData.mInternal.mInternalRadius = internalObjectsData[0];
mHullData.mInternal.mInternalExtents.x = internalObjectsData[1];
mHullData.mInternal.mInternalExtents.y = internalObjectsData[2];
mHullData.mInternal.mInternalExtents.z = internalObjectsData[3];
PX_ASSERT(mHullData.mInternal.mInternalExtents.isFinite());
PX_ASSERT(mHullData.mInternal.mInternalExtents.x != 0.0f);
PX_ASSERT(mHullData.mInternal.mInternalExtents.y != 0.0f);
PX_ASSERT(mHullData.mInternal.mInternalExtents.z != 0.0f);
//~TEST_INTERNAL_OBJECTS
return true;
}
void ConvexMesh::release()
{
RefCountable_decRefCount(*this);
}
void ConvexMesh::onRefCountZero()
{
// when the mesh failed to load properly, it will not have been added to the convex array
::onRefCountZero(this, mMeshFactory, !getBufferSize(), "PxConvexMesh::release: double deletion detected!");
}
void ConvexMesh::acquireReference()
{
RefCountable_incRefCount(*this);
}
PxU32 ConvexMesh::getReferenceCount() const
{
return RefCountable_getRefCount(*this);
}
void ConvexMesh::getMassInformation(PxReal& mass, PxMat33& localInertia, PxVec3& localCenterOfMass) const
{
mass = ConvexMesh::getMass();
localInertia = ConvexMesh::getInertia();
localCenterOfMass = ConvexMesh::getHull().mCenterOfMass;
}
PxBounds3 ConvexMesh::getLocalBounds() const
{
PX_ASSERT(mHullData.mAABB.isValid());
return PxBounds3::centerExtents(mHullData.mAABB.mCenter, mHullData.mAABB.mExtents);
}
const PxReal* ConvexMesh::getSDF() const
{
if(mSdfData)
return mSdfData->mSdf;
return NULL;
}

View File

@@ -0,0 +1,187 @@
// 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_CONVEX_MESH_H
#define GU_CONVEX_MESH_H
#include "foundation/PxBitAndData.h"
#include "geometry/PxConvexMesh.h"
#include "geometry/PxConvexMeshGeometry.h"
#include "foundation/PxUserAllocated.h"
#include "CmRefCountable.h"
#include "common/PxRenderOutput.h"
#include "GuConvexMeshData.h"
namespace physx
{
class BigConvexData;
namespace Gu
{
class MeshFactory;
struct HullPolygonData;
PX_INLINE PxU32 computeBufferSize(const Gu::ConvexHullData& data, PxU32 nb)
{
PxU32 bytesNeeded = sizeof(Gu::HullPolygonData) * data.mNbPolygons;
bytesNeeded += sizeof(PxVec3) * data.mNbHullVertices;
bytesNeeded += sizeof(PxU8) * data.mNbEdges * 2; // mFacesByEdges8
bytesNeeded += sizeof(PxU8) * data.mNbHullVertices * 3; // mFacesByVertices8;
bytesNeeded += data.mNbEdges.isBitSet() ? (sizeof(PxU16) * data.mNbEdges * 2) : 0; // mEdges;
bytesNeeded += sizeof(PxU8) * nb; // mVertexData8
//4 align the whole thing!
const PxU32 mod = bytesNeeded % sizeof(PxReal);
if (mod)
bytesNeeded += sizeof(PxReal) - mod;
return bytesNeeded;
}
struct ConvexHullInitData
{
ConvexHullData mHullData;
PxU32 mNb;
PxReal mMass;
PxMat33 mInertia;
BigConvexData* mBigConvexData;
SDF* mSdfData;
};
// 0: includes raycast map
// 1: discarded raycast map
// 2: support map not always there
// 3: support stackless trees for non-recursive collision queries
// 4: no more opcode model
// 5: valencies table and gauss map combined, only exported over a vertex count treshold that depends on the platform cooked for.
// 6: removed support for edgeData16.
// 7: removed support for edge8Data.
// 8: removed support for triangles.
// 9: removed local sphere.
//10: removed geometric center.
//11: removed mFlags, and mERef16 from Poly; nbVerts is just a byte.
//12: removed explicit minimum, maximum from Poly
//13: internal objects
//14: SDF
#define PX_CONVEX_VERSION 14
class ConvexMesh : public PxConvexMesh, public PxUserAllocated
{
public:
// PX_SERIALIZATION
ConvexMesh(PxBaseFlags baseFlags) : PxConvexMesh(baseFlags), mHullData(PxEmpty), mNb(PxEmpty)
{
mNb.setBit();
}
void preExportDataReset() { Cm::RefCountable_preExportDataReset(*this); }
virtual void exportExtraData(PxSerializationContext& stream);
void importExtraData(PxDeserializationContext& context);
PX_PHYSX_COMMON_API static ConvexMesh* createObject(PxU8*& address, PxDeserializationContext& context);
void resolveReferences(PxDeserializationContext&) {}
virtual void requiresObjects(PxProcessPxBaseCallback&){}
//~PX_SERIALIZATION
ConvexMesh(MeshFactory* factory);
ConvexMesh(MeshFactory* factory, ConvexHullInitData& data);
bool load(PxInputStream& stream);
// PxBase
virtual void onRefCountZero();
//~PxBase
// PxRefCounted
virtual PxU32 getReferenceCount() const;
virtual void acquireReference();
//~PxRefCounted
// PxConvexMesh
virtual void release();
virtual PxU32 getNbVertices() const { return mHullData.mNbHullVertices; }
virtual const PxVec3* getVertices() const { return mHullData.getHullVertices(); }
virtual const PxU8* getIndexBuffer() const { return mHullData.getVertexData8(); }
virtual PxU32 getNbPolygons() const { return mHullData.mNbPolygons; }
virtual bool getPolygonData(PxU32 i, PxHullPolygon& data) const;
virtual bool isGpuCompatible() const;
virtual void getMassInformation(PxReal& mass, PxMat33& localInertia, PxVec3& localCenterOfMass) const;
virtual PxBounds3 getLocalBounds() const;
virtual const PxReal* getSDF() const;
//~PxConvexMesh
PX_FORCE_INLINE PxU32 getNbVerts() const { return mHullData.mNbHullVertices; }
PX_FORCE_INLINE const PxVec3* getVerts() const { return mHullData.getHullVertices(); }
PX_FORCE_INLINE PxU32 getNbPolygonsFast() const { return mHullData.mNbPolygons; }
PX_FORCE_INLINE const HullPolygonData& getPolygon(PxU32 i) const { return mHullData.mPolygons[i]; }
PX_FORCE_INLINE const HullPolygonData* getPolygons() const { return mHullData.mPolygons; }
PX_FORCE_INLINE PxU32 getNbEdges() const { return mHullData.mNbEdges; }
PX_FORCE_INLINE const ConvexHullData& getHull() const { return mHullData; }
PX_FORCE_INLINE ConvexHullData& getHull() { return mHullData; }
PX_FORCE_INLINE const CenterExtents& getLocalBoundsFast() const { return mHullData.mAABB; }
PX_FORCE_INLINE PxReal getMass() const { return mMass; }
PX_FORCE_INLINE void setMass(PxReal mass) { mMass = mass; }
PX_FORCE_INLINE const PxMat33& getInertia() const { return mInertia; }
PX_FORCE_INLINE void setInertia(const PxMat33& inertia) { mInertia = inertia; }
PX_FORCE_INLINE BigConvexData* getBigConvexData() const { return mBigConvexData; }
PX_FORCE_INLINE void setBigConvexData(BigConvexData* bcd) { mBigConvexData = bcd; }
PX_FORCE_INLINE PxU32 getBufferSize() const { return computeBufferSize(mHullData, getNb()); }
virtual ~ConvexMesh();
PX_FORCE_INLINE void setMeshFactory(MeshFactory* f) { mMeshFactory = f; }
PX_FORCE_INLINE void setNb(PxU32 nb) { mNb = nb; }
protected:
ConvexHullData mHullData;
PxBitAndDword mNb; // ### PT: added for serialization. Try to remove later?
SDF* mSdfData;
BigConvexData* mBigConvexData; //!< optional, only for large meshes! PT: redundant with ptr in chull data? Could also be end of other buffer
PxReal mMass; //this is mass assuming a unit density that can be scaled by instances!
PxMat33 mInertia; //in local space of mesh!
private:
MeshFactory* mMeshFactory; // PT: changed to pointer for serialization
PX_FORCE_INLINE PxU32 getNb() const { return mNb; }
PX_FORCE_INLINE PxU32 ownsMemory() const { return PxU32(!mNb.isBitSet()); }
};
PX_FORCE_INLINE const Gu::ConvexHullData* _getHullData(const PxConvexMeshGeometry& convexGeom)
{
return &static_cast<const Gu::ConvexMesh*>(convexGeom.convexMesh)->getHull();
}
} // namespace Gu
}
#endif

View File

@@ -0,0 +1,208 @@
// 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_CONVEX_MESH_DATA_H
#define GU_CONVEX_MESH_DATA_H
#include "foundation/PxPlane.h"
#include "foundation/PxBitAndData.h"
#include "foundation/PxIntrinsics.h"
#include "GuCenterExtents.h"
#include "CmSerialize.h"
#include "GuSDF.h"
// Data definition
namespace physx
{
namespace Gu
{
struct BigConvexRawData;
struct HullPolygonData
{
// PT: this structure won't be allocated with PX_NEW because polygons aren't allocated alone (with a dedicated alloc).
// Instead they are part of a unique allocation/buffer containing all data for the ConvexHullData class (polygons, followed by
// hull vertices, edge data, etc). As a result, ctors for embedded classes like PxPlane won't be called.
PxPlane mPlane; //!< Plane equation for this polygon //Could drop 4th elem as it can be computed from any vertex as: d = - p.dot(n);
PxU16 mVRef8; //!< Offset of vertex references in hull vertex data (CS: can we assume indices are tightly packed and offsets are ascending?? DrawObjects makes and uses this assumption)
PxU8 mNbVerts; //!< Number of vertices/edges in the polygon
PxU8 mMinIndex; //!< Index of the polygon vertex that has minimal projection along this plane's normal.
PX_FORCE_INLINE PxReal getMin(const PxVec3* PX_RESTRICT hullVertices) const //minimum of projection of the hull along this plane normal
{
return mPlane.n.dot(hullVertices[mMinIndex]);
}
PX_FORCE_INLINE PxReal getMax() const { return -mPlane.d; } //maximum of projection of the hull along this plane normal
};
PX_FORCE_INLINE void flipData(Gu::HullPolygonData& data)
{
flip(data.mPlane.n.x);
flip(data.mPlane.n.y);
flip(data.mPlane.n.z);
flip(data.mPlane.d);
flip(data.mVRef8);
}
// PT: if this one breaks, please make sure the 'flipData' function is properly updated.
PX_COMPILE_TIME_ASSERT(sizeof(Gu::HullPolygonData) == 20);
// TEST_INTERNAL_OBJECTS
struct InternalObjectsData
{
PxVec3 mInternalExtents;
PxReal mInternalRadius;
PX_FORCE_INLINE void reset()
{
mInternalExtents = PxVec3(0.0f);
mInternalRadius = 0.0f;
}
};
PX_COMPILE_TIME_ASSERT(sizeof(Gu::InternalObjectsData) == 16);
// PT: ensure that mInternalExtents is not the last member of InternalObjectsData, i.e. it is safe to load 4 bytes after mInternalExtents
PX_COMPILE_TIME_ASSERT(PX_OFFSET_OF(InternalObjectsData, mInternalExtents)+sizeof(InternalObjectsData::mInternalExtents) + 4 <= sizeof(InternalObjectsData));
//~TEST_INTERNAL_OBJECTS
struct ConvexHullData
{
// PT: WARNING: bounds must be followed by at least 32bits of data for safe SIMD loading
CenterExtents mAABB; //!< bounds TODO: compute this on the fly from first 6 vertices in the vertex array. We'll of course need to sort the most extreme ones to the front.
PxVec3 mCenterOfMass; //in local space of mesh!
// PT: WARNING: mNbHullVertices *must* appear before mBigConvexRawData for ConvX to be able to do "big raw data" surgery
PxBitAndWord mNbEdges; //!<the highest bit indicate whether we have grb data, the other 15 bits indicate the number of edges in this convex hull
PxU8 mNbHullVertices; //!< Number of vertices in the convex hull
PxU8 mNbPolygons; //!< Number of planar polygons composing the hull
HullPolygonData* mPolygons; //!< Array of mNbPolygons structures
BigConvexRawData* mBigConvexRawData; //!< Hill climbing data, only for large convexes! else NULL.
// SDF data
SDF* mSdfData;
// TEST_INTERNAL_OBJECTS
InternalObjectsData mInternal;
//~TEST_INTERNAL_OBJECTS
PX_FORCE_INLINE ConvexHullData(const PxEMPTY) : mNbEdges(PxEmpty)
{
}
PX_FORCE_INLINE ConvexHullData()
{
}
PX_FORCE_INLINE const CenterExtentsPadded& getPaddedBounds() const
{
// PT: see compile-time assert at the end of file
return static_cast<const CenterExtentsPadded&>(mAABB);
}
PX_FORCE_INLINE const PxVec3* getHullVertices() const //!< Convex hull vertices
{
const char* tmp = reinterpret_cast<const char*>(mPolygons);
tmp += sizeof(Gu::HullPolygonData) * mNbPolygons;
return reinterpret_cast<const PxVec3*>(tmp);
}
PX_FORCE_INLINE const PxU8* getFacesByEdges8() const //!< for each edge, gives 2 adjacent polygons; used by convex-convex code to come up with all the convex' edge normals.
{
const char* tmp = reinterpret_cast<const char*>(mPolygons);
tmp += sizeof(Gu::HullPolygonData) * mNbPolygons;
tmp += sizeof(PxVec3) * mNbHullVertices;
return reinterpret_cast<const PxU8*>(tmp);
}
PX_FORCE_INLINE const PxU8* getFacesByVertices8() const //!< for each edge, gives 2 adjacent polygons; used by convex-convex code to come up with all the convex' edge normals.
{
const char* tmp = reinterpret_cast<const char*>(mPolygons);
tmp += sizeof(Gu::HullPolygonData) * mNbPolygons;
tmp += sizeof(PxVec3) * mNbHullVertices;
tmp += sizeof(PxU8) * mNbEdges * 2;
return reinterpret_cast<const PxU8*>(tmp);
}
//If we don't build the convex hull with grb data, we will return NULL pointer
PX_FORCE_INLINE const PxU16* getVerticesByEdges16() const //!< Vertex indices indexed by unique edges
{
if (mNbEdges.isBitSet())
{
const char* tmp = reinterpret_cast<const char*>(mPolygons);
tmp += sizeof(Gu::HullPolygonData) * mNbPolygons;
tmp += sizeof(PxVec3) * mNbHullVertices;
tmp += sizeof(PxU8) * mNbEdges * 2;
tmp += sizeof(PxU8) * mNbHullVertices * 3;
return reinterpret_cast<const PxU16*>(tmp);
}
return NULL;
}
PX_FORCE_INLINE const PxU8* getVertexData8() const //!< Vertex indices indexed by hull polygons
{
const char* tmp = reinterpret_cast<const char*>(mPolygons);
tmp += sizeof(Gu::HullPolygonData) * mNbPolygons;
tmp += sizeof(PxVec3) * mNbHullVertices;
tmp += sizeof(PxU8) * mNbEdges * 2;
tmp += sizeof(PxU8) * mNbHullVertices * 3;
if (mNbEdges.isBitSet())
tmp += sizeof(PxU16) * mNbEdges * 2;
return reinterpret_cast<const PxU8*>(tmp);
}
PX_FORCE_INLINE bool checkExtentRadiusRatio() const
{
const PxReal maxR = mInternal.mInternalExtents.maxElement();
const PxReal minR = mInternal.mInternalRadius;
const PxReal ratio = maxR/minR;
return ratio < 100.f;
}
};
#if PX_P64_FAMILY
PX_COMPILE_TIME_ASSERT(sizeof(Gu::ConvexHullData) == 80);
#else
PX_COMPILE_TIME_ASSERT(sizeof(Gu::ConvexHullData) == 68);
#endif
// PT: 'getPaddedBounds()' is only safe if we make sure the bounds member is followed by at least 32bits of data
PX_COMPILE_TIME_ASSERT(PX_OFFSET_OF(Gu::ConvexHullData, mCenterOfMass)>=PX_OFFSET_OF(Gu::ConvexHullData, mAABB)+4);
} // namespace Gu
}
//#pragma PX_POP_PACK
#endif

View File

@@ -0,0 +1,43 @@
// 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 "GuVecBox.h"
namespace physx
{
const aos::BoolV boxVertexTable[8] = {
aos::BFFFF(),//---
aos::BTFFF(),//+--
aos::BFTFF(),//-+-
aos::BTTFF(),//++-
aos::BFFTF(),//--+
aos::BTFTF(),//+-+
aos::BFTTF(),//-++
aos::BTTTF(),//+++
};
}

View File

@@ -0,0 +1,116 @@
// 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_CONVEX_SUPPORT_TABLE_H
#define GU_CONVEX_SUPPORT_TABLE_H
#include "common/PxPhysXCommonConfig.h"
#include "GuVecConvex.h"
#include "foundation/PxVecTransform.h"
namespace physx
{
namespace Gu
{
class TriangleV;
class CapsuleV;
class BoxV;
class ConvexHullV;
class ConvexHullNoScaleV;
#if PX_VC
#pragma warning(push)
#pragma warning( disable : 4324 ) // Padding was added at the end of a structure because of a __declspec(align) value.
#endif
class SupportLocal
{
public:
aos::Vec3V shapeSpaceCenterOfMass;
const aos::PxTransformV& transform;
const aos::Mat33V& vertex2Shape;
const aos::Mat33V& shape2Vertex;
const bool isIdentityScale;
SupportLocal(const aos::PxTransformV& _transform, const aos::Mat33V& _vertex2Shape, const aos::Mat33V& _shape2Vertex, const bool _isIdentityScale = true): transform(_transform),
vertex2Shape(_vertex2Shape), shape2Vertex(_shape2Vertex), isIdentityScale(_isIdentityScale)
{
}
PX_FORCE_INLINE void setShapeSpaceCenterofMass(const aos::Vec3VArg _shapeSpaceCenterOfMass)
{
shapeSpaceCenterOfMass = _shapeSpaceCenterOfMass;
}
virtual ~SupportLocal() {}
virtual aos::Vec3V doSupport(const aos::Vec3VArg dir) const = 0;
virtual void doSupport(const aos::Vec3VArg dir, aos::FloatV& min, aos::FloatV& max) const = 0;
virtual void populateVerts(const PxU8* inds, PxU32 numInds, const PxVec3* originalVerts, aos::Vec3V* verts)const = 0;
protected:
SupportLocal& operator=(const SupportLocal&);
};
#if PX_VC
#pragma warning(pop)
#endif
template <typename Convex>
class SupportLocalImpl : public SupportLocal
{
public:
const Convex& conv;
SupportLocalImpl(const Convex& _conv, const aos::PxTransformV& _transform, const aos::Mat33V& _vertex2Shape, const aos::Mat33V& _shape2Vertex, const bool _isIdentityScale = true) :
SupportLocal(_transform, _vertex2Shape, _shape2Vertex, _isIdentityScale), conv(_conv)
{
}
aos::Vec3V doSupport(const aos::Vec3VArg dir) const
{
//return conv.supportVertsLocal(dir);
return conv.supportLocal(dir);
}
void doSupport(const aos::Vec3VArg dir, aos::FloatV& min, aos::FloatV& max) const
{
return conv.supportLocal(dir, min, max);
}
void populateVerts(const PxU8* inds, PxU32 numInds, const PxVec3* originalVerts, aos::Vec3V* verts) const
{
conv.populateVerts(inds, numInds, originalVerts, verts);
}
protected:
SupportLocalImpl& operator=(const SupportLocalImpl&);
};
}
}
#endif

View File

@@ -0,0 +1,77 @@
// 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/PxBounds3.h"
#include "geometry/PxConvexMeshGeometry.h"
#include "GuConvexUtilsInternal.h"
#include "GuBoxConversion.h"
#include "GuConvexMesh.h"
#include "CmScaling.h"
#include "CmMatrix34.h"
using namespace physx;
using namespace Gu;
using namespace Cm;
void Gu::computeHullOBB(Box& hullOBB, const PxBounds3& hullAABB, float offset,
const PxMat34& convexPose,
const PxMat34& meshPose, const FastVertex2ShapeScaling& meshScaling, bool idtScaleMesh)
{
// transform bounds = mesh space
const PxMat34 m0to1 = meshPose.transformTranspose(convexPose);
hullOBB.extents = hullAABB.getExtents() + PxVec3(offset);
hullOBB.center = m0to1.transform(hullAABB.getCenter());
hullOBB.rot = m0to1.m;
if(!idtScaleMesh)
meshScaling.transformQueryBounds(hullOBB.center, hullOBB.extents, hullOBB.rot);
}
void Gu::computeVertexSpaceOBB(Box& dst, const Box& src, const PxTransform& meshPose, const PxMeshScale& meshScale)
{
// AP scaffold failure in x64 debug in GuConvexUtilsInternal.cpp
//PX_ASSERT("Performance warning - this path shouldn't execute for identity mesh scale." && !meshScale.isIdentity());
dst = transform(meshScale.getInverse() * Matrix34FromTransform(meshPose.getInverse()), src);
}
void Gu::computeOBBAroundConvex(Box& obb, const PxConvexMeshGeometry& convexGeom, const PxConvexMesh* cm, const PxTransform& convexPose)
{
const CenterExtents& aabb = static_cast<const Gu::ConvexMesh*>(cm)->getLocalBoundsFast();
if(convexGeom.scale.isIdentity())
{
const PxMat33Padded m(convexPose.q);
obb = Gu::Box(m.transform(aabb.mCenter) + convexPose.p, aabb.mExtents, m);
}
else
{
obb = transform(Matrix34FromTransform(convexPose) * toMat33(convexGeom.scale), Box(aabb.mCenter, aabb.mExtents, PxMat33(PxIdentity)));
}
}

View File

@@ -0,0 +1,66 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_CONVEX_UTILS_INTERNALS_H
#define GU_CONVEX_UTILS_INTERNALS_H
#include "foundation/PxMat34.h"
#include "foundation/PxBounds3.h"
#include "common/PxPhysXCommonConfig.h"
namespace physx
{
class PxMeshScale;
class PxConvexMeshGeometry;
class PxConvexMesh;
namespace Cm
{
class FastVertex2ShapeScaling;
}
namespace Gu
{
class Box;
void computeHullOBB(
Gu::Box& hullOBB, const PxBounds3& hullAABB, float offset, const PxMat34& world0,
const PxMat34& world1, const Cm::FastVertex2ShapeScaling& meshScaling, bool idtScaleMesh);
// src = input
// computes a box in vertex space (including skewed scale) from src world box
void computeVertexSpaceOBB(Gu::Box& dst, const Gu::Box& src, const PxTransform& meshPose, const PxMeshScale& meshScale);
PX_PHYSX_COMMON_API void computeOBBAroundConvex(
Gu::Box& obb, const PxConvexMeshGeometry& convexGeom, const PxConvexMesh* cm, const PxTransform& convexPose);
} // namespace Gu
}
#endif

View File

@@ -0,0 +1,153 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_CUBE_INDEX_H
#define GU_CUBE_INDEX_H
#include "foundation/PxVec3.h"
#include "foundation/PxFPU.h"
namespace physx
{
enum CubeIndex
{
CUBE_RIGHT,
CUBE_LEFT,
CUBE_TOP,
CUBE_BOTTOM,
CUBE_FRONT,
CUBE_BACK,
CUBE_FORCE_DWORD = 0x7fffffff
};
/*
It's pretty straightforwards in concept (though the execution in hardware is
a bit crufty and complex). You use a 3D texture coord to look up a texel in
a cube map. First you find which of the axis has the largest value (i.e.
X,Y,Z), and then the sign of that axis decides which face you are going to
use. Which is why the faces are called +X, -X, +Y, -Y, +Z, -Z - after their
principle axis. Then you scale the vector so that the largest value is +/-1.
Then use the other two as 2D coords to look up your texel (with a 0.5 scale
& offset).
For example, vector (0.4, -0.2, -0.5). Largest value is the Z axis, and it's
-ve, so we're reading from the -Z map. Scale so that this Z axis is +/-1,
and you get the vector (0.8, -0.4, -1.0). So now use the other two values to
look up your texel. So we look up texel (0.8, -0.4). The scale & offset move
the -1->+1 range into the usual 0->1 UV range, so we actually look up texel
(0.9, 0.3). The filtering is extremely complex, especially where three maps
meet, but that's a hardware problem :-)
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Cubemap lookup function.
*
* To transform returned uvs into mapping coordinates :
* u += 1.0f; u *= 0.5f;
* v += 1.0f; v *= 0.5f;
*
* \fn CubemapLookup(const PxVec3& direction, float& u, float& v)
* \param direction [in] a direction vector
* \param u [out] impact coordinate on the unit cube, in [-1,1]
* \param v [out] impact coordinate on the unit cube, in [-1,1]
* \return cubemap texture index
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PX_INLINE CubeIndex CubemapLookup(const PxVec3& direction, float& u, float& v);
PX_INLINE PxU32 ComputeCubemapOffset(const PxVec3& dir, PxU32 subdiv)
{
float u,v;
const CubeIndex CI = CubemapLookup(dir, u, v);
// Remap to [0, subdiv[
const float Coeff = 0.5f * float(subdiv-1);
u += 1.0f; u *= Coeff;
v += 1.0f; v *= Coeff;
// Compute offset
return PxU32(CI)*(subdiv*subdiv) + PxU32(u)*subdiv + PxU32(v);
}
PX_INLINE PxU32 ComputeCubemapNearestOffset(const PxVec3& dir, PxU32 subdiv)
{
float u,v;
const CubeIndex CI = CubemapLookup(dir, u, v);
// Remap to [0, subdiv]
const float Coeff = 0.5f * float(subdiv-1);
u += 1.0f; u *= Coeff;
v += 1.0f; v *= Coeff;
// Compute offset
return PxU32(CI)*(subdiv*subdiv) + PxU32(u + 0.5f)*subdiv + PxU32(v + 0.5f);
}
PX_INLINE CubeIndex CubemapLookup(const PxVec3& direction, float& u, float& v)
{
const PxU32* binary = reinterpret_cast<const PxU32*>(&direction.x);
const PxU32 absPx = binary[0] & ~PX_SIGN_BITMASK;
const PxU32 absNy = binary[1] & ~PX_SIGN_BITMASK;
const PxU32 absNz = binary[2] & ~PX_SIGN_BITMASK;
PxU32 Index1 = 0; //x biggest axis
PxU32 Index2 = 1;
PxU32 Index3 = 2;
if( (absNy > absPx) & (absNy > absNz))
{
//y biggest
Index2 = 2;
Index3 = 0;
Index1 = 1;
}
else if(absNz > absPx)
{
//z biggest
Index2 = 0;
Index3 = 1;
Index1 = 2;
}
const PxF32* data = &direction.x;
const float Coeff = 1.0f / fabsf(data[Index1]);
u = data[Index2] * Coeff;
v = data[Index3] * Coeff;
const PxU32 Sign = binary[Index1]>>31;
return CubeIndex(Sign|(Index1+Index1));
}
}
#endif

View File

@@ -0,0 +1,94 @@
// 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/PxVec3.h"
#include "foundation/PxAssert.h"
#include "foundation/PxUserAllocated.h"
#include "GuHillClimbing.h"
#include "GuBigConvexData2.h"
namespace physx
{
void localSearch(PxU32& id, const PxVec3& dir, const PxVec3* verts, const Gu::BigConvexRawData* val)
{
// WARNING: there is a problem on x86 with a naive version of this code, where truncation
// of values from 80 bits to 32 bits as they're stored in memory means that iteratively moving to
// an adjacent vertex of greater support can go into an infinite loop. So we use a version which
// never visits a vertex twice. Note - this might not be enough for GJK, since local
// termination of the support function might not be enough to ensure convergence of GJK itself.
// if we got here, we'd better have vertices and valencies
PX_ASSERT(verts && val);
class TinyBitMap
{
public:
PxU32 m[8];
PX_FORCE_INLINE TinyBitMap() { m[0] = m[1] = m[2] = m[3] = m[4] = m[5] = m[6] = m[7] = 0; }
PX_FORCE_INLINE void set(PxU8 v) { m[v>>5] |= 1<<(v&31); }
PX_FORCE_INLINE bool get(PxU8 v) const { return (m[v>>5] & 1<<(v&31)) != 0; }
};
TinyBitMap visited;
const Gu::Valency* Valencies = val->mValencies;
const PxU8* Adj = val->mAdjacentVerts;
PX_ASSERT(Valencies && Adj);
// Get the initial value and the initial vertex
float MaxVal = dir.dot(verts[id]);
PxU32 NextVtx = id;
do
{
PxU16 NbNeighbors = Valencies[NextVtx].mCount;
const PxU8* Run = Adj + Valencies[NextVtx].mOffset;
id = NextVtx;
while(NbNeighbors--)
{
const PxU8 Neighbor = *Run++;
if(!visited.get(Neighbor))
{
visited.set(Neighbor);
const float CurVal = dir.dot(verts[Neighbor]);
if(CurVal>MaxVal)
{
MaxVal = CurVal;
NextVtx = Neighbor;
}
}
}
} while(NextVtx!=id);
}
}

View File

@@ -0,0 +1,44 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_HILL_CLIMBING_H
#define GU_HILL_CLIMBING_H
#include "common/PxPhysXCommonConfig.h"
namespace physx
{
namespace Gu
{
struct BigConvexRawData;
}
void localSearch(PxU32& id, const PxVec3& dir, const PxVec3* verts, const Gu::BigConvexRawData* val);
}
#endif

View File

@@ -0,0 +1,513 @@
// 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 "GuShapeConvex.h"
#include "GuBigConvexData.h"
#include "GuEdgeList.h"
#include "GuInternal.h"
#include "foundation/PxMat34.h"
#include "GuHillClimbing.h"
#include "foundation/PxFPU.h"
using namespace physx;
using namespace Gu;
static PX_FORCE_INLINE PxU32 selectClosestPolygon(PxReal& maxDp_, PxU32 numPolygons, const Gu::HullPolygonData* polys, const PxVec3& axis)
{
float maxDp = polys[0].mPlane.n.dot(axis);
PxU32 closest = 0;
// Loop through polygons
for(PxU32 i=1; i <numPolygons; i++)
{
// Catch current polygon and test its plane
const PxReal dp = polys[i].mPlane.n.dot(axis);
if(dp>maxDp)
{
maxDp = dp;
closest = i;
}
}
maxDp_ = maxDp;
return closest;
}
static PxU32 SelectClosestEdgeCB_Convex(const PolygonalData& data, const Cm::FastVertex2ShapeScaling& scaling, const PxVec3& localSpaceDirection)
{
//vertex1TOShape1Skew is a symmetric matrix.
//it has the property that (vertex1TOShape1Skew * v)|localSpaceDirection == (vertex1TOShape1Skew * localSpaceDirection)|v
const PxVec3 vertexSpaceDirection = scaling * localSpaceDirection;
const Gu::HullPolygonData* PX_RESTRICT polys = data.mPolygons;
PxReal maxDp;
// ##might not be needed
PxU32 closest = ::selectClosestPolygon(maxDp, data.mNbPolygons, polys, vertexSpaceDirection);
// Since the convex is closed, at least some poly must satisfy this
PX_ASSERT(maxDp>=0);
const PxU32 numEdges = data.mNbEdges;
const PxU8* const edgeToFace = data.mFacesByEdges;
//Loop through edges
PxU32 closestEdge = 0xffffffff;
PxReal maxDpSq = maxDp * maxDp;
for(PxU32 i=0; i < numEdges; i++)
{
const PxU8 f0 = edgeToFace[i*2];
const PxU8 f1 = edgeToFace[i*2+1];
// unnormalized edge normal
const PxVec3 edgeNormal = polys[f0].mPlane.n + polys[f1].mPlane.n;
const PxReal enMagSq = edgeNormal.magnitudeSquared();
//Test normal of current edge - squared test is valid if dp and maxDp both >= 0
const float dp = edgeNormal.dot(vertexSpaceDirection);
if(dp>=0.0f && dp*dp>maxDpSq*enMagSq)
{
maxDpSq = dp*dp/enMagSq;
closestEdge = i;
}
}
if(closestEdge!=0xffffffff)
{
const PxU8* FBE = edgeToFace;
const PxU32 f0 = FBE[closestEdge*2];
const PxU32 f1 = FBE[closestEdge*2+1];
const PxReal dp0 = polys[f0].mPlane.n.dot(vertexSpaceDirection);
const PxReal dp1 = polys[f1].mPlane.n.dot(vertexSpaceDirection);
if(dp0>dp1)
closest = f0;
else
closest = f1;
}
return closest;
}
// Hull projection callback for "small" hulls
static void HullProjectionCB_SmallConvex(const PolygonalData& data, const PxVec3& dir,
const PxMat34& world,
const Cm::FastVertex2ShapeScaling& scaling,
PxReal& min, PxReal& max)
{
const PxVec3 localSpaceDirection = world.rotateTranspose(dir);
//vertex1TOShape1Skew is a symmetric matrix.
//it has the property that (vertex1TOShape1Skew * v)|localSpaceDirection == (vertex1TOShape1Skew * localSpaceDirection)|v
const PxVec3 vertexSpaceDirection = scaling * localSpaceDirection;
// PT: prevents aliasing
PxReal minimum = PX_MAX_REAL;
PxReal maximum = -PX_MAX_REAL;
//brute-force, localspace
{
const PxVec3* PX_RESTRICT verts = data.mVerts;
PxU32 numVerts = data.mNbVerts;
while(numVerts--)
{
const PxReal dp = (*verts++).dot(vertexSpaceDirection);
minimum = physx::intrinsics::selectMin(minimum, dp);
maximum = physx::intrinsics::selectMax(maximum, dp);
}
}
const PxReal offset = world.p.dot(dir);
min = minimum + offset;
max = maximum + offset;
}
static PxU32 computeNearestOffset(const PxU32 subdiv, const PxVec3& dir)
{
// ComputeCubemapNearestOffset(const Point& dir, udword subdiv)
// PT: ok so why exactly was the code duplicated here?
// PxU32 CI = CubemapLookup(dir,u,v)
PxU32 index;
PxReal coeff;
// find largest axis
PxReal absNx = PxAbs(dir.x);
PxReal absNy = PxAbs(dir.y);
PxReal absNz = PxAbs(dir.z);
if( absNy > absNx &&
absNy > absNz)
{
//y biggest
index = 1;
coeff = 1.0f/absNy;
}
else if(absNz > absNx)
{
index = 2;
coeff = 1.0f/absNz;
}
else
{
index = 0;
coeff = 1.0f/absNx;
}
union
{
PxU32 aU32;
PxReal aFloat;
} conv;
conv.aFloat = dir[index];
PxU32 sign = conv.aU32>>31;
const PxU32 index2 = PxGetNextIndex3(index);
const PxU32 index3 = PxGetNextIndex3(index2);
PxReal u = dir[index2] * coeff;
PxReal v = dir[index3] * coeff;
PxU32 CI = (sign | (index+index));
//Remap to [0, subdiv[
coeff = 0.5f * PxReal(subdiv-1);
u += 1.0f; u *= coeff;
v += 1.0f; v *= coeff;
//Round to nearest
PxU32 ui = PxU32(u);
PxU32 vi = PxU32(v);
PxReal du = u - PxReal(ui);
PxReal dv = v - PxReal(vi);
if(du>0.5f) ui++;
if(dv>0.5f) vi++;
//Compute offset
return CI*(subdiv*subdiv) + ui*subdiv + vi;
}
// Hull projection callback for "big" hulls
static void HullProjectionCB_BigConvex(const PolygonalData& data, const PxVec3& dir, const PxMat34& world, const Cm::FastVertex2ShapeScaling& scaling, PxReal& minimum, PxReal& maximum)
{
const PxVec3* PX_RESTRICT verts = data.mVerts;
const PxVec3 localSpaceDirection = world.rotateTranspose(dir);
//vertex1TOShape1Skew is a symmetric matrix.
//it has the property that (vertex1TOShape1Skew * v)|localSpaceDirection == (vertex1TOShape1Skew * localSpaceDirection)|v
const PxVec3 vertexSpaceDirection = scaling * localSpaceDirection; //NB: triangles are always shape 1! eek!
// This version is better for objects with a lot of vertices
const Gu::BigConvexRawData* bigData = data.mBigData;
PxU32 minID = 0, maxID = 0;
{
const PxU32 offset = computeNearestOffset(bigData->mSubdiv, -vertexSpaceDirection);
minID = bigData->mSamples[offset];
maxID = bigData->getSamples2()[offset];
}
// Do hillclimbing!
localSearch(minID, -vertexSpaceDirection, verts, bigData);
localSearch(maxID, vertexSpaceDirection, verts, bigData);
const PxReal offset = world.p.dot(dir);
minimum = offset + verts[minID].dot(vertexSpaceDirection);
maximum = offset + verts[maxID].dot(vertexSpaceDirection);
PX_ASSERT(maximum >= minimum);
}
void Gu::getPolygonalData_Convex(PolygonalData* PX_RESTRICT dst, const Gu::ConvexHullData* PX_RESTRICT src, const Cm::FastVertex2ShapeScaling& scaling)
{
dst->mCenter = scaling * src->mCenterOfMass;
dst->mNbVerts = src->mNbHullVertices;
dst->mNbPolygons = src->mNbPolygons;
dst->mNbEdges = src->mNbEdges;
dst->mPolygons = src->mPolygons;
dst->mVerts = src->getHullVertices();
dst->mPolygonVertexRefs = src->getVertexData8();
dst->mFacesByEdges = src->getFacesByEdges8();
// TEST_INTERNAL_OBJECTS
dst->mInternal = src->mInternal;
//~TEST_INTERNAL_OBJECTS
dst->mBigData = src->mBigConvexRawData;
// This threshold test doesnt cost much and many customers cook on PC and use this on 360.
// 360 has a much higher threshold than PC(and it makes a big difference)
// PT: the cool thing is that this test is now done once by contact generation call, not once by hull projection
if(!src->mBigConvexRawData)
dst->mProjectHull = HullProjectionCB_SmallConvex;
else
dst->mProjectHull = HullProjectionCB_BigConvex;
dst->mSelectClosestEdgeCB = SelectClosestEdgeCB_Convex;
}
// Box emulating convex mesh
// Face0: 0-1-2-3
// Face1: 1-5-6-2
// Face2: 5-4-7-6
// Face3: 4-0-3-7
// Face4; 3-2-6-7
// Face5: 4-5-1-0
// 7+------+6 0 = ---
// /| /| 1 = +--
// / | / | 2 = ++-
// / 4+---/--+5 3 = -+-
// 3+------+2 / y z 4 = --+
// | / | / | / 5 = +-+
// |/ |/ |/ 6 = +++
// 0+------+1 *---x 7 = -++
static const PxU8 gPxcBoxPolygonData[] = {
0, 1, 2, 3,
1, 5, 6, 2,
5, 4, 7, 6,
4, 0, 3, 7,
3, 2, 6, 7,
4, 5, 1, 0,
};
#define INVSQRT2 0.707106781188f //!< 1 / sqrt(2)
static PxVec3 gPxcBoxEdgeNormals[] =
{
PxVec3(0, -INVSQRT2, -INVSQRT2), // 0-1
PxVec3(INVSQRT2, 0, -INVSQRT2), // 1-2
PxVec3(0, INVSQRT2, -INVSQRT2), // 2-3
PxVec3(-INVSQRT2, 0, -INVSQRT2), // 3-0
PxVec3(0, INVSQRT2, INVSQRT2), // 7-6
PxVec3(INVSQRT2, 0, INVSQRT2), // 6-5
PxVec3(0, -INVSQRT2, INVSQRT2), // 5-4
PxVec3(-INVSQRT2, 0, INVSQRT2), // 4-7
PxVec3(INVSQRT2, -INVSQRT2, 0), // 1-5
PxVec3(INVSQRT2, INVSQRT2, 0), // 6-2
PxVec3(-INVSQRT2, INVSQRT2, 0), // 3-7
PxVec3(-INVSQRT2, -INVSQRT2, 0) // 4-0
};
#undef INVSQRT2
// ### needs serious checkings
// Flags(16), Count(16), Offset(32);
static Gu::EdgeDescData gPxcBoxEdgeDesc[] = {
{Gu::PX_EDGE_ACTIVE, 2, 0},
{Gu::PX_EDGE_ACTIVE, 2, 2},
{Gu::PX_EDGE_ACTIVE, 2, 4},
{Gu::PX_EDGE_ACTIVE, 2, 6},
{Gu::PX_EDGE_ACTIVE, 2, 8},
{Gu::PX_EDGE_ACTIVE, 2, 10},
{Gu::PX_EDGE_ACTIVE, 2, 12},
{Gu::PX_EDGE_ACTIVE, 2, 14},
{Gu::PX_EDGE_ACTIVE, 2, 16},
{Gu::PX_EDGE_ACTIVE, 2, 18},
{Gu::PX_EDGE_ACTIVE, 2, 20},
{Gu::PX_EDGE_ACTIVE, 2, 22},
};
// ### needs serious checkings
static PxU8 gPxcBoxFaceByEdge[] = {
0,5, // Edge 0-1
0,1, // Edge 1-2
0,4, // Edge 2-3
0,3, // Edge 3-0
2,4, // Edge 7-6
1,2, // Edge 6-5
2,5, // Edge 5-4
2,3, // Edge 4-7
1,5, // Edge 1-5
1,4, // Edge 6-2
3,4, // Edge 3-7
3,5, // Edge 4-0
};
static PxU32 SelectClosestEdgeCB_Box(const PolygonalData& data, const Cm::FastVertex2ShapeScaling& scaling, const PxVec3& localDirection)
{
PX_UNUSED(scaling);
PxReal maxDp;
// ##might not be needed
PxU32 closest = ::selectClosestPolygon(maxDp, 6, data.mPolygons, localDirection);
PxU32 numEdges = 12;
const PxVec3* PX_RESTRICT edgeNormals = gPxcBoxEdgeNormals;
//Loop through edges
PxU32 closestEdge = 0xffffffff;
for(PxU32 i=0; i < numEdges; i++)
{
//Test normal of current edge
const float dp = edgeNormals[i].dot(localDirection);
if(dp>maxDp)
{
maxDp = dp;
closestEdge = i;
}
}
if(closestEdge!=0xffffffff)
{
const Gu::EdgeDescData* PX_RESTRICT ED = gPxcBoxEdgeDesc;
const PxU8* PX_RESTRICT FBE = gPxcBoxFaceByEdge;
PX_ASSERT(ED[closestEdge].Count==2);
const PxU32 f0 = FBE[ED[closestEdge].Offset];
const PxU32 f1 = FBE[ED[closestEdge].Offset+1];
const PxReal dp0 = data.mPolygons[f0].mPlane.n.dot(localDirection);
const PxReal dp1 = data.mPolygons[f1].mPlane.n.dot(localDirection);
if(dp0>dp1)
closest = f0;
else
closest = f1;
}
return closest;
}
static PX_FORCE_INLINE void projectBox(PxVec3& p, const PxVec3& localDir, const PxVec3& extents)
{
// PT: the original code didn't have branches or FPU comparisons. Why rewrite it ?
// p.x = (localDir.x >= 0) ? extents.x : -extents.x;
// p.y = (localDir.y >= 0) ? extents.y : -extents.y;
// p.z = (localDir.z >= 0) ? extents.z : -extents.z;
p.x = physx::intrinsics::fsel(localDir.x, extents.x, -extents.x);
p.y = physx::intrinsics::fsel(localDir.y, extents.y, -extents.y);
p.z = physx::intrinsics::fsel(localDir.z, extents.z, -extents.z);
}
static void HullProjectionCB_Box(const PolygonalData& data, const PxVec3& dir, const PxMat34& world, const Cm::FastVertex2ShapeScaling& scaling, PxReal& minimum, PxReal& maximum)
{
PX_UNUSED(scaling);
const PxVec3 localDir = world.rotateTranspose(dir);
PxVec3 p;
projectBox(p, localDir, *data.mHalfSide);
const PxReal offset = world.p.dot(dir);
const PxReal tmp = p.dot(localDir);
maximum = offset + tmp;
minimum = offset - tmp;
}
PolygonalBox::PolygonalBox(const PxVec3& halfSide) : mHalfSide(halfSide)
{
//Precompute the convex data
// 7+------+6 0 = ---
// /| /| 1 = +--
// / | / | 2 = ++-
// / 4+---/--+5 3 = -+-
// 3+------+2 / y z 4 = --+
// | / | / | / 5 = +-+
// |/ |/ |/ 6 = +++
// 0+------+1 *---x 7 = -++
PxVec3 minimum = -mHalfSide;
PxVec3 maximum = mHalfSide;
// Generate 8 corners of the bbox
mVertices[0] = PxVec3(minimum.x, minimum.y, minimum.z);
mVertices[1] = PxVec3(maximum.x, minimum.y, minimum.z);
mVertices[2] = PxVec3(maximum.x, maximum.y, minimum.z);
mVertices[3] = PxVec3(minimum.x, maximum.y, minimum.z);
mVertices[4] = PxVec3(minimum.x, minimum.y, maximum.z);
mVertices[5] = PxVec3(maximum.x, minimum.y, maximum.z);
mVertices[6] = PxVec3(maximum.x, maximum.y, maximum.z);
mVertices[7] = PxVec3(minimum.x, maximum.y, maximum.z);
//Setup the polygons
for(PxU8 i=0; i < 6; i++)
{
mPolygons[i].mNbVerts = 4;
mPolygons[i].mVRef8 = PxU16(i*4);
}
// ### planes needs *very* careful checks
// X axis
mPolygons[1].mPlane.n = PxVec3(1.0f, 0.0f, 0.0f);
mPolygons[1].mPlane.d = -mHalfSide.x;
mPolygons[3].mPlane.n = PxVec3(-1.0f, 0.0f, 0.0f);
mPolygons[3].mPlane.d = -mHalfSide.x;
mPolygons[1].mMinIndex = 0;
mPolygons[3].mMinIndex = 1;
// mPolygons[1].mMinObsolete = -mHalfSide.x;
// mPolygons[3].mMinObsolete = -mHalfSide.x;
PX_ASSERT(mPolygons[1].getMin(mVertices) == -mHalfSide.x);
PX_ASSERT(mPolygons[3].getMin(mVertices) == -mHalfSide.x);
// Y axis
mPolygons[4].mPlane.n = PxVec3(0.f, 1.0f, 0.0f);
mPolygons[4].mPlane.d = -mHalfSide.y;
mPolygons[5].mPlane.n = PxVec3(0.0f, -1.0f, 0.0f);
mPolygons[5].mPlane.d = -mHalfSide.y;
mPolygons[4].mMinIndex = 0;
mPolygons[5].mMinIndex = 2;
// mPolygons[4].mMinObsolete = -mHalfSide.y;
// mPolygons[5].mMinObsolete = -mHalfSide.y;
PX_ASSERT(mPolygons[4].getMin(mVertices) == -mHalfSide.y);
PX_ASSERT(mPolygons[5].getMin(mVertices) == -mHalfSide.y);
// Z axis
mPolygons[2].mPlane.n = PxVec3(0.f, 0.0f, 1.0f);
mPolygons[2].mPlane.d = -mHalfSide.z;
mPolygons[0].mPlane.n = PxVec3(0.0f, 0.0f, -1.0f);
mPolygons[0].mPlane.d = -mHalfSide.z;
mPolygons[2].mMinIndex = 0;
mPolygons[0].mMinIndex = 4;
// mPolygons[2].mMinObsolete = -mHalfSide.z;
// mPolygons[0].mMinObsolete = -mHalfSide.z;
PX_ASSERT(mPolygons[2].getMin(mVertices) == -mHalfSide.z);
PX_ASSERT(mPolygons[0].getMin(mVertices) == -mHalfSide.z);
}
void PolygonalBox::getPolygonalData(PolygonalData* PX_RESTRICT dst) const
{
dst->mCenter = PxVec3(0.0f, 0.0f, 0.0f);
dst->mNbVerts = 8;
dst->mNbPolygons = 6;
dst->mPolygons = mPolygons;
dst->mNbEdges = 0;
dst->mVerts = mVertices;
dst->mPolygonVertexRefs = gPxcBoxPolygonData;
dst->mFacesByEdges = NULL;
dst->mInternal.mInternalRadius = 0.0f;
dst->mInternal.mInternalExtents = PxVec3(0.0f);
// dst->mBigData = NULL;
dst->mHalfSide = &mHalfSide;
dst->mProjectHull = HullProjectionCB_Box;
dst->mSelectClosestEdgeCB = SelectClosestEdgeCB_Box;
}

View File

@@ -0,0 +1,100 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
#ifndef GU_SHAPECONVEX_H
#define GU_SHAPECONVEX_H
#include "GuConvexMeshData.h"
#include "CmScaling.h"
namespace physx
{
namespace Gu
{
struct PolygonalData;
typedef void (*HullPrefetchCB) (PxU32 numVerts, const PxVec3* PX_RESTRICT verts);
typedef void (*HullProjectionCB) (const PolygonalData& data, const PxVec3& dir, const PxMat34& world2hull, const Cm::FastVertex2ShapeScaling& scaling, PxReal& minimum, PxReal& maximum);
typedef PxU32 (*SelectClosestEdgeCB) (const PolygonalData& data, const Cm::FastVertex2ShapeScaling& scaling, const PxVec3& localDirection);
struct PolygonalData
{
// Data
Gu::InternalObjectsData mInternal;
PxMeshScale mScale;
PxVec3 mCenter;
PxU32 mNbVerts;
PxU32 mNbPolygons;
PxU32 mNbEdges;
const Gu::HullPolygonData* mPolygons;
const PxVec3* mVerts;
const PxU8* mPolygonVertexRefs;
const PxU8* mFacesByEdges;
const PxU16* mVerticesByEdges;
union
{
const Gu::BigConvexRawData* mBigData; // Only for big convexes
const PxVec3* mHalfSide; // Only for boxes
};
// Code
HullProjectionCB mProjectHull;
SelectClosestEdgeCB mSelectClosestEdgeCB;
PX_FORCE_INLINE const PxU8* getPolygonVertexRefs(const Gu::HullPolygonData& poly) const
{
return mPolygonVertexRefs + poly.mVRef8;
}
};
#if PX_VC
#pragma warning(push)
#pragma warning( disable : 4251 ) // class needs to have dll-interface to be used by clients of class
#endif
class PolygonalBox
{
public:
PolygonalBox(const PxVec3& halfSide);
void getPolygonalData(PolygonalData* PX_RESTRICT dst) const;
const PxVec3& mHalfSide;
PxVec3 mVertices[8];
Gu::HullPolygonData mPolygons[6];
private:
PolygonalBox& operator=(const PolygonalBox&);
};
#if PX_VC
#pragma warning(pop)
#endif
void getPolygonalData_Convex(PolygonalData* PX_RESTRICT dst, const Gu::ConvexHullData* PX_RESTRICT src, const Cm::FastVertex2ShapeScaling& scaling);
}
}
#endif