feat(physics): wire physx sdk into build
This commit is contained in:
411
engine/third_party/physx/source/geomutils/src/mesh/GuBV32.cpp
vendored
Normal file
411
engine/third_party/physx/source/geomutils/src/mesh/GuBV32.cpp
vendored
Normal file
@@ -0,0 +1,411 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxMemory.h"
|
||||
#include "GuBV32.h"
|
||||
#include "CmSerialize.h"
|
||||
#include "CmUtils.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
#include "foundation/PxVecMath.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
using namespace Cm;
|
||||
|
||||
BV32Tree::BV32Tree(SourceMesh* meshInterface, const PxBounds3& localBounds)
|
||||
{
|
||||
reset();
|
||||
init(meshInterface, localBounds);
|
||||
}
|
||||
|
||||
BV32Tree::BV32Tree()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void BV32Tree::release()
|
||||
{
|
||||
if (!mUserAllocated)
|
||||
{
|
||||
PX_DELETE_ARRAY(mNodes);
|
||||
PX_FREE(mPackedNodes);
|
||||
PX_FREE(mTreeDepthInfo);
|
||||
PX_FREE(mRemapPackedNodeIndexWithDepth);
|
||||
}
|
||||
mNodes = NULL;
|
||||
mNbNodes = 0;
|
||||
mMaxTreeDepth = 0;
|
||||
}
|
||||
|
||||
BV32Tree::~BV32Tree()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void BV32Tree::reset()
|
||||
{
|
||||
mMeshInterface = NULL;
|
||||
mNbNodes = 0;
|
||||
mNodes = NULL;
|
||||
mNbPackedNodes = 0;
|
||||
mPackedNodes = NULL;
|
||||
mMaxTreeDepth = 0;
|
||||
mTreeDepthInfo = NULL;
|
||||
mRemapPackedNodeIndexWithDepth = NULL;
|
||||
mInitData = 0;
|
||||
mUserAllocated = false;
|
||||
}
|
||||
|
||||
void BV32Tree::operator=(BV32Tree& v)
|
||||
{
|
||||
mMeshInterface = v.mMeshInterface;
|
||||
mLocalBounds = v.mLocalBounds;
|
||||
mNbNodes = v.mNbNodes;
|
||||
mNodes = v.mNodes;
|
||||
mInitData = v.mInitData;
|
||||
mUserAllocated = v.mUserAllocated;
|
||||
v.reset();
|
||||
}
|
||||
|
||||
bool BV32Tree::init(SourceMeshBase* meshInterface, const PxBounds3& localBounds)
|
||||
{
|
||||
mMeshInterface = meshInterface;
|
||||
mLocalBounds.init(localBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
// PX_SERIALIZATION
|
||||
BV32Tree::BV32Tree(const PxEMPTY)
|
||||
{
|
||||
mUserAllocated = true;
|
||||
}
|
||||
|
||||
void BV32Tree::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
stream.alignData(16);
|
||||
stream.writeData(mPackedNodes, mNbPackedNodes*sizeof(BV32DataPacked));
|
||||
}
|
||||
|
||||
void BV32Tree::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
context.alignExtraData(16);
|
||||
mPackedNodes = context.readExtraData<BV32DataPacked>(mNbPackedNodes);
|
||||
}
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
bool BV32Tree::load(PxInputStream& stream, bool mismatch_)
|
||||
{
|
||||
PX_ASSERT(!mUserAllocated);
|
||||
|
||||
release();
|
||||
|
||||
PxI8 a, b, c, d;
|
||||
readChunk(a, b, c, d, stream);
|
||||
if(a != 'B' || b != 'V' || c != '3' || d != '2')
|
||||
return false;
|
||||
|
||||
bool mismatch;
|
||||
PxU32 fileVersion;
|
||||
if(!readBigEndianVersionNumber(stream, mismatch_, fileVersion, mismatch))
|
||||
return false;
|
||||
|
||||
mLocalBounds.mCenter.x = readFloat(mismatch, stream);
|
||||
mLocalBounds.mCenter.y = readFloat(mismatch, stream);
|
||||
mLocalBounds.mCenter.z = readFloat(mismatch, stream);
|
||||
mLocalBounds.mExtentsMagnitude = readFloat(mismatch, stream);
|
||||
|
||||
mInitData = readDword(mismatch, stream);
|
||||
|
||||
/*const PxU32 nbNodes = readDword(mismatch, stream);
|
||||
mNbNodes = nbNodes;
|
||||
|
||||
if (nbNodes)
|
||||
{
|
||||
BV32Data* nodes = PX_NEW(BV32Data)[nbNodes];
|
||||
|
||||
mNodes = nodes;
|
||||
PxMarkSerializedMemory(nodes, sizeof(BV32Data)*nbNodes);
|
||||
|
||||
for (PxU32 i = 0; i<nbNodes; i++)
|
||||
{
|
||||
BV32Data& node = nodes[i];
|
||||
|
||||
readFloatBuffer(&node.mCenter.x, 3, mismatch, stream);
|
||||
node.mData = readDword(mismatch, stream);
|
||||
readFloatBuffer(&node.mExtents.x, 3, mismatch, stream);
|
||||
}
|
||||
}*/
|
||||
|
||||
//read SOA format node data
|
||||
const PxU32 nbPackedNodes = readDword(mismatch, stream);
|
||||
mNbPackedNodes = nbPackedNodes;
|
||||
|
||||
if (nbPackedNodes)
|
||||
{
|
||||
mPackedNodes = reinterpret_cast<BV32DataPacked*>(PX_ALLOC(sizeof(BV32DataPacked)*nbPackedNodes, "BV32DataPacked"));
|
||||
|
||||
PxMarkSerializedMemory(mPackedNodes, sizeof(BV32DataPacked)*nbPackedNodes);
|
||||
|
||||
for (PxU32 i = 0; i < nbPackedNodes; ++i)
|
||||
{
|
||||
BV32DataPacked& node = mPackedNodes[i];
|
||||
node.mNbNodes = readDword(mismatch, stream);
|
||||
PX_ASSERT(node.mNbNodes > 0);
|
||||
node.mDepth = readDword(mismatch, stream);
|
||||
ReadDwordBuffer(node.mData, node.mNbNodes, mismatch, stream);
|
||||
const PxU32 nbElements = 4 * node.mNbNodes;
|
||||
readFloatBuffer(&node.mMin[0].x, nbElements, mismatch, stream);
|
||||
readFloatBuffer(&node.mMax[0].x, nbElements, mismatch, stream);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const PxU32 maxTreeDepth = readDword(mismatch, stream);
|
||||
mMaxTreeDepth = maxTreeDepth;
|
||||
|
||||
if (maxTreeDepth > 0)
|
||||
{
|
||||
mTreeDepthInfo = reinterpret_cast<BV32DataDepthInfo*>(PX_ALLOC(sizeof(BV32DataDepthInfo)*maxTreeDepth, "BV32DataDepthInfo"));
|
||||
|
||||
for (PxU32 i = 0; i < maxTreeDepth; ++i)
|
||||
{
|
||||
BV32DataDepthInfo& info = mTreeDepthInfo[i];
|
||||
|
||||
info.offset = readDword(mismatch, stream);
|
||||
info.count = readDword(mismatch, stream);
|
||||
}
|
||||
|
||||
mRemapPackedNodeIndexWithDepth = reinterpret_cast<PxU32*>(PX_ALLOC(sizeof(PxU32)*nbPackedNodes, "PxU32"));
|
||||
|
||||
ReadDwordBuffer(mRemapPackedNodeIndexWithDepth, nbPackedNodes, mismatch, stream);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BV32Tree::createSOAformatNode(BV32DataPacked& packedData,
|
||||
const BV32Data& node, const PxU32 childOffset, PxU32& currentIndex, PxU32& nbPackedNodes)
|
||||
{
|
||||
//found the next 32 nodes and fill it in SOA format
|
||||
|
||||
const PxU32 nbChildren = node.getNbChildren();
|
||||
const PxU32 offset = node.getChildOffset();
|
||||
|
||||
packedData.mDepth = node.mDepth;
|
||||
|
||||
for (PxU32 i = 0; i < nbChildren; ++i)
|
||||
{
|
||||
BV32Data& child = mNodes[offset + i];
|
||||
|
||||
packedData.mMin[i] = PxVec4(child.mMin, 0.f);
|
||||
packedData.mMax[i] = PxVec4(child.mMax, 0.f);
|
||||
packedData.mData[i] = PxU32(child.mData);
|
||||
}
|
||||
|
||||
packedData.mNbNodes = nbChildren;
|
||||
|
||||
PxU32 NbToGo = 0;
|
||||
PxU32 NextIDs[32];
|
||||
PxMemSet(NextIDs, PX_INVALID_U32, sizeof(PxU32) * 32);
|
||||
const BV32Data* ChildNodes[32];
|
||||
PxMemSet(ChildNodes, 0, sizeof(BV32Data*) * 32);
|
||||
|
||||
for (PxU32 i = 0; i< nbChildren; i++)
|
||||
{
|
||||
BV32Data& child = mNodes[offset + i];
|
||||
|
||||
if (!child.isLeaf())
|
||||
{
|
||||
const PxU32 NextID = currentIndex;
|
||||
|
||||
const PxU32 ChildSize = child.getNbChildren() - child.mNbLeafNodes;
|
||||
currentIndex += ChildSize;
|
||||
|
||||
//packedData.mData[i] = (packedData.mData[i] & ((1 << GU_BV4_CHILD_OFFSET_SHIFT_COUNT) - 1)) | (NextID << GU_BV4_CHILD_OFFSET_SHIFT_COUNT);
|
||||
packedData.mData[i] = (packedData.mData[i] & ((1 << GU_BV4_CHILD_OFFSET_SHIFT_COUNT) - 1)) | ((childOffset + NbToGo) << GU_BV4_CHILD_OFFSET_SHIFT_COUNT);
|
||||
|
||||
NextIDs[NbToGo] = NextID;
|
||||
ChildNodes[NbToGo] = &child;
|
||||
NbToGo++;
|
||||
}
|
||||
}
|
||||
|
||||
nbPackedNodes += NbToGo;
|
||||
for (PxU32 i = 0; i < NbToGo; ++i)
|
||||
{
|
||||
const BV32Data& child = *ChildNodes[i];
|
||||
|
||||
BV32DataPacked& childData = mPackedNodes[childOffset+i];
|
||||
|
||||
createSOAformatNode(childData, child, NextIDs[i], currentIndex, nbPackedNodes);
|
||||
}
|
||||
}
|
||||
|
||||
bool BV32Tree::refit(float epsilon)
|
||||
{
|
||||
using namespace aos;
|
||||
|
||||
if (!mPackedNodes)
|
||||
{
|
||||
PxBounds3 bounds;
|
||||
bounds.setEmpty();
|
||||
if (mMeshInterface)
|
||||
{
|
||||
PxU32 nbVerts = mMeshInterface->getNbVertices();
|
||||
const PxVec3* verts = mMeshInterface->getVerts();
|
||||
while (nbVerts--)
|
||||
bounds.include(*verts++);
|
||||
mLocalBounds.init(bounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class PxBounds3Padded : public PxBounds3
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE PxBounds3Padded() {}
|
||||
PX_FORCE_INLINE ~PxBounds3Padded() {}
|
||||
PxU32 padding;
|
||||
};
|
||||
|
||||
PxU32 nb = mNbPackedNodes;
|
||||
|
||||
while (nb--)
|
||||
{
|
||||
BV32DataPacked* PX_RESTRICT current = mPackedNodes + nb;
|
||||
const PxU32 nbChildren = current->mNbNodes;
|
||||
|
||||
for (PxU32 j = 0; j< nbChildren; j++)
|
||||
{
|
||||
if (current->isLeaf(j))
|
||||
{
|
||||
PxU32 nbTets = current->getNbReferencedPrimitives(j);
|
||||
PxU32 primIndex = current->getPrimitiveStartIndex(j);
|
||||
|
||||
Vec4V minV = V4Load(FLT_MAX);
|
||||
Vec4V maxV = V4Load(-FLT_MAX);
|
||||
|
||||
//TetrahedronPointers
|
||||
do
|
||||
{
|
||||
PX_ASSERT(primIndex< mMeshInterface->getNbPrimitives());
|
||||
|
||||
//meshInterface->getTriangle(VP, primIndex);
|
||||
Vec4V tMin, tMax;
|
||||
mMeshInterface->getPrimitiveBox(primIndex, tMin, tMax);
|
||||
minV = V4Min(minV, tMin);
|
||||
maxV = V4Max(maxV, tMax);
|
||||
|
||||
primIndex++;
|
||||
} while (--nbTets);
|
||||
|
||||
const Vec4V epsilonV = V4Load(epsilon);
|
||||
minV = V4Sub(minV, epsilonV);
|
||||
maxV = V4Add(maxV, epsilonV);
|
||||
|
||||
PxBounds3Padded refitBox;
|
||||
V4StoreU_Safe(minV, &refitBox.minimum.x);
|
||||
V4StoreU_Safe(maxV, &refitBox.maximum.x);
|
||||
|
||||
current->mMin[j].x = refitBox.minimum.x;
|
||||
current->mMin[j].y = refitBox.minimum.y;
|
||||
current->mMin[j].z = refitBox.minimum.z;
|
||||
current->mMax[j].x = refitBox.maximum.x;
|
||||
current->mMax[j].y = refitBox.maximum.y;
|
||||
current->mMax[j].z = refitBox.maximum.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
PxU32 childOffset = current->getChildOffset(j);
|
||||
|
||||
PX_ASSERT(childOffset < mNbPackedNodes);
|
||||
|
||||
BV32DataPacked* next = mPackedNodes + childOffset;
|
||||
|
||||
const PxU32 nextNbChilds = next->mNbNodes;
|
||||
|
||||
Vec4V minV = V4Load(FLT_MAX);
|
||||
Vec4V maxV = V4Load(-FLT_MAX);
|
||||
|
||||
for (PxU32 a = 0; a < nextNbChilds; ++a)
|
||||
{
|
||||
const Vec4V tMin = V4LoadU(&next->mMin[a].x);
|
||||
const Vec4V tMax = V4LoadU(&next->mMax[a].x);
|
||||
|
||||
minV = V4Min(minV, tMin);
|
||||
maxV = V4Max(maxV, tMax);
|
||||
}
|
||||
|
||||
PxBounds3Padded refitBox;
|
||||
V4StoreU_Safe(minV, &refitBox.minimum.x);
|
||||
V4StoreU_Safe(maxV, &refitBox.maximum.x);
|
||||
|
||||
current->mMin[j].x = refitBox.minimum.x;
|
||||
current->mMin[j].y = refitBox.minimum.y;
|
||||
current->mMin[j].z = refitBox.minimum.z;
|
||||
|
||||
current->mMax[j].x = refitBox.maximum.x;
|
||||
current->mMax[j].y = refitBox.maximum.y;
|
||||
current->mMax[j].z = refitBox.maximum.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BV32DataPacked* root = mPackedNodes;
|
||||
{
|
||||
PxBounds3 globalBounds;
|
||||
globalBounds.setEmpty();
|
||||
|
||||
const PxU32 nbChildren = root->mNbNodes;
|
||||
|
||||
Vec4V minV = V4Load(FLT_MAX);
|
||||
Vec4V maxV = V4Load(-FLT_MAX);
|
||||
|
||||
for (PxU32 a = 0; a < nbChildren; ++a)
|
||||
{
|
||||
const Vec4V tMin = V4LoadU(&root->mMin[a].x);
|
||||
const Vec4V tMax = V4LoadU(&root->mMax[a].x);
|
||||
|
||||
minV = V4Min(minV, tMin);
|
||||
maxV = V4Max(maxV, tMax);
|
||||
}
|
||||
|
||||
PxBounds3Padded refitBox;
|
||||
V4StoreU_Safe(minV, &refitBox.minimum.x);
|
||||
V4StoreU_Safe(maxV, &refitBox.maximum.x);
|
||||
globalBounds.minimum.x = refitBox.minimum.x;
|
||||
globalBounds.minimum.y = refitBox.minimum.y;
|
||||
globalBounds.minimum.z = refitBox.minimum.z;
|
||||
|
||||
globalBounds.maximum.x = refitBox.maximum.x;
|
||||
globalBounds.maximum.y = refitBox.maximum.y;
|
||||
globalBounds.maximum.z = refitBox.maximum.z;
|
||||
|
||||
mLocalBounds.init(globalBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
164
engine/third_party/physx/source/geomutils/src/mesh/GuBV32.h
vendored
Normal file
164
engine/third_party/physx/source/geomutils/src/mesh/GuBV32.h
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
// 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_BV32_H
|
||||
#define GU_BV32_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "foundation/PxVec4.h"
|
||||
#include "common/PxSerialFramework.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "GuBV4.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
struct BV32Data : public physx::PxUserAllocated
|
||||
{
|
||||
PxVec3 mMin;
|
||||
PxVec3 mMax;
|
||||
PxU32 mNbLeafNodes;
|
||||
PxU32 mDepth;
|
||||
size_t mData;
|
||||
|
||||
PX_FORCE_INLINE BV32Data() : mNbLeafNodes(0), mDepth(0), mData(PX_INVALID_U32)
|
||||
{
|
||||
setEmpty();
|
||||
}
|
||||
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 isLeaf() const { return mData & 1; }
|
||||
|
||||
//if the node is leaf,
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getNbReferencedPrimitives() const { PX_ASSERT(isLeaf()); return PxU32((mData >>1)&63); }
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getPrimitiveStartIndex() const { PX_ASSERT(isLeaf()); return PxU32(mData >> 7); }
|
||||
|
||||
//PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getPrimitive() const { return mData >> 1; }
|
||||
//if the node isn't leaf, we will get the childOffset
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getChildOffset() const { PX_ASSERT(!isLeaf()); return PxU32(mData >> GU_BV4_CHILD_OFFSET_SHIFT_COUNT); }
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getNbChildren() const { PX_ASSERT(!isLeaf()); return ((mData) & ((1 << GU_BV4_CHILD_OFFSET_SHIFT_COUNT) - 1))>>1; }
|
||||
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE void getMinMax(PxVec3& min, PxVec3& max) const
|
||||
{
|
||||
//min = mCenter - mExtents;
|
||||
//max = mCenter + mExtents;
|
||||
min = mMin;
|
||||
max = mMax;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void setEmpty()
|
||||
{
|
||||
//mCenter = PxVec3(0.0f, 0.0f, 0.0f);
|
||||
//mExtents = PxVec3(-1.0f, -1.0f, -1.0f);
|
||||
|
||||
mMin = PxVec3(PX_MAX_F32);
|
||||
mMax = PxVec3(-PX_MAX_F32);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
PX_ALIGN_PREFIX(16)
|
||||
struct BV32DataPacked
|
||||
{
|
||||
/*PxVec4 mCenter[32];
|
||||
PxVec4 mExtents[32];*/
|
||||
PxVec4 mMin[32];
|
||||
PxVec4 mMax[32];
|
||||
PxU32 mData[32];
|
||||
PxU32 mNbNodes;
|
||||
PxU32 mDepth;
|
||||
PxU32 padding[2];
|
||||
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE BV32DataPacked() : mNbNodes(0), mDepth(0)
|
||||
{
|
||||
}
|
||||
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 isLeaf(const PxU32 index) const { return mData[index] & 1; }
|
||||
//if the node is leaf
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getNbReferencedPrimitives(const PxU32 index) const { PX_ASSERT(isLeaf(index)); return (mData[index] >> 1) & 63; }
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getPrimitiveStartIndex(const PxU32 index) const { PX_ASSERT(isLeaf(index)); return (mData[index] >> 7); }
|
||||
//if the node isn't leaf, we will get the childOffset
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getChildOffset(const PxU32 index) const { PX_ASSERT(!isLeaf(index)); return mData[index] >> GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
|
||||
PX_CUDA_CALLABLE PX_FORCE_INLINE PxU32 getNbChildren(const PxU32 index) const { PX_ASSERT(!isLeaf(index)); return ((mData[index])& ((1 << GU_BV4_CHILD_OFFSET_SHIFT_COUNT) - 1)) >> 1; }
|
||||
}
|
||||
PX_ALIGN_SUFFIX(16);
|
||||
|
||||
//This struct store the start and end index of the packed node at the same depth level in the tree
|
||||
struct BV32DataDepthInfo
|
||||
{
|
||||
public:
|
||||
PxU32 offset;
|
||||
PxU32 count;
|
||||
};
|
||||
|
||||
class BV32Tree : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
// PX_SERIALIZATION
|
||||
BV32Tree(const PxEMPTY);
|
||||
void exportExtraData(PxSerializationContext&);
|
||||
void importExtraData(PxDeserializationContext& context);
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
BV32Tree();
|
||||
BV32Tree(SourceMesh* meshInterface, const PxBounds3& localBounds);
|
||||
~BV32Tree();
|
||||
|
||||
bool refit(const float epsilon);
|
||||
|
||||
bool load(PxInputStream& stream, bool mismatch);
|
||||
|
||||
void createSOAformatNode(BV32DataPacked& packedData, const BV32Data& node, const PxU32 childOffset, PxU32& currentIndex, PxU32& nbPackedNodes);
|
||||
|
||||
void reset();
|
||||
void operator = (BV32Tree& v);
|
||||
|
||||
bool init(SourceMeshBase* meshInterface, const PxBounds3& localBounds);
|
||||
void release();
|
||||
|
||||
SourceMeshBase* mMeshInterface;
|
||||
LocalBounds mLocalBounds;
|
||||
|
||||
PxU32 mNbNodes;
|
||||
BV32Data* mNodes;
|
||||
BV32DataPacked* mPackedNodes;
|
||||
PxU32 mNbPackedNodes;
|
||||
PxU32* mRemapPackedNodeIndexWithDepth;
|
||||
BV32DataDepthInfo* mTreeDepthInfo;
|
||||
PxU32 mMaxTreeDepth;
|
||||
PxU32 mInitData;
|
||||
bool mUserAllocated; // PT: please keep these 4 bytes right after mCenterOrMinCoeff/mExtentsOrMaxCoeff for safe V4 loading
|
||||
bool mPadding[2];
|
||||
};
|
||||
|
||||
} // namespace Gu
|
||||
}
|
||||
|
||||
#endif // GU_BV32_H
|
||||
694
engine/third_party/physx/source/geomutils/src/mesh/GuBV32Build.cpp
vendored
Normal file
694
engine/third_party/physx/source/geomutils/src/mesh/GuBV32Build.cpp
vendored
Normal file
@@ -0,0 +1,694 @@
|
||||
// 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/PxVec4.h"
|
||||
#include "foundation/PxBasicTemplates.h"
|
||||
#include "foundation/PxAllocator.h"
|
||||
#include "foundation/PxMemory.h"
|
||||
#include "geometry/PxTriangle.h"
|
||||
|
||||
#include "GuBV32Build.h"
|
||||
#include "GuBV32.h"
|
||||
#include "GuCenterExtents.h"
|
||||
#include "GuBV4Build.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
|
||||
struct BV32Node : public PxUserAllocated
|
||||
{
|
||||
BV32Node() : mNbChildBVNodes(0)
|
||||
{}
|
||||
|
||||
BV32Data mBVData[32];
|
||||
PxU32 mNbChildBVNodes;
|
||||
|
||||
PX_FORCE_INLINE size_t isLeaf(PxU32 i) const { return mBVData[i].mData & 1; }
|
||||
PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return PxU32(mBVData[i].mData >> 1); }
|
||||
PX_FORCE_INLINE const BV32Node* getChild(PxU32 i) const { return reinterpret_cast<BV32Node*>(mBVData[i].mData); }
|
||||
|
||||
|
||||
PxU32 getSize() const
|
||||
{
|
||||
return sizeof(BV32Data)*mNbChildBVNodes;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void fillInNodes(const AABBTreeNode* current_node, const PxU32 startIndex, const PxU32 endIndex, const AABBTreeNode** NODES, PxU32& stat)
|
||||
{
|
||||
|
||||
if (startIndex + 1 == endIndex)
|
||||
{
|
||||
//fill in nodes
|
||||
const AABBTreeNode* P = current_node->getPos();
|
||||
const AABBTreeNode* N = current_node->getNeg();
|
||||
NODES[startIndex] = P;
|
||||
NODES[endIndex] = N;
|
||||
stat += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
const AABBTreeNode* P = current_node->getPos();
|
||||
const AABBTreeNode* N = current_node->getNeg();
|
||||
const PxU32 midIndex = startIndex + ((endIndex - startIndex) / 2);
|
||||
if (!P->isLeaf())
|
||||
fillInNodes(P, startIndex, midIndex, NODES, stat);
|
||||
else
|
||||
{
|
||||
NODES[startIndex] = P;
|
||||
stat++;
|
||||
}
|
||||
|
||||
if (!N->isLeaf())
|
||||
fillInNodes(N, midIndex + 1, endIndex, NODES, stat);
|
||||
else
|
||||
{
|
||||
NODES[midIndex + 1] = N;
|
||||
stat++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void setPrimitive(const BV4_AABBTree& source, BV32Node* node32, PxU32 i, const AABBTreeNode* node, float epsilon)
|
||||
{
|
||||
const PxU32 nbPrims = node->getNbPrimitives();
|
||||
PX_ASSERT(nbPrims<=32);
|
||||
const PxU32* indexBase = source.getIndices();
|
||||
const PxU32* prims = node->getPrimitives();
|
||||
const PxU32 offset = PxU32(prims - indexBase);
|
||||
|
||||
#if BV32_VALIDATE
|
||||
for (PxU32 j = 0; j<nbPrims; j++)
|
||||
{
|
||||
PX_ASSERT(prims[j] == offset + j);
|
||||
}
|
||||
#endif
|
||||
const PxU32 primitiveIndex = (offset << 6) | (nbPrims & 63);
|
||||
|
||||
node32->mBVData[i].mMin = node->getAABB().minimum;
|
||||
node32->mBVData[i].mMax = node->getAABB().maximum;
|
||||
if (epsilon != 0.0f)
|
||||
{
|
||||
node32->mBVData[i].mMin -= PxVec3(epsilon);
|
||||
node32->mBVData[i].mMax += PxVec3(epsilon);
|
||||
}
|
||||
node32->mBVData[i].mData = (primitiveIndex << 1) | 1;
|
||||
}
|
||||
|
||||
static BV32Node* setNode(const BV4_AABBTree& source, BV32Node* node32, PxU32 i, const AABBTreeNode* node, float epsilon)
|
||||
{
|
||||
BV32Node* child = NULL;
|
||||
|
||||
if (node)
|
||||
{
|
||||
if (node->isLeaf())
|
||||
{
|
||||
setPrimitive(source, node32, i, node, epsilon);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
node32->mBVData[i].mMin = node->getAABB().minimum;
|
||||
node32->mBVData[i].mMax = node->getAABB().maximum;
|
||||
if (epsilon != 0.0f)
|
||||
{
|
||||
node32->mBVData[i].mMin -= PxVec3(epsilon);
|
||||
node32->mBVData[i].mMax += PxVec3(epsilon);
|
||||
}
|
||||
|
||||
child = PX_NEW(BV32Node);
|
||||
node32->mBVData[i].mData = size_t(child);
|
||||
}
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
|
||||
static void buildBV32(const BV4_AABBTree& source, BV32Node* tmp, const AABBTreeNode* current_node, float epsilon, PxU32& nbNodes)
|
||||
{
|
||||
PX_ASSERT(!current_node->isLeaf());
|
||||
|
||||
const AABBTreeNode* NODES[32];
|
||||
PxMemSet(NODES, 0, sizeof(AABBTreeNode*) * 32);
|
||||
|
||||
fillInNodes(current_node, 0, 31, NODES, tmp->mNbChildBVNodes);
|
||||
|
||||
PxU32 left = 0;
|
||||
PxU32 right = 31;
|
||||
|
||||
while (left < right)
|
||||
{
|
||||
|
||||
//sweep from the front
|
||||
while (left<right)
|
||||
{
|
||||
//found a hole
|
||||
if (NODES[left] == NULL)
|
||||
break;
|
||||
left++;
|
||||
}
|
||||
|
||||
//sweep from the back
|
||||
while (left < right)
|
||||
{
|
||||
//found a node
|
||||
if (NODES[right])
|
||||
break;
|
||||
right--;
|
||||
}
|
||||
|
||||
if (left != right)
|
||||
{
|
||||
//swap left and right
|
||||
const AABBTreeNode* node = NODES[right];
|
||||
NODES[right] = NODES[left];
|
||||
NODES[left] = node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nbNodes += tmp->mNbChildBVNodes;
|
||||
|
||||
for (PxU32 i = 0; i < tmp->mNbChildBVNodes; ++i)
|
||||
{
|
||||
const AABBTreeNode* tempNode = NODES[i];
|
||||
BV32Node* Child = setNode(source, tmp, i, tempNode, epsilon);
|
||||
if (Child)
|
||||
{
|
||||
buildBV32(source, Child, tempNode, epsilon, nbNodes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
//static void validateTree(const AABBTree& Source, const AABBTreeNode* currentNode)
|
||||
//{
|
||||
// if (currentNode->isLeaf())
|
||||
// {
|
||||
// const PxU32* indexBase = Source.getIndices();
|
||||
// const PxU32* prims = currentNode->getPrimitives();
|
||||
// const PxU32 offset = PxU32(prims - indexBase);
|
||||
// const PxU32 nbPrims = currentNode->getNbPrimitives();
|
||||
// for (PxU32 j = 0; j<nbPrims; j++)
|
||||
// {
|
||||
// PX_ASSERT(prims[j] == offset + j);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// const AABBTreeNode* pos = currentNode->getPos();
|
||||
// validateTree(Source, pos);
|
||||
// const AABBTreeNode* neg = currentNode->getNeg();
|
||||
// validateTree(Source, neg);
|
||||
// }
|
||||
//}
|
||||
|
||||
#if BV32_VALIDATE
|
||||
static void validateNodeBound(const BV32Node* currentNode, SourceMeshBase* mesh, float epsilon)
|
||||
{
|
||||
const PxU32 nbPrimitivesFromMesh = mesh->getNbPrimitives();
|
||||
const PxReal eps = 1e-5f;
|
||||
const PxU32 nbNodes = currentNode->mNbChildBVNodes;
|
||||
for (PxU32 i = 0; i < nbNodes; ++i)
|
||||
{
|
||||
const BV32Node* node = currentNode->getChild(i);
|
||||
if (currentNode->isLeaf(i))
|
||||
{
|
||||
BV32Data data = currentNode->mBVData[i];
|
||||
PxU32 nbPrimitives = data.getNbReferencedPrimitives();
|
||||
PxU32 startIndex = data.getPrimitiveStartIndex();
|
||||
|
||||
PX_ASSERT(startIndex< nbPrimitivesFromMesh);
|
||||
|
||||
PxVec3 min(PX_MAX_F32, PX_MAX_F32, PX_MAX_F32);
|
||||
PxVec3 max(-PX_MAX_F32, -PX_MAX_F32, -PX_MAX_F32);
|
||||
const PxVec3* verts = mesh->getVerts();
|
||||
|
||||
if (mesh->getMeshType() == SourceMeshBase::MeshType::TRI_MESH)
|
||||
{
|
||||
const IndTri32* triIndices = static_cast<SourceMesh*>(mesh)->getTris32();
|
||||
for (PxU32 j = 0; j < nbPrimitives; ++j)
|
||||
{
|
||||
IndTri32 index = triIndices[startIndex + j];
|
||||
|
||||
for (PxU32 k = 0; k < 3; ++k)
|
||||
{
|
||||
const PxVec3& v = verts[index.mRef[k]];
|
||||
|
||||
min.x = (min.x > v.x) ? v.x : min.x;
|
||||
min.y = (min.y > v.y) ? v.y : min.y;
|
||||
min.z = (min.z > v.z) ? v.z : min.z;
|
||||
|
||||
max.x = (max.x < v.x) ? v.x : max.x;
|
||||
max.y = (max.y < v.y) ? v.y : max.y;
|
||||
max.z = (max.z < v.z) ? v.z : max.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const IndTetrahedron32* tetIndices = static_cast<TetrahedronSourceMesh*>(mesh)->getTetrahedrons32();
|
||||
for (PxU32 j = 0; j < nbPrimitives; ++j)
|
||||
{
|
||||
IndTetrahedron32 index = tetIndices[startIndex + j];
|
||||
|
||||
for (PxU32 k = 0; k < 4; ++k)
|
||||
{
|
||||
const PxVec3& v = verts[index.mRef[k]];
|
||||
|
||||
min.x = (min.x > v.x) ? v.x : min.x;
|
||||
min.y = (min.y > v.y) ? v.y : min.y;
|
||||
min.z = (min.z > v.z) ? v.z : min.z;
|
||||
|
||||
max.x = (max.x < v.x) ? v.x : max.x;
|
||||
max.y = (max.y < v.y) ? v.y : max.y;
|
||||
max.z = (max.z < v.z) ? v.z : max.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PxVec3 dMin, dMax;
|
||||
data.getMinMax(dMin, dMax);
|
||||
|
||||
const PxVec3 difMin = min - dMin;
|
||||
const PxVec3 difMax = dMax - max;
|
||||
PX_ASSERT(PxAbs(difMin.x - epsilon) < eps && PxAbs(difMin.y - epsilon) < eps && PxAbs(difMin.z - epsilon) < eps);
|
||||
PX_ASSERT(PxAbs(difMax.x - epsilon) < eps && PxAbs(difMax.y - epsilon) < eps && PxAbs(difMax.z - epsilon) < eps);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
validateNodeBound(node, mesh, epsilon);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool BuildBV32Internal(BV32Tree& bv32Tree, const BV4_AABBTree& Source, SourceMeshBase* mesh, float epsilon)
|
||||
{
|
||||
GU_PROFILE_ZONE("..BuildBV32Internal")
|
||||
|
||||
const PxU32 nbPrimitives = mesh->getNbPrimitives();
|
||||
if (nbPrimitives <= 32)
|
||||
{
|
||||
bv32Tree.mNbPackedNodes = 1;
|
||||
bv32Tree.mPackedNodes = reinterpret_cast<BV32DataPacked*>(PX_ALLOC(sizeof(BV32DataPacked), "BV32DataPacked"));
|
||||
BV32DataPacked& packedData = bv32Tree.mPackedNodes[0];
|
||||
packedData.mNbNodes = 1;
|
||||
packedData.mMin[0] = PxVec4(Source.getBV().minimum, 0.f);
|
||||
packedData.mMax[0] = PxVec4(Source.getBV().maximum, 0.f);
|
||||
packedData.mData[0] = (nbPrimitives << 1) | 1;
|
||||
bv32Tree.mMaxTreeDepth = 1;
|
||||
bv32Tree.mTreeDepthInfo = reinterpret_cast<BV32DataDepthInfo*>(PX_ALLOC(sizeof(BV32DataDepthInfo), "BV32DataDepthInfo"));
|
||||
bv32Tree.mRemapPackedNodeIndexWithDepth = reinterpret_cast<PxU32*>(PX_ALLOC(sizeof(PxU32), "PxU32"));
|
||||
bv32Tree.mTreeDepthInfo[0].offset = 0;
|
||||
bv32Tree.mTreeDepthInfo[0].count = 1;
|
||||
bv32Tree.mRemapPackedNodeIndexWithDepth[0] = 0;
|
||||
|
||||
return bv32Tree.init(mesh, Source.getBV());
|
||||
}
|
||||
|
||||
{
|
||||
GU_PROFILE_ZONE("...._checkMD")
|
||||
struct Local
|
||||
{
|
||||
static void _checkMD(const AABBTreeNode* current_node, PxU32& md, PxU32& cd)
|
||||
{
|
||||
cd++;
|
||||
md = PxMax(md, cd);
|
||||
|
||||
if (current_node->getPos()) { _checkMD(current_node->getPos(), md, cd); cd--; }
|
||||
if (current_node->getNeg()) { _checkMD(current_node->getNeg(), md, cd); cd--; }
|
||||
}
|
||||
|
||||
static void _check(AABBTreeNode* current_node)
|
||||
{
|
||||
if (current_node->isLeaf())
|
||||
return;
|
||||
|
||||
AABBTreeNode* P = const_cast<AABBTreeNode*>(current_node->getPos());
|
||||
AABBTreeNode* N = const_cast<AABBTreeNode*>(current_node->getNeg());
|
||||
{
|
||||
PxU32 MDP = 0; PxU32 CDP = 0; _checkMD(P, MDP, CDP);
|
||||
PxU32 MDN = 0; PxU32 CDN = 0; _checkMD(N, MDN, CDN);
|
||||
|
||||
if (MDP>MDN)
|
||||
// if(MDP<MDN)
|
||||
{
|
||||
PxSwap(*P, *N);
|
||||
PxSwap(P, N);
|
||||
}
|
||||
}
|
||||
_check(P);
|
||||
_check(N);
|
||||
}
|
||||
};
|
||||
Local::_check(const_cast<AABBTreeNode*>(Source.getNodes()));
|
||||
}
|
||||
|
||||
|
||||
PxU32 nbNodes = 1;
|
||||
BV32Node* Root32 = PX_NEW(BV32Node);
|
||||
|
||||
{
|
||||
GU_PROFILE_ZONE("....buildBV32")
|
||||
buildBV32(Source, Root32, Source.getNodes(), epsilon, nbNodes);
|
||||
}
|
||||
|
||||
#if BV32_VALIDATE
|
||||
validateNodeBound(Root32, mesh, epsilon);
|
||||
#endif
|
||||
|
||||
if (!bv32Tree.init(mesh, Source.getBV()))
|
||||
return false;
|
||||
BV32Tree* T = &bv32Tree;
|
||||
|
||||
PxU32 MaxDepth = 0;
|
||||
|
||||
// Version with variable-sized nodes in single stream
|
||||
{
|
||||
GU_PROFILE_ZONE("...._flatten")
|
||||
|
||||
struct Local
|
||||
{
|
||||
static void _flatten(BV32Data* const dest, const PxU32 box_id, PxU32& current_id, const BV32Node* current, PxU32& max_depth, PxU32& current_depth, const PxU32 nb_nodes)
|
||||
{
|
||||
// Entering a new node => increase depth
|
||||
current_depth++;
|
||||
// Keep track of max depth
|
||||
if (current_depth>max_depth)
|
||||
max_depth = current_depth;
|
||||
|
||||
for (PxU32 i = 0; i<current->mNbChildBVNodes; i++)
|
||||
{
|
||||
dest[box_id + i].mMin = current->mBVData[i].mMin;
|
||||
dest[box_id + i].mMax = current->mBVData[i].mMax;
|
||||
dest[box_id + i].mData = PxU32(current->mBVData[i].mData);
|
||||
dest[box_id + i].mDepth = current_depth;
|
||||
|
||||
PX_ASSERT(box_id + i < nb_nodes);
|
||||
}
|
||||
|
||||
PxU32 NbToGo = 0;
|
||||
PxU32 NextIDs[32];
|
||||
PxMemSet(NextIDs, PX_INVALID_U32, sizeof(PxU32)*32);
|
||||
const BV32Node* ChildNodes[32];
|
||||
PxMemSet(ChildNodes, 0, sizeof(BV32Node*)*32);
|
||||
|
||||
BV32Data* data = dest + box_id;
|
||||
for (PxU32 i = 0; i<current->mNbChildBVNodes; i++)
|
||||
{
|
||||
PX_ASSERT(current->mBVData[i].mData != PX_INVALID_U32);
|
||||
|
||||
if (!current->isLeaf(i))
|
||||
{
|
||||
|
||||
const BV32Node* ChildNode = current->getChild(i);
|
||||
|
||||
const PxU32 NextID = current_id;
|
||||
|
||||
const PxU32 ChildSize = ChildNode->mNbChildBVNodes;
|
||||
current_id += ChildSize;
|
||||
|
||||
const PxU32 ChildType = ChildNode->mNbChildBVNodes << 1;
|
||||
data[i].mData = size_t(ChildType + (NextID << GU_BV4_CHILD_OFFSET_SHIFT_COUNT));
|
||||
//PX_ASSERT(data[i].mData == size_t(ChildType+(NextID<<3)));
|
||||
|
||||
PX_ASSERT(box_id + i < nb_nodes);
|
||||
|
||||
NextIDs[NbToGo] = NextID;
|
||||
ChildNodes[NbToGo] = ChildNode;
|
||||
NbToGo++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (PxU32 i = 0; i<NbToGo; i++)
|
||||
{
|
||||
_flatten(dest, NextIDs[i], current_id, ChildNodes[i], max_depth, current_depth, nb_nodes);
|
||||
current_depth--;
|
||||
}
|
||||
|
||||
PX_DELETE(current);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PxU32 CurID = Root32->mNbChildBVNodes+1;
|
||||
|
||||
BV32Data* Nodes = PX_NEW(BV32Data)[nbNodes];
|
||||
Nodes[0].mMin = Source.getBV().minimum;
|
||||
Nodes[0].mMax = Source.getBV().maximum;
|
||||
|
||||
const PxU32 ChildType = Root32->mNbChildBVNodes << 1;
|
||||
Nodes[0].mData = size_t(ChildType + (1 << GU_BV4_CHILD_OFFSET_SHIFT_COUNT));
|
||||
|
||||
const PxU32 nbChilden = Nodes[0].getNbChildren();
|
||||
|
||||
PX_UNUSED(nbChilden);
|
||||
|
||||
|
||||
T->mInitData = CurID;
|
||||
|
||||
PxU32 CurrentDepth = 0;
|
||||
|
||||
Local::_flatten(Nodes, 1, CurID, Root32, MaxDepth, CurrentDepth, nbNodes);
|
||||
|
||||
PX_ASSERT(CurID == nbNodes);
|
||||
|
||||
T->mNbNodes = nbNodes;
|
||||
|
||||
T->mNodes = Nodes;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
GU_PROFILE_ZONE("....calculateLeafNode")
|
||||
|
||||
BV32Data* nodes = bv32Tree.mNodes;
|
||||
|
||||
for(PxU32 i=0; i<nbNodes; i++)
|
||||
{
|
||||
BV32Data& node = nodes[i];
|
||||
if(!node.isLeaf())
|
||||
{
|
||||
PxU32 nbChildren = node.getNbChildren();
|
||||
PxU32 offset = node.getChildOffset();
|
||||
//calculate how many children nodes are leaf nodes
|
||||
PxU32 nbLeafNodes = 0;
|
||||
while(nbChildren--)
|
||||
{
|
||||
BV32Data& child = nodes[offset++];
|
||||
if(child.isLeaf())
|
||||
nbLeafNodes++;
|
||||
}
|
||||
|
||||
node.mNbLeafNodes = nbLeafNodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bv32Tree.mPackedNodes = PX_ALLOCATE(BV32DataPacked, nbNodes, "BV32DataPacked");
|
||||
bv32Tree.mNbPackedNodes = nbNodes;
|
||||
bv32Tree.mMaxTreeDepth = MaxDepth;
|
||||
|
||||
PxU32 nbPackedNodes = 1;
|
||||
PxU32 currentIndex = bv32Tree.mNodes[0].getNbChildren() - bv32Tree.mNodes[0].mNbLeafNodes + 1;
|
||||
BV32DataPacked& packedData = bv32Tree.mPackedNodes[0];
|
||||
//BV32DataDepth& depthData = bv32Tree.mMaxDepthForPackedNodes[0];
|
||||
{
|
||||
GU_PROFILE_ZONE("....createSOAformatNode")
|
||||
bv32Tree.createSOAformatNode(packedData, bv32Tree.mNodes[0], 1, currentIndex, nbPackedNodes);
|
||||
}
|
||||
|
||||
PX_ASSERT(nbPackedNodes == currentIndex);
|
||||
PX_ASSERT(nbPackedNodes > 0);
|
||||
|
||||
bv32Tree.mNbPackedNodes = nbPackedNodes;
|
||||
|
||||
#if BV32_VALIDATE
|
||||
|
||||
/*for (PxU32 i = 0; i < nbNodes; ++i)
|
||||
{
|
||||
BV32Data& iNode = bv32Tree.mNodes[i];
|
||||
for (PxU32 j = i+1; j < nbNodes; ++j)
|
||||
{
|
||||
BV32Data& jNode = bv32Tree.mNodes[j];
|
||||
PX_ASSERT(iNode.mDepth <= jNode.mDepth);
|
||||
}
|
||||
}*/
|
||||
|
||||
#endif
|
||||
|
||||
{
|
||||
GU_PROFILE_ZONE("....depth stuff")
|
||||
|
||||
//bv32Tree.mMaxDepthForPackedNodes = reinterpret_cast<BV32DataDepth*>(PX_ALLOC(sizeof(BV32DataDepth)*MaxDepth, "BV32DataDepth"));
|
||||
|
||||
bv32Tree.mTreeDepthInfo = PX_ALLOCATE(BV32DataDepthInfo, MaxDepth, "BV32DataDepthInfo");
|
||||
|
||||
PxU32 totalCount = 0;
|
||||
for (PxU32 i = 0; i < MaxDepth; ++i)
|
||||
{
|
||||
PxU32 count = 0;
|
||||
for (PxU32 j = 0; j < nbPackedNodes; ++j)
|
||||
{
|
||||
BV32DataPacked& jPackedData = bv32Tree.mPackedNodes[j];
|
||||
if (jPackedData.mDepth == i)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
bv32Tree.mTreeDepthInfo[i].offset = totalCount;
|
||||
bv32Tree.mTreeDepthInfo[i].count = count;
|
||||
totalCount += count;
|
||||
}
|
||||
|
||||
PX_ASSERT(totalCount == nbPackedNodes);
|
||||
bv32Tree.mRemapPackedNodeIndexWithDepth = PX_ALLOCATE(PxU32, nbPackedNodes, "PxU32");
|
||||
|
||||
for (PxU32 i = 0; i < MaxDepth; ++i)
|
||||
{
|
||||
PxU32 count = 0;
|
||||
const PxU32 offset = bv32Tree.mTreeDepthInfo[i].offset;
|
||||
PxU32* treeDepth = &bv32Tree.mRemapPackedNodeIndexWithDepth[offset];
|
||||
for (PxU32 j = 0; j < nbPackedNodes; ++j)
|
||||
{
|
||||
BV32DataPacked& jPackedData = bv32Tree.mPackedNodes[j];
|
||||
if (jPackedData.mDepth == i)
|
||||
{
|
||||
treeDepth[count++] = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if BV32_VALIDATE
|
||||
for (PxU32 i = MaxDepth; i > 0; i--)
|
||||
{
|
||||
const PxU32 iOffset = bv32Tree.mTreeDepthInfo[i - 1].offset;
|
||||
const PxU32 iCount = bv32Tree.mTreeDepthInfo[i - 1].count;
|
||||
PxU32* iRempapNodeIndex = &bv32Tree.mRemapPackedNodeIndexWithDepth[iOffset];
|
||||
|
||||
for (PxU32 j = 0; j < iCount; ++j)
|
||||
{
|
||||
const PxU32 nodeIndex = iRempapNodeIndex[j];
|
||||
BV32DataPacked& currentNode = bv32Tree.mPackedNodes[nodeIndex];
|
||||
PX_ASSERT(currentNode.mDepth == i - 1);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/////
|
||||
|
||||
struct ReorderData32
|
||||
{
|
||||
//const SourceMesh* mMesh;
|
||||
SourceMeshBase* mMesh;
|
||||
PxU32* mOrder;
|
||||
PxU32 mNbPrimitivesPerLeaf;
|
||||
PxU32 mIndex;
|
||||
PxU32 mNbPrimitives;
|
||||
PxU32 mStats[32];
|
||||
};
|
||||
|
||||
static bool gReorderCallback(const AABBTreeNode* current, PxU32 /*depth*/, void* userData)
|
||||
{
|
||||
ReorderData32* Data = reinterpret_cast<ReorderData32*>(userData);
|
||||
if (current->isLeaf())
|
||||
{
|
||||
const PxU32 n = current->getNbPrimitives();
|
||||
PX_ASSERT(n > 0);
|
||||
PX_ASSERT(n <= Data->mNbPrimitivesPerLeaf);
|
||||
Data->mStats[n-1]++;
|
||||
PxU32* Prims = const_cast<PxU32*>(current->getPrimitives());
|
||||
|
||||
for (PxU32 i = 0; i<n; i++)
|
||||
{
|
||||
PX_ASSERT(Prims[i]<Data->mNbPrimitives);
|
||||
Data->mOrder[Data->mIndex] = Prims[i];
|
||||
PX_ASSERT(Data->mIndex<Data->mNbPrimitives);
|
||||
Prims[i] = Data->mIndex;
|
||||
Data->mIndex++;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Gu::BuildBV32Ex(BV32Tree& tree, SourceMeshBase& mesh, float epsilon, PxU32 nbPrimitivesPerLeaf)
|
||||
{
|
||||
const PxU32 nbPrimitives = mesh.getNbPrimitives();
|
||||
|
||||
BV4_AABBTree Source;
|
||||
{
|
||||
GU_PROFILE_ZONE("..BuildBV32Ex_buildFromMesh")
|
||||
|
||||
// if (!Source.buildFromMesh(mesh, nbPrimitivesPerLeaf, BV4_SPLATTER_POINTS_SPLIT_GEOM_CENTER))
|
||||
if (!Source.buildFromMesh(mesh, nbPrimitivesPerLeaf, BV4_SAH))
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
GU_PROFILE_ZONE("..BuildBV32Ex_remap")
|
||||
|
||||
PxU32* order = PX_ALLOCATE(PxU32, nbPrimitives, "BV32");
|
||||
ReorderData32 RD;
|
||||
RD.mMesh = &mesh;
|
||||
RD.mOrder = order;
|
||||
RD.mNbPrimitivesPerLeaf = nbPrimitivesPerLeaf;
|
||||
RD.mIndex = 0;
|
||||
RD.mNbPrimitives = nbPrimitives;
|
||||
for (PxU32 i = 0; i<32; i++)
|
||||
RD.mStats[i] = 0;
|
||||
Source.walk(gReorderCallback, &RD);
|
||||
PX_ASSERT(RD.mIndex == nbPrimitives);
|
||||
mesh.remapTopology(order);
|
||||
PX_FREE(order);
|
||||
// for(PxU32 i=0;i<16;i++)
|
||||
// printf("%d: %d\n", i, RD.mStats[i]);
|
||||
}
|
||||
|
||||
|
||||
/*if (mesh.getNbPrimitives() <= nbPrimitivesPerLeaf)
|
||||
return tree.init(&mesh, Source.getBV());*/
|
||||
|
||||
return BuildBV32Internal(tree, Source, &mesh, epsilon);
|
||||
}
|
||||
49
engine/third_party/physx/source/geomutils/src/mesh/GuBV32Build.h
vendored
Normal file
49
engine/third_party/physx/source/geomutils/src/mesh/GuBV32Build.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV32_BUILD_H
|
||||
#define GU_BV32_BUILD_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "common/PxPhysXCommonConfig.h"
|
||||
|
||||
#define BV32_VALIDATE 0
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class BV32Tree;
|
||||
class SourceMeshBase;
|
||||
|
||||
bool BuildBV32Ex(BV32Tree& tree, SourceMeshBase& mesh, float epsilon, PxU32 nbPrimitivesPerLeaf);
|
||||
|
||||
} // namespace Gu
|
||||
}
|
||||
|
||||
#endif // GU_BV32_BUILD_H
|
||||
737
engine/third_party/physx/source/geomutils/src/mesh/GuBV4.cpp
vendored
Normal file
737
engine/third_party/physx/source/geomutils/src/mesh/GuBV4.cpp
vendored
Normal file
@@ -0,0 +1,737 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxMemory.h"
|
||||
#include "GuBV4.h"
|
||||
#include "GuBV4_Common.h"
|
||||
#include "CmSerialize.h"
|
||||
#include "foundation/PxVecMath.h"
|
||||
#include "common/PxSerialFramework.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
using namespace Cm;
|
||||
using namespace aos;
|
||||
|
||||
SourceMeshBase::SourceMeshBase(MeshType meshType) : mNbVerts(0), mVerts(NULL), mType(meshType), mRemap(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
SourceMeshBase::~SourceMeshBase()
|
||||
{
|
||||
PX_FREE(mRemap);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TetrahedronSourceMesh::TetrahedronSourceMesh() : SourceMeshBase(MeshType::TET_MESH)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
TetrahedronSourceMesh::~TetrahedronSourceMesh()
|
||||
{
|
||||
}
|
||||
|
||||
void TetrahedronSourceMesh::reset()
|
||||
{
|
||||
mNbVerts = 0;
|
||||
mVerts = NULL;
|
||||
mNbTetrahedrons = 0;
|
||||
mTetrahedrons32 = NULL;
|
||||
mTetrahedrons16 = NULL;
|
||||
mRemap = NULL;
|
||||
}
|
||||
|
||||
void TetrahedronSourceMesh::operator=(TetrahedronSourceMesh& v)
|
||||
{
|
||||
mNbVerts = v.mNbVerts;
|
||||
mVerts = v.mVerts;
|
||||
mNbTetrahedrons = v.mNbTetrahedrons;
|
||||
mTetrahedrons32 = v.mTetrahedrons32;
|
||||
mTetrahedrons16 = v.mTetrahedrons16;
|
||||
v.reset();
|
||||
}
|
||||
|
||||
void TetrahedronSourceMesh::remapTopology(const PxU32* order)
|
||||
{
|
||||
if(!mNbTetrahedrons)
|
||||
return;
|
||||
|
||||
if(mTetrahedrons32)
|
||||
{
|
||||
IndTetrahedron32* newTopo = PX_NEW(IndTetrahedron32)[mNbTetrahedrons];
|
||||
for(PxU32 i = 0; i<mNbTetrahedrons; i++)
|
||||
newTopo[i] = mTetrahedrons32[order[i]];
|
||||
|
||||
PxMemCopy(mTetrahedrons32, newTopo, sizeof(IndTetrahedron32)*mNbTetrahedrons);
|
||||
PX_DELETE_ARRAY(newTopo);
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(mTetrahedrons16);
|
||||
IndTetrahedron16* newTopo = PX_NEW(IndTetrahedron16)[mNbTetrahedrons];
|
||||
for(PxU32 i = 0; i<mNbTetrahedrons; i++)
|
||||
newTopo[i] = mTetrahedrons16[order[i]];
|
||||
|
||||
PxMemCopy(mTetrahedrons16, newTopo, sizeof(IndTetrahedron16)*mNbTetrahedrons);
|
||||
PX_DELETE_ARRAY(newTopo);
|
||||
}
|
||||
|
||||
{
|
||||
PxU32* newMap = PX_ALLOCATE(PxU32, mNbTetrahedrons, "newMap");
|
||||
for(PxU32 i = 0; i<mNbTetrahedrons; i++)
|
||||
newMap[i] = mRemap ? mRemap[order[i]] : order[i];
|
||||
|
||||
PX_FREE(mRemap);
|
||||
mRemap = newMap;
|
||||
}
|
||||
}
|
||||
|
||||
void TetrahedronSourceMesh::getPrimitiveBox(const PxU32 primitiveInd, Vec4V& minV, Vec4V& maxV)
|
||||
{
|
||||
TetrahedronPointers VP;
|
||||
getTetrahedron(VP, primitiveInd);
|
||||
|
||||
const Vec4V v0V = V4LoadU(&VP.Vertex[0]->x);
|
||||
const Vec4V v1V = V4LoadU(&VP.Vertex[1]->x);
|
||||
const Vec4V v2V = V4LoadU(&VP.Vertex[2]->x);
|
||||
const Vec4V v3V = V4LoadU(&VP.Vertex[3]->x);
|
||||
minV = V4Min(v0V, v1V);
|
||||
minV = V4Min(minV, v2V);
|
||||
minV = V4Min(minV, v3V);
|
||||
|
||||
maxV = V4Max(v0V, v1V);
|
||||
maxV = V4Max(maxV, v2V);
|
||||
maxV = V4Max(maxV, v3V);
|
||||
}
|
||||
|
||||
void TetrahedronSourceMesh::refit(const PxU32 primitiveInd, PxBounds3& refitBox)
|
||||
{
|
||||
TetrahedronPointers VP;
|
||||
getTetrahedron(VP, primitiveInd);
|
||||
|
||||
refitBox.include(*VP.Vertex[0]);
|
||||
refitBox.include(*VP.Vertex[1]);
|
||||
refitBox.include(*VP.Vertex[2]);
|
||||
refitBox.include(*VP.Vertex[3]);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SourceMesh::SourceMesh() : SourceMeshBase(MeshType::TRI_MESH)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
SourceMesh::~SourceMesh()
|
||||
{
|
||||
}
|
||||
|
||||
void SourceMesh::reset()
|
||||
{
|
||||
mNbVerts = 0;
|
||||
mVerts = NULL;
|
||||
mNbTris = 0;
|
||||
mTriangles32 = NULL;
|
||||
mTriangles16 = NULL;
|
||||
mRemap = NULL;
|
||||
}
|
||||
|
||||
void SourceMesh::operator=(SourceMesh& v)
|
||||
{
|
||||
mNbVerts = v.mNbVerts;
|
||||
mVerts = v.mVerts;
|
||||
mNbTris = v.mNbTris;
|
||||
mTriangles32 = v.mTriangles32;
|
||||
mTriangles16 = v.mTriangles16;
|
||||
mRemap = v.mRemap;
|
||||
v.reset();
|
||||
}
|
||||
|
||||
void SourceMesh::remapTopology(const PxU32* order)
|
||||
{
|
||||
if(!mNbTris)
|
||||
return;
|
||||
|
||||
if(mTriangles32)
|
||||
{
|
||||
IndTri32* newTopo = PX_NEW(IndTri32)[mNbTris];
|
||||
for(PxU32 i=0;i<mNbTris;i++)
|
||||
newTopo[i] = mTriangles32[order[i]];
|
||||
|
||||
PxMemCopy(mTriangles32, newTopo, sizeof(IndTri32)*mNbTris);
|
||||
PX_DELETE_ARRAY(newTopo);
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(mTriangles16);
|
||||
IndTri16* newTopo = PX_NEW(IndTri16)[mNbTris];
|
||||
for(PxU32 i=0;i<mNbTris;i++)
|
||||
newTopo[i] = mTriangles16[order[i]];
|
||||
|
||||
PxMemCopy(mTriangles16, newTopo, sizeof(IndTri16)*mNbTris);
|
||||
PX_DELETE_ARRAY(newTopo);
|
||||
}
|
||||
|
||||
{
|
||||
PxU32* newMap = PX_ALLOCATE(PxU32, mNbTris, "newMap");
|
||||
for(PxU32 i=0;i<mNbTris;i++)
|
||||
newMap[i] = mRemap ? mRemap[order[i]] : order[i];
|
||||
|
||||
PX_FREE(mRemap);
|
||||
mRemap = newMap;
|
||||
}
|
||||
}
|
||||
|
||||
void SourceMesh::getPrimitiveBox(const PxU32 primitiveInd, Vec4V& minV, Vec4V& maxV)
|
||||
{
|
||||
VertexPointers VP;
|
||||
getTriangle(VP, primitiveInd);
|
||||
|
||||
const Vec4V v0V = V4LoadU(&VP.Vertex[0]->x);
|
||||
const Vec4V v1V = V4LoadU(&VP.Vertex[1]->x);
|
||||
const Vec4V v2V = V4LoadU(&VP.Vertex[2]->x);
|
||||
minV = V4Min(v0V, v1V);
|
||||
minV = V4Min(minV, v2V);
|
||||
|
||||
maxV = V4Max(v0V, v1V);
|
||||
maxV = V4Max(maxV, v2V);
|
||||
}
|
||||
|
||||
void SourceMesh::refit(const PxU32 primitiveInd, PxBounds3& refitBox)
|
||||
{
|
||||
VertexPointers VP;
|
||||
getTriangle(VP, primitiveInd);
|
||||
|
||||
refitBox.include(*VP.Vertex[0]);
|
||||
refitBox.include(*VP.Vertex[1]);
|
||||
refitBox.include(*VP.Vertex[2]);
|
||||
}
|
||||
|
||||
bool SourceMesh::isValid() const
|
||||
{
|
||||
if(!mNbTris || !mNbVerts) return false;
|
||||
if(!mVerts) return false;
|
||||
if(!mTriangles32 && !mTriangles16) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/////
|
||||
|
||||
BV4Tree::BV4Tree(SourceMesh* meshInterface, const PxBounds3& localBounds)
|
||||
{
|
||||
reset();
|
||||
init(meshInterface, localBounds);
|
||||
}
|
||||
|
||||
BV4Tree::BV4Tree()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void BV4Tree::release()
|
||||
{
|
||||
if(!mUserAllocated)
|
||||
{
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
PX_FREE(mNodes);
|
||||
// PX_DELETE(mNodes);
|
||||
#else
|
||||
PX_DELETE_ARRAY(mNodes);
|
||||
#endif
|
||||
}
|
||||
|
||||
mNodes = NULL;
|
||||
mNbNodes = 0;
|
||||
reset();
|
||||
}
|
||||
|
||||
BV4Tree::~BV4Tree()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void BV4Tree::reset()
|
||||
{
|
||||
mMeshInterface = NULL;
|
||||
//mTetrahedronMeshInterface = NULL;
|
||||
mNbNodes = 0;
|
||||
mNodes = NULL;
|
||||
mInitData = 0;
|
||||
mCenterOrMinCoeff = PxVec3(0.0f);
|
||||
mExtentsOrMaxCoeff = PxVec3(0.0f);
|
||||
mUserAllocated = false;
|
||||
mQuantized = false;
|
||||
mIsEdgeSet = false;
|
||||
}
|
||||
|
||||
void BV4Tree::operator=(BV4Tree& v)
|
||||
{
|
||||
mMeshInterface = v.mMeshInterface;
|
||||
//mTetrahedronMeshInterface = v.mTetrahedronMeshInterface;
|
||||
mLocalBounds = v.mLocalBounds;
|
||||
mNbNodes = v.mNbNodes;
|
||||
mNodes = v.mNodes;
|
||||
mInitData = v.mInitData;
|
||||
mCenterOrMinCoeff = v.mCenterOrMinCoeff;
|
||||
mExtentsOrMaxCoeff = v.mExtentsOrMaxCoeff;
|
||||
mUserAllocated = v.mUserAllocated;
|
||||
mQuantized = v.mQuantized;
|
||||
mIsEdgeSet = false;
|
||||
v.reset();
|
||||
}
|
||||
|
||||
bool BV4Tree::init(SourceMeshBase* meshInterface, const PxBounds3& localBounds)
|
||||
{
|
||||
mMeshInterface = meshInterface;
|
||||
mLocalBounds.init(localBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
//bool BV4Tree::init(TetrahedronSourceMesh* meshInterface, const PxBounds3& localBounds)
|
||||
//{
|
||||
// mTetrahedronMeshInterface = meshInterface;
|
||||
// mLocalBounds.init(localBounds);
|
||||
// return true;
|
||||
//}
|
||||
|
||||
// PX_SERIALIZATION
|
||||
BV4Tree::BV4Tree(const PxEMPTY) : mLocalBounds(PxEmpty)
|
||||
{
|
||||
mUserAllocated = true;
|
||||
mIsEdgeSet = false;
|
||||
}
|
||||
|
||||
void BV4Tree::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
if(mNbNodes)
|
||||
{
|
||||
stream.alignData(16);
|
||||
const PxU32 nodeSize = mQuantized ? sizeof(BVDataPackedQ) : sizeof(BVDataPackedNQ);
|
||||
stream.writeData(mNodes, mNbNodes*nodeSize);
|
||||
}
|
||||
}
|
||||
|
||||
void BV4Tree::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
if(mNbNodes)
|
||||
{
|
||||
context.alignExtraData(16);
|
||||
if(mQuantized)
|
||||
mNodes = context.readExtraData<BVDataPackedQ>(mNbNodes);
|
||||
else
|
||||
mNodes = context.readExtraData<BVDataPackedNQ>(mNbNodes);
|
||||
}
|
||||
}
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
bool BV4Tree::load(PxInputStream& stream, bool mismatch_)
|
||||
{
|
||||
PX_ASSERT(!mUserAllocated);
|
||||
|
||||
release();
|
||||
|
||||
PxI8 a, b, c, d;
|
||||
readChunk(a, b, c, d, stream);
|
||||
if(a!='B' || b!='V' || c!='4' || d!=' ')
|
||||
return false;
|
||||
|
||||
bool mismatch;
|
||||
PxU32 fileVersion;
|
||||
if(!readBigEndianVersionNumber(stream, mismatch_, fileVersion, mismatch))
|
||||
return false;
|
||||
|
||||
readFloatBuffer(&mLocalBounds.mCenter.x, 3, mismatch, stream);
|
||||
mLocalBounds.mExtentsMagnitude = readFloat(mismatch, stream);
|
||||
|
||||
mInitData = readDword(mismatch, stream);
|
||||
|
||||
readFloatBuffer(&mCenterOrMinCoeff.x, 3, mismatch, stream);
|
||||
readFloatBuffer(&mExtentsOrMaxCoeff.x, 3, mismatch, stream);
|
||||
|
||||
// PT: version 3
|
||||
if(fileVersion>=3)
|
||||
{
|
||||
const PxU32 Quantized = readDword(mismatch, stream);
|
||||
mQuantized = Quantized!=0;
|
||||
}
|
||||
else
|
||||
mQuantized = true;
|
||||
|
||||
const PxU32 nbNodes = readDword(mismatch, stream);
|
||||
mNbNodes = nbNodes;
|
||||
|
||||
if(nbNodes)
|
||||
{
|
||||
PxU32 dataSize = 0;
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
const PxU32 nodeSize = mQuantized ? sizeof(BVDataPackedQ) : sizeof(BVDataPackedNQ);
|
||||
dataSize = nodeSize*nbNodes;
|
||||
void* nodes = PX_ALLOC(dataSize, "BV4 nodes"); // PT: PX_NEW breaks alignment here
|
||||
// BVDataPacked* nodes = reinterpret_cast<BVDataPacked*>(PX_ALLOC(sizeof(BVDataPacked)*nbNodes, "BV4 nodes")); // PT: PX_NEW breaks alignment here
|
||||
mNodes = nodes;
|
||||
#else
|
||||
BVDataPacked* nodes = PX_NEW(BVDataPacked)[nbNodes];
|
||||
mNodes = nodes;
|
||||
#endif
|
||||
// PxMarkSerializedMemory(nodes, dataSize);
|
||||
|
||||
stream.read(nodes, dataSize);
|
||||
PX_ASSERT(!mismatch);
|
||||
}
|
||||
else mNodes = NULL;
|
||||
|
||||
mIsEdgeSet = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define VERSION2
|
||||
#ifdef VERSION1
|
||||
bool BV4Tree::refit(PxBounds3& globalBounds, float epsilon)
|
||||
{
|
||||
if(mQuantized)
|
||||
|
||||
if(!mNodes)
|
||||
{
|
||||
PxBounds3 bounds;
|
||||
bounds.setEmpty();
|
||||
if(mMeshInterface)
|
||||
{
|
||||
PxU32 nbVerts = mMeshInterface->getNbVertices();
|
||||
const PxVec3* verts = mMeshInterface->getVerts();
|
||||
while(nbVerts--)
|
||||
bounds.include(*verts++);
|
||||
mLocalBounds.init(bounds);
|
||||
}
|
||||
if(mTetrahedronMeshInterface)
|
||||
{
|
||||
PX_ASSERT(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class PxBounds3Padded : public PxBounds3
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE PxBounds3Padded() {}
|
||||
PX_FORCE_INLINE ~PxBounds3Padded() {}
|
||||
PxU32 padding;
|
||||
};
|
||||
|
||||
PX_ASSERT(!(mNbNodes&3));
|
||||
PxU32 nb = mNbNodes/4;
|
||||
BVDataSwizzledNQ* data = reinterpret_cast<BVDataSwizzledNQ*>(mNodes);
|
||||
while(nb--)
|
||||
{
|
||||
BVDataSwizzledNQ* PX_RESTRICT current = data + nb;
|
||||
|
||||
for(PxU32 j=0;j<4;j++)
|
||||
{
|
||||
if(current->getChildData(j)==PX_INVALID_U32)
|
||||
continue;
|
||||
|
||||
Vec4V minV = V4Load(FLT_MAX);
|
||||
Vec4V maxV = V4Load(-FLT_MAX);
|
||||
|
||||
if(current->isLeaf(j))
|
||||
{
|
||||
PxU32 primIndex = current->getPrimitive(j);
|
||||
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
VertexPointers VP;
|
||||
do
|
||||
{
|
||||
PX_ASSERT(primIndex<mMeshInterface->getNbTriangles());
|
||||
mMeshInterface->getTriangle(VP, primIndex);
|
||||
|
||||
const Vec4V v0V = V4LoadU(&VP.Vertex[0]->x);
|
||||
const Vec4V v1V = V4LoadU(&VP.Vertex[1]->x);
|
||||
const Vec4V v2V = V4LoadU(&VP.Vertex[2]->x);
|
||||
minV = V4Min(minV, v0V);
|
||||
minV = V4Min(minV, v1V);
|
||||
minV = V4Min(minV, v2V);
|
||||
maxV = V4Max(maxV, v0V);
|
||||
maxV = V4Max(maxV, v1V);
|
||||
maxV = V4Max(maxV, v2V);
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
const Vec4V epsilonV = V4Load(epsilon);
|
||||
minV = V4Sub(minV, epsilonV);
|
||||
maxV = V4Add(maxV, epsilonV);
|
||||
}
|
||||
else
|
||||
{
|
||||
PxU32 childOffset = current->getChildOffset(j);
|
||||
PX_ASSERT(!(childOffset&3));
|
||||
childOffset>>=2;
|
||||
PX_ASSERT(childOffset>nb);
|
||||
const PxU32 childType = current->getChildType(j);
|
||||
|
||||
// PT: TODO: revisit SIMD here, not great
|
||||
const BVDataSwizzledNQ* PX_RESTRICT next = data + childOffset;
|
||||
{
|
||||
{
|
||||
const Vec4V childMinV = V4LoadXYZW(next->mMinX[0], next->mMinY[0], next->mMinZ[0], 0.0f);
|
||||
const Vec4V childMaxV = V4LoadXYZW(next->mMaxX[0], next->mMaxY[0], next->mMaxZ[0], 0.0f);
|
||||
// minV = V4Min(minV, childMinV);
|
||||
// maxV = V4Max(maxV, childMaxV);
|
||||
minV = childMinV;
|
||||
maxV = childMaxV;
|
||||
}
|
||||
|
||||
{
|
||||
const Vec4V childMinV = V4LoadXYZW(next->mMinX[1], next->mMinY[1], next->mMinZ[1], 0.0f);
|
||||
const Vec4V childMaxV = V4LoadXYZW(next->mMaxX[1], next->mMaxY[1], next->mMaxZ[1], 0.0f);
|
||||
minV = V4Min(minV, childMinV);
|
||||
maxV = V4Max(maxV, childMaxV);
|
||||
}
|
||||
|
||||
/* {
|
||||
const Vec4V childMinV0 = V4LoadXYZW(next->mMinX[0], next->mMinY[0], next->mMinZ[0], 0.0f);
|
||||
const Vec4V childMaxV0 = V4LoadXYZW(next->mMaxX[0], next->mMaxY[0], next->mMaxZ[0], 0.0f);
|
||||
const Vec4V childMinV1 = V4LoadXYZW(next->mMinX[1], next->mMinY[1], next->mMinZ[1], 0.0f);
|
||||
const Vec4V childMaxV1 = V4LoadXYZW(next->mMaxX[1], next->mMaxY[1], next->mMaxZ[1], 0.0f);
|
||||
minV = V4Min(childMinV0, childMinV1);
|
||||
maxV = V4Max(childMaxV0, childMaxV1);
|
||||
}*/
|
||||
|
||||
if(childType>0)
|
||||
{
|
||||
const Vec4V childMinV = V4LoadXYZW(next->mMinX[2], next->mMinY[2], next->mMinZ[2], 0.0f);
|
||||
const Vec4V childMaxV = V4LoadXYZW(next->mMaxX[2], next->mMaxY[2], next->mMaxZ[2], 0.0f);
|
||||
minV = V4Min(minV, childMinV);
|
||||
maxV = V4Max(maxV, childMaxV);
|
||||
}
|
||||
|
||||
if(childType>1)
|
||||
{
|
||||
const Vec4V childMinV = V4LoadXYZW(next->mMinX[3], next->mMinY[3], next->mMinZ[3], 0.0f);
|
||||
const Vec4V childMaxV = V4LoadXYZW(next->mMaxX[3], next->mMaxY[3], next->mMaxZ[3], 0.0f);
|
||||
minV = V4Min(minV, childMinV);
|
||||
maxV = V4Max(maxV, childMaxV);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PxBounds3Padded refitBox;
|
||||
V4StoreU_Safe(minV, &refitBox.minimum.x);
|
||||
V4StoreU_Safe(maxV, &refitBox.maximum.x);
|
||||
|
||||
current->mMinX[j] = refitBox.minimum.x;
|
||||
current->mMinY[j] = refitBox.minimum.y;
|
||||
current->mMinZ[j] = refitBox.minimum.z;
|
||||
current->mMaxX[j] = refitBox.maximum.x;
|
||||
current->mMaxY[j] = refitBox.maximum.y;
|
||||
current->mMaxZ[j] = refitBox.maximum.z;
|
||||
}
|
||||
}
|
||||
|
||||
BVDataSwizzledNQ* root = reinterpret_cast<BVDataSwizzledNQ*>(mNodes);
|
||||
{
|
||||
globalBounds.setEmpty();
|
||||
|
||||
for(PxU32 j=0;j<4;j++)
|
||||
{
|
||||
if(root->getChildData(j)==PX_INVALID_U32)
|
||||
continue;
|
||||
|
||||
PxBounds3 refitBox;
|
||||
refitBox.minimum.x = root->mMinX[j];
|
||||
refitBox.minimum.y = root->mMinY[j];
|
||||
refitBox.minimum.z = root->mMinZ[j];
|
||||
refitBox.maximum.x = root->mMaxX[j];
|
||||
refitBox.maximum.y = root->mMaxY[j];
|
||||
refitBox.maximum.z = root->mMaxZ[j];
|
||||
globalBounds.include(refitBox);
|
||||
}
|
||||
|
||||
mLocalBounds.init(globalBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef VERSION2
|
||||
bool BV4Tree::refit(PxBounds3& globalBounds, float epsilon)
|
||||
{
|
||||
if(mQuantized)
|
||||
return false;
|
||||
|
||||
if(!mNodes)
|
||||
{
|
||||
globalBounds.setEmpty();
|
||||
if(mMeshInterface)
|
||||
{
|
||||
PxU32 nbVerts = mMeshInterface->getNbVertices();
|
||||
const PxVec3* verts = mMeshInterface->getVerts();
|
||||
while(nbVerts--)
|
||||
globalBounds.include(*verts++);
|
||||
mLocalBounds.init(globalBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
class PxBounds3Padded : public PxBounds3
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE PxBounds3Padded() {}
|
||||
PX_FORCE_INLINE ~PxBounds3Padded() {}
|
||||
PxU32 padding;
|
||||
};
|
||||
|
||||
PX_ASSERT(!(mNbNodes&3));
|
||||
PxU32 nb = mNbNodes/4;
|
||||
BVDataSwizzledNQ* data = reinterpret_cast<BVDataSwizzledNQ*>(mNodes);
|
||||
|
||||
while(nb--)
|
||||
{
|
||||
BVDataSwizzledNQ* PX_RESTRICT current = data + nb;
|
||||
|
||||
for(PxU32 j=0;j<4;j++)
|
||||
{
|
||||
if(current->getChildData(j)==PX_INVALID_U32)
|
||||
continue;
|
||||
|
||||
if(current->isLeaf(j))
|
||||
{
|
||||
PxU32 primIndex = current->getPrimitive(j);
|
||||
|
||||
Vec4V minV = V4Load(FLT_MAX);
|
||||
Vec4V maxV = V4Load(-FLT_MAX);
|
||||
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
//VertexPointers VP;
|
||||
do
|
||||
{
|
||||
PX_ASSERT(primIndex< mMeshInterface->getNbPrimitives());
|
||||
|
||||
|
||||
//meshInterface->getTriangle(VP, primIndex);
|
||||
Vec4V tMin, tMax;
|
||||
mMeshInterface->getPrimitiveBox(primIndex, tMin, tMax);
|
||||
minV = V4Min(minV, tMin);
|
||||
maxV = V4Max(maxV, tMax);
|
||||
|
||||
/* const Vec4V v0V = V4LoadU(&VP.Vertex[0]->x);
|
||||
const Vec4V v1V = V4LoadU(&VP.Vertex[1]->x);
|
||||
const Vec4V v2V = V4LoadU(&VP.Vertex[2]->x);
|
||||
minV = V4Min(minV, v0V);
|
||||
minV = V4Min(minV, v1V);
|
||||
minV = V4Min(minV, v2V);
|
||||
maxV = V4Max(maxV, v0V);
|
||||
maxV = V4Max(maxV, v1V);
|
||||
maxV = V4Max(maxV, v2V);*/
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
const Vec4V epsilonV = V4Load(epsilon);
|
||||
minV = V4Sub(minV, epsilonV);
|
||||
maxV = V4Add(maxV, epsilonV);
|
||||
|
||||
PxBounds3Padded refitBox;
|
||||
V4StoreU_Safe(minV, &refitBox.minimum.x);
|
||||
V4StoreU_Safe(maxV, &refitBox.maximum.x);
|
||||
|
||||
current->mMinX[j] = refitBox.minimum.x;
|
||||
current->mMinY[j] = refitBox.minimum.y;
|
||||
current->mMinZ[j] = refitBox.minimum.z;
|
||||
current->mMaxX[j] = refitBox.maximum.x;
|
||||
current->mMaxY[j] = refitBox.maximum.y;
|
||||
current->mMaxZ[j] = refitBox.maximum.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
PxU32 childOffset = current->getChildOffset(j);
|
||||
PX_ASSERT(!(childOffset&3));
|
||||
childOffset>>=2;
|
||||
PX_ASSERT(childOffset>nb);
|
||||
const PxU32 childType = current->getChildType(j);
|
||||
|
||||
const BVDataSwizzledNQ* PX_RESTRICT next = data + childOffset;
|
||||
{
|
||||
current->mMinX[j] = PxMin(next->mMinX[0], next->mMinX[1]);
|
||||
current->mMinY[j] = PxMin(next->mMinY[0], next->mMinY[1]);
|
||||
current->mMinZ[j] = PxMin(next->mMinZ[0], next->mMinZ[1]);
|
||||
current->mMaxX[j] = PxMax(next->mMaxX[0], next->mMaxX[1]);
|
||||
current->mMaxY[j] = PxMax(next->mMaxY[0], next->mMaxY[1]);
|
||||
current->mMaxZ[j] = PxMax(next->mMaxZ[0], next->mMaxZ[1]);
|
||||
|
||||
if(childType>0)
|
||||
{
|
||||
current->mMinX[j] = PxMin(current->mMinX[j], next->mMinX[2]);
|
||||
current->mMinY[j] = PxMin(current->mMinY[j], next->mMinY[2]);
|
||||
current->mMinZ[j] = PxMin(current->mMinZ[j], next->mMinZ[2]);
|
||||
current->mMaxX[j] = PxMax(current->mMaxX[j], next->mMaxX[2]);
|
||||
current->mMaxY[j] = PxMax(current->mMaxY[j], next->mMaxY[2]);
|
||||
current->mMaxZ[j] = PxMax(current->mMaxZ[j], next->mMaxZ[2]);
|
||||
}
|
||||
|
||||
if(childType>1)
|
||||
{
|
||||
current->mMinX[j] = PxMin(current->mMinX[j], next->mMinX[3]);
|
||||
current->mMinY[j] = PxMin(current->mMinY[j], next->mMinY[3]);
|
||||
current->mMinZ[j] = PxMin(current->mMinZ[j], next->mMinZ[3]);
|
||||
current->mMaxX[j] = PxMax(current->mMaxX[j], next->mMaxX[3]);
|
||||
current->mMaxY[j] = PxMax(current->mMaxY[j], next->mMaxY[3]);
|
||||
current->mMaxZ[j] = PxMax(current->mMaxZ[j], next->mMaxZ[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BVDataSwizzledNQ* root = reinterpret_cast<BVDataSwizzledNQ*>(mNodes);
|
||||
{
|
||||
globalBounds.setEmpty();
|
||||
|
||||
for(PxU32 j=0;j<4;j++)
|
||||
{
|
||||
if(root->getChildData(j)==PX_INVALID_U32)
|
||||
continue;
|
||||
|
||||
PxBounds3 refitBox;
|
||||
refitBox.minimum.x = root->mMinX[j];
|
||||
refitBox.minimum.y = root->mMinY[j];
|
||||
refitBox.minimum.z = root->mMinZ[j];
|
||||
refitBox.maximum.x = root->mMaxX[j];
|
||||
refitBox.maximum.y = root->mMaxY[j];
|
||||
refitBox.maximum.z = root->mMaxZ[j];
|
||||
globalBounds.include(refitBox);
|
||||
}
|
||||
|
||||
mLocalBounds.init(globalBounds);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
380
engine/third_party/physx/source/geomutils/src/mesh/GuBV4.h
vendored
Normal file
380
engine/third_party/physx/source/geomutils/src/mesh/GuBV4.h
vendored
Normal file
@@ -0,0 +1,380 @@
|
||||
// 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_BV4_H
|
||||
#define GU_BV4_H
|
||||
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "GuBV4Settings.h"
|
||||
#include "GuCenterExtents.h"
|
||||
#include "GuTriangle.h"
|
||||
#include "foundation/PxVecMath.h"
|
||||
#include "common/PxPhysXCommonConfig.h"
|
||||
|
||||
#define V4LoadU_Safe physx::aos::V4LoadU // PT: prefix needed on Linux. Sigh.
|
||||
#define V4LoadA_Safe V4LoadA
|
||||
#define V4StoreA_Safe V4StoreA
|
||||
#define V4StoreU_Safe V4StoreU
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxSerializationContext;
|
||||
class PxDeserializationContext;
|
||||
class PxOutputStream;
|
||||
class PxInputStream;
|
||||
|
||||
namespace Gu
|
||||
{
|
||||
struct VertexPointers
|
||||
{
|
||||
const PxVec3* Vertex[3];
|
||||
};
|
||||
|
||||
struct TetrahedronPointers
|
||||
{
|
||||
const PxVec3* Vertex[4];
|
||||
};
|
||||
|
||||
// PT: TODO: make this more generic, rename to IndQuad32, refactor with GRB's int4
|
||||
class IndTetrahedron32 : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
public:
|
||||
PX_FORCE_INLINE IndTetrahedron32() {}
|
||||
PX_FORCE_INLINE IndTetrahedron32(PxU32 r0, PxU32 r1, PxU32 r2, PxU32 r3) { mRef[0] = r0; mRef[1] = r1; mRef[2] = r2; mRef[3] = r3; }
|
||||
PX_FORCE_INLINE IndTetrahedron32(const IndTetrahedron32& tetrahedron)
|
||||
{
|
||||
mRef[0] = tetrahedron.mRef[0];
|
||||
mRef[1] = tetrahedron.mRef[1];
|
||||
mRef[2] = tetrahedron.mRef[2];
|
||||
mRef[3] = tetrahedron.mRef[3];
|
||||
}
|
||||
PX_FORCE_INLINE ~IndTetrahedron32() {}
|
||||
PxU32 mRef[4];
|
||||
};
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(IndTetrahedron32) == 16);
|
||||
|
||||
// PT: TODO: make this more generic, rename to IndQuad16
|
||||
class IndTetrahedron16 : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
public:
|
||||
PX_FORCE_INLINE IndTetrahedron16() {}
|
||||
PX_FORCE_INLINE IndTetrahedron16(PxU16 r0, PxU16 r1, PxU16 r2, PxU16 r3) { mRef[0] = r0; mRef[1] = r1; mRef[2] = r2; mRef[3] = r3; }
|
||||
PX_FORCE_INLINE IndTetrahedron16(const IndTetrahedron16& tetrahedron)
|
||||
{
|
||||
mRef[0] = tetrahedron.mRef[0];
|
||||
mRef[1] = tetrahedron.mRef[1];
|
||||
mRef[2] = tetrahedron.mRef[2];
|
||||
mRef[3] = tetrahedron.mRef[3];
|
||||
}
|
||||
PX_FORCE_INLINE ~IndTetrahedron16() {}
|
||||
PxU16 mRef[4];
|
||||
};
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(IndTetrahedron16) == 8);
|
||||
|
||||
typedef IndexedTriangle32 IndTri32;
|
||||
typedef IndexedTriangle16 IndTri16;
|
||||
|
||||
PX_FORCE_INLINE void getVertexReferences(PxU32& vref0, PxU32& vref1, PxU32& vref2, PxU32 index, const IndTri32* T32, const IndTri16* T16)
|
||||
{
|
||||
if(T32)
|
||||
{
|
||||
const IndTri32* PX_RESTRICT tri = T32 + index;
|
||||
vref0 = tri->mRef[0];
|
||||
vref1 = tri->mRef[1];
|
||||
vref2 = tri->mRef[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
const IndTri16* PX_RESTRICT tri = T16 + index;
|
||||
vref0 = tri->mRef[0];
|
||||
vref1 = tri->mRef[1];
|
||||
vref2 = tri->mRef[2];
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void getVertexReferences(PxU32& vref0, PxU32& vref1, PxU32& vref2, PxU32& vref3, PxU32 index, const IndTetrahedron32* T32, const IndTetrahedron16* T16)
|
||||
{
|
||||
if(T32)
|
||||
{
|
||||
const IndTetrahedron32* PX_RESTRICT tet = T32 + index;
|
||||
vref0 = tet->mRef[0];
|
||||
vref1 = tet->mRef[1];
|
||||
vref2 = tet->mRef[2];
|
||||
vref3 = tet->mRef[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
const IndTetrahedron16* PX_RESTRICT tet = T16 + index;
|
||||
vref0 = tet->mRef[0];
|
||||
vref1 = tet->mRef[1];
|
||||
vref2 = tet->mRef[2];
|
||||
vref3 = tet->mRef[3];
|
||||
}
|
||||
}
|
||||
|
||||
class SourceMeshBase : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
enum MeshType
|
||||
{
|
||||
TRI_MESH,
|
||||
TET_MESH,
|
||||
FORCE_DWORD = 0x7fffffff
|
||||
};
|
||||
SourceMeshBase(MeshType meshType);
|
||||
virtual ~SourceMeshBase();
|
||||
|
||||
SourceMeshBase(const PxEMPTY) {}
|
||||
|
||||
PxU32 mNbVerts;
|
||||
const PxVec3* mVerts;
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbVertices() const { return mNbVerts; }
|
||||
PX_FORCE_INLINE const PxVec3* getVerts() const { return mVerts; }
|
||||
|
||||
PX_FORCE_INLINE void setNbVertices(PxU32 nb) { mNbVerts = nb; }
|
||||
|
||||
PX_FORCE_INLINE void initRemap() { mRemap = NULL; }
|
||||
PX_FORCE_INLINE const PxU32* getRemap() const { return mRemap; }
|
||||
PX_FORCE_INLINE void releaseRemap() { PX_FREE(mRemap); }
|
||||
|
||||
PX_FORCE_INLINE MeshType getMeshType() const { return mType; }
|
||||
|
||||
// PT: TODO: check whether adding these vcalls affected build & runtime performance
|
||||
virtual PxU32 getNbPrimitives() const = 0;
|
||||
virtual void remapTopology(const PxU32* order) = 0;
|
||||
virtual void getPrimitiveBox(const PxU32 primitiveInd, physx::aos::Vec4V& minV, physx::aos::Vec4V& maxV) = 0;
|
||||
virtual void refit(const PxU32 primitiveInd, PxBounds3& refitBox) = 0;
|
||||
|
||||
protected:
|
||||
MeshType mType;
|
||||
PxU32* mRemap;
|
||||
};
|
||||
|
||||
class SourceMesh : public SourceMeshBase
|
||||
{
|
||||
public:
|
||||
SourceMesh();
|
||||
virtual ~SourceMesh();
|
||||
// PX_SERIALIZATION
|
||||
SourceMesh(const PxEMPTY) : SourceMeshBase(PxEmpty) {}
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
void reset();
|
||||
void operator = (SourceMesh& v);
|
||||
|
||||
PxU32 mNbTris;
|
||||
IndTri32* mTriangles32;
|
||||
IndTri16* mTriangles16;
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbTriangles() const { return mNbTris; }
|
||||
PX_FORCE_INLINE const IndTri32* getTris32() const { return mTriangles32; }
|
||||
PX_FORCE_INLINE const IndTri16* getTris16() const { return mTriangles16; }
|
||||
|
||||
PX_FORCE_INLINE void setNbTriangles(PxU32 nb) { mNbTris = nb; }
|
||||
|
||||
// SourceMeshBase
|
||||
virtual PxU32 getNbPrimitives() const { return getNbTriangles(); }
|
||||
virtual void remapTopology(const PxU32* order);
|
||||
virtual void getPrimitiveBox(const PxU32 primitiveInd, physx::aos::Vec4V& minV, physx::aos::Vec4V& maxV);
|
||||
virtual void refit(const PxU32 primitiveInd, PxBounds3& refitBox);
|
||||
//~SourceMeshBase
|
||||
|
||||
PX_FORCE_INLINE void setPointers(IndTri32* tris32, IndTri16* tris16, const PxVec3* verts)
|
||||
{
|
||||
mTriangles32 = tris32;
|
||||
mTriangles16 = tris16;
|
||||
mVerts = verts;
|
||||
}
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
PX_FORCE_INLINE void getTriangle(VertexPointers& vp, PxU32 index) const
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, index, mTriangles32, mTriangles16);
|
||||
vp.Vertex[0] = mVerts + VRef0;
|
||||
vp.Vertex[1] = mVerts + VRef1;
|
||||
vp.Vertex[2] = mVerts + VRef2;
|
||||
}
|
||||
};
|
||||
|
||||
class TetrahedronSourceMesh : public SourceMeshBase
|
||||
{
|
||||
public:
|
||||
TetrahedronSourceMesh();
|
||||
virtual ~TetrahedronSourceMesh();
|
||||
// PX_SERIALIZATION
|
||||
TetrahedronSourceMesh(const PxEMPTY) : SourceMeshBase(TET_MESH) {}
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
void reset();
|
||||
void operator = (TetrahedronSourceMesh& v);
|
||||
|
||||
PxU32 mNbTetrahedrons;
|
||||
IndTetrahedron32* mTetrahedrons32;
|
||||
IndTetrahedron16* mTetrahedrons16;
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbTetrahedrons() const { return mNbTetrahedrons; }
|
||||
PX_FORCE_INLINE const IndTetrahedron32* getTetrahedrons32() const { return mTetrahedrons32; }
|
||||
PX_FORCE_INLINE const IndTetrahedron16* getTetrahedrons16() const { return mTetrahedrons16; }
|
||||
|
||||
PX_FORCE_INLINE void setNbTetrahedrons(PxU32 nb) { mNbTetrahedrons = nb; }
|
||||
|
||||
// SourceMeshBase
|
||||
virtual PxU32 getNbPrimitives() const { return getNbTetrahedrons(); }
|
||||
virtual void remapTopology(const PxU32* order);
|
||||
virtual void getPrimitiveBox(const PxU32 primitiveInd, physx::aos::Vec4V& minV, physx::aos::Vec4V& maxV);
|
||||
virtual void refit(const PxU32 primitiveInd, PxBounds3& refitBox);
|
||||
//~SourceMeshBase
|
||||
|
||||
PX_FORCE_INLINE void setPointers(IndTetrahedron32* tets32, IndTetrahedron16* tets16, const PxVec3* verts)
|
||||
{
|
||||
mTetrahedrons32 = tets32;
|
||||
mTetrahedrons16 = tets16;
|
||||
mVerts = verts;
|
||||
}
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
PX_FORCE_INLINE void getTetrahedron(TetrahedronPointers& vp, PxU32 index) const
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2, VRef3;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, VRef3, index, mTetrahedrons32, mTetrahedrons16);
|
||||
vp.Vertex[0] = mVerts + VRef0;
|
||||
vp.Vertex[1] = mVerts + VRef1;
|
||||
vp.Vertex[2] = mVerts + VRef2;
|
||||
vp.Vertex[3] = mVerts + VRef3;
|
||||
}
|
||||
};
|
||||
|
||||
struct LocalBounds
|
||||
{
|
||||
// PX_SERIALIZATION
|
||||
LocalBounds(const PxEMPTY) {}
|
||||
//~PX_SERIALIZATION
|
||||
LocalBounds() : mCenter(PxVec3(0.0f)), mExtentsMagnitude(0.0f) {}
|
||||
|
||||
PxVec3 mCenter;
|
||||
float mExtentsMagnitude;
|
||||
|
||||
PX_FORCE_INLINE void init(const PxBounds3& bounds)
|
||||
{
|
||||
mCenter = bounds.getCenter();
|
||||
// PT: TODO: compute mag first, then multiplies by 0.5f (TA34704)
|
||||
mExtentsMagnitude = bounds.getExtents().magnitude();
|
||||
}
|
||||
};
|
||||
|
||||
class QuantizedAABB
|
||||
{
|
||||
public:
|
||||
|
||||
struct Data
|
||||
{
|
||||
PxU16 mExtents; //!< Quantized extents
|
||||
PxI16 mCenter; //!< Quantized center
|
||||
};
|
||||
Data mData[3];
|
||||
};
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(QuantizedAABB)==12);
|
||||
|
||||
/////
|
||||
|
||||
#define GU_BV4_CHILD_OFFSET_SHIFT_COUNT 11
|
||||
static PX_FORCE_INLINE PxU32 getChildOffset(PxU32 data) { return data>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
|
||||
static PX_FORCE_INLINE PxU32 getChildType(PxU32 data) { return (data>>1)&3; }
|
||||
|
||||
template<class BoxType>
|
||||
struct BVDataPackedT
|
||||
{
|
||||
BoxType mAABB;
|
||||
PxU32 mData;
|
||||
|
||||
PX_FORCE_INLINE PxU32 isLeaf() const { return mData&1; }
|
||||
PX_FORCE_INLINE PxU32 getPrimitive() const { return mData>>1; }
|
||||
PX_FORCE_INLINE PxU32 getChildOffset() const { return mData>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT;}
|
||||
PX_FORCE_INLINE PxU32 getChildType() const { return (mData>>1)&3; }
|
||||
PX_FORCE_INLINE PxU32 getChildData() const { return mData; }
|
||||
|
||||
PX_FORCE_INLINE void encodePNS(PxU32 code)
|
||||
{
|
||||
PX_ASSERT(code<256);
|
||||
mData |= code<<3;
|
||||
}
|
||||
PX_FORCE_INLINE PxU32 decodePNSNoShift() const { return mData; }
|
||||
};
|
||||
|
||||
typedef BVDataPackedT<QuantizedAABB> BVDataPackedQ;
|
||||
typedef BVDataPackedT<CenterExtents> BVDataPackedNQ;
|
||||
|
||||
// PT: TODO: align class to 16? (TA34704)
|
||||
class BV4Tree : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
// PX_SERIALIZATION
|
||||
BV4Tree(const PxEMPTY);
|
||||
void exportExtraData(PxSerializationContext&);
|
||||
void importExtraData(PxDeserializationContext& context);
|
||||
//~PX_SERIALIZATION
|
||||
BV4Tree();
|
||||
BV4Tree(SourceMesh* meshInterface, const PxBounds3& localBounds);
|
||||
~BV4Tree();
|
||||
|
||||
bool refit(PxBounds3& globalBounds, float epsilon);
|
||||
|
||||
bool load(PxInputStream& stream, bool mismatch);
|
||||
|
||||
void reset();
|
||||
void operator = (BV4Tree& v);
|
||||
|
||||
bool init(SourceMeshBase* meshInterface, const PxBounds3& localBounds);
|
||||
void release();
|
||||
|
||||
SourceMeshBase* mMeshInterface;
|
||||
|
||||
LocalBounds mLocalBounds;
|
||||
|
||||
PxU32 mNbNodes;
|
||||
void* mNodes; // PT: BVDataPacked / BVDataSwizzled
|
||||
PxU32 mInitData;
|
||||
// PT: the dequantization coeffs are only used for quantized trees
|
||||
PxVec3 mCenterOrMinCoeff; // PT: dequantization coeff, either for Center or Min (depending on AABB format)
|
||||
PxVec3 mExtentsOrMaxCoeff; // PT: dequantization coeff, either for Extents or Max (depending on AABB format)
|
||||
bool mUserAllocated; // PT: please keep these 4 bytes right after mCenterOrMinCoeff/mExtentsOrMaxCoeff for safe V4 loading
|
||||
bool mQuantized; // PT: true for quantized trees
|
||||
bool mIsEdgeSet; // PT: equivalent to RTree::IS_EDGE_SET
|
||||
bool mPadding;
|
||||
};
|
||||
|
||||
} // namespace Gu
|
||||
}
|
||||
|
||||
#endif // GU_BV4_H
|
||||
1859
engine/third_party/physx/source/geomutils/src/mesh/GuBV4Build.cpp
vendored
Normal file
1859
engine/third_party/physx/source/geomutils/src/mesh/GuBV4Build.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
123
engine/third_party/physx/source/geomutils/src/mesh/GuBV4Build.h
vendored
Normal file
123
engine/third_party/physx/source/geomutils/src/mesh/GuBV4Build.h
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_BUILD_H
|
||||
#define GU_BV4_BUILD_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "GuBV4Settings.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class BV4Tree;
|
||||
class SourceMeshBase;
|
||||
|
||||
// PT: TODO: refactor with SQ version (TA34704)
|
||||
class AABBTreeNode : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE AABBTreeNode() : mPos(0), mNodePrimitives(NULL), mNbPrimitives(0)
|
||||
#ifdef GU_BV4_FILL_GAPS
|
||||
, mNextSplit(0)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
PX_FORCE_INLINE ~AABBTreeNode()
|
||||
{
|
||||
mPos = 0;
|
||||
mNodePrimitives = NULL; // This was just a shortcut to the global list => no release
|
||||
mNbPrimitives = 0;
|
||||
}
|
||||
// Data access
|
||||
PX_FORCE_INLINE const PxBounds3& getAABB() const { return mBV; }
|
||||
|
||||
PX_FORCE_INLINE const AABBTreeNode* getPos() const { return reinterpret_cast<const AABBTreeNode*>(mPos); }
|
||||
PX_FORCE_INLINE const AABBTreeNode* getNeg() const { const AABBTreeNode* P = getPos(); return P ? P+1 : NULL; }
|
||||
|
||||
PX_FORCE_INLINE bool isLeaf() const { return !getPos(); }
|
||||
|
||||
PxBounds3 mBV; // Global bounding-volume enclosing all the node-related primitives
|
||||
size_t mPos; // "Positive" & "Negative" children
|
||||
|
||||
// Data access
|
||||
PX_FORCE_INLINE const PxU32* getPrimitives() const { return mNodePrimitives; }
|
||||
PX_FORCE_INLINE PxU32 getNbPrimitives() const { return mNbPrimitives; }
|
||||
|
||||
PxU32* mNodePrimitives; //!< Node-related primitives (shortcut to a position in mIndices below)
|
||||
PxU32 mNbPrimitives; //!< Number of primitives for this node
|
||||
#ifdef GU_BV4_FILL_GAPS
|
||||
PxU32 mNextSplit;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef bool (*WalkingCallback) (const AABBTreeNode* current, PxU32 depth, void* userData);
|
||||
typedef bool (*WalkingDistanceCallback) (const AABBTreeNode* current, void* userData);
|
||||
|
||||
enum BV4_BuildStrategy
|
||||
{
|
||||
BV4_SPLATTER_POINTS,
|
||||
BV4_SPLATTER_POINTS_SPLIT_GEOM_CENTER,
|
||||
BV4_SAH
|
||||
};
|
||||
|
||||
// PT: TODO: refactor with SQ version (TA34704)
|
||||
class BV4_AABBTree : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
BV4_AABBTree();
|
||||
~BV4_AABBTree();
|
||||
|
||||
bool buildFromMesh(SourceMeshBase& mesh, PxU32 limit, BV4_BuildStrategy strategy=BV4_SPLATTER_POINTS);
|
||||
void release();
|
||||
|
||||
PX_FORCE_INLINE const PxU32* getIndices() const { return mIndices; } //!< Catch the indices
|
||||
PX_FORCE_INLINE PxU32 getNbNodes() const { return mTotalNbNodes; } //!< Catch the number of nodes
|
||||
|
||||
PX_FORCE_INLINE const PxU32* getPrimitives() const { return mPool->mNodePrimitives; }
|
||||
PX_FORCE_INLINE PxU32 getNbPrimitives() const { return mPool->mNbPrimitives; }
|
||||
PX_FORCE_INLINE const AABBTreeNode* getNodes() const { return mPool; }
|
||||
PX_FORCE_INLINE const PxBounds3& getBV() const { return mPool->mBV; }
|
||||
|
||||
PxU32 walk(WalkingCallback callback, void* userData) const;
|
||||
PxU32 walkDistance(WalkingCallback callback, WalkingDistanceCallback distancCallback, void* userData) const;
|
||||
private:
|
||||
PxU32* mIndices; //!< Indices in the app list. Indices are reorganized during build (permutation).
|
||||
AABBTreeNode* mPool; //!< Linear pool of nodes for complete trees. Null otherwise. [Opcode 1.3]
|
||||
PxU32 mTotalNbNodes; //!< Number of nodes in the tree.
|
||||
};
|
||||
|
||||
bool BuildBV4Ex(BV4Tree& tree, SourceMeshBase& mesh, float epsilon, PxU32 nbPrimitivePerLeaf, bool quantized, BV4_BuildStrategy strategy=BV4_SPLATTER_POINTS);
|
||||
|
||||
} // namespace Gu
|
||||
}
|
||||
|
||||
#endif // GU_BV4_BUILD_H
|
||||
66
engine/third_party/physx/source/geomutils/src/mesh/GuBV4Settings.h
vendored
Normal file
66
engine/third_party/physx/source/geomutils/src/mesh/GuBV4Settings.h
vendored
Normal 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_BV4_SETTINGS_H
|
||||
#define GU_BV4_SETTINGS_H
|
||||
|
||||
// PT: "BV4" ported from "Opcode 2.0". Available compile-time options are:
|
||||
#define GU_BV4_STACK_SIZE 256 // Default size of local stacks for non-recursive traversals.
|
||||
#define GU_BV4_PRECOMPUTED_NODE_SORT // Use node sorting or not. This should probably always be enabled.
|
||||
// #define GU_BV4_QUANTIZED_TREE // Use AABB quantization/compression or not.
|
||||
#define GU_BV4_USE_SLABS // Use swizzled data format or not. Swizzled = faster raycasts, but slower overlaps & larger trees.
|
||||
// #define GU_BV4_COMPILE_NON_QUANTIZED_TREE //
|
||||
#define GU_BV4_FILL_GAPS
|
||||
|
||||
//#define PROFILE_MESH_COOKING
|
||||
#ifdef PROFILE_MESH_COOKING
|
||||
#include <intrin.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct LocalProfileZone
|
||||
{
|
||||
LocalProfileZone(const char* name)
|
||||
{
|
||||
mName = name;
|
||||
mTime = __rdtsc();
|
||||
}
|
||||
~LocalProfileZone()
|
||||
{
|
||||
mTime = __rdtsc() - mTime;
|
||||
printf("%s: %d\n", mName, unsigned int(mTime/1024));
|
||||
}
|
||||
|
||||
const char* mName;
|
||||
unsigned long long mTime;
|
||||
};
|
||||
#define GU_PROFILE_ZONE(name) LocalProfileZone zone(name);
|
||||
#else
|
||||
#define GU_PROFILE_ZONE(name)
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_SETTINGS_H
|
||||
110
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_AABBAABBSweepTest.h
vendored
Normal file
110
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_AABBAABBSweepTest.h
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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_BV4_AABB_AABB_SWEEP_TEST_H
|
||||
#define GU_BV4_AABB_AABB_SWEEP_TEST_H
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
PX_FORCE_INLINE PxIntBool BV4_SegmentAABBOverlap(const PxVec3& center, const PxVec3& extents, const PxVec3& extents2, const RayParams* PX_RESTRICT params)
|
||||
{
|
||||
const Vec4V fdirV = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V extentsV = V4Add(V4LoadU(&extents.x), V4LoadU(&extents2.x));
|
||||
const Vec4V DV = V4Sub(V4LoadA_Safe(¶ms->mData2_PaddedAligned.x), V4LoadU(¢er.x));
|
||||
const Vec4V absDV = V4Abs(DV);
|
||||
const BoolV resDV = V4IsGrtr(absDV, V4Add(extentsV, fdirV));
|
||||
const PxU32 test = BGetBitMask(resDV);
|
||||
if(test&7)
|
||||
return 0;
|
||||
|
||||
if(1)
|
||||
{
|
||||
const Vec4V dataZYX_V = V4LoadA_Safe(¶ms->mData_PaddedAligned.x);
|
||||
const Vec4V dataXZY_V = V4Perm<1, 2, 0, 3>(dataZYX_V);
|
||||
const Vec4V DXZY_V = V4Perm<1, 2, 0, 3>(DV);
|
||||
const Vec4V fV = V4Sub(V4Mul(dataZYX_V, DXZY_V), V4Mul(dataXZY_V, DV));
|
||||
|
||||
const Vec4V fdirZYX_V = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V fdirXZY_V = V4Perm<1, 2, 0, 3>(fdirZYX_V);
|
||||
const Vec4V extentsXZY_V = V4Perm<1, 2, 0, 3>(extentsV);
|
||||
// PT: TODO: use V4MulAdd here (TA34704)
|
||||
const Vec4V fg = V4Add(V4Mul(extentsV, fdirXZY_V), V4Mul(extentsXZY_V, fdirZYX_V));
|
||||
|
||||
const Vec4V absfV = V4Abs(fV);
|
||||
const BoolV resAbsfV = V4IsGrtr(absfV, fg);
|
||||
const PxU32 test2 = BGetBitMask(resAbsfV);
|
||||
if(test2&7)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
template<class T>
|
||||
PX_FORCE_INLINE PxIntBool BV4_SegmentAABBOverlap(const T* PX_RESTRICT node, const PxVec3& extents2, const RayParams* PX_RESTRICT params)
|
||||
{
|
||||
const VecI32V testV = I4LoadA((PxI32*)node->mAABB.mData);
|
||||
const VecI32V qextentsV = VecI32V_And(testV, I4Load(0x0000ffff));
|
||||
const VecI32V qcenterV = VecI32V_RightShift(testV, 16);
|
||||
const Vec4V centerV0 = V4Mul(Vec4V_From_VecI32V(qcenterV), V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x));
|
||||
const Vec4V extentsV0 = V4Mul(Vec4V_From_VecI32V(qextentsV), V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x));
|
||||
|
||||
const Vec4V fdirV = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V extentsV = V4Add(extentsV0, V4LoadU(&extents2.x));
|
||||
const Vec4V DV = V4Sub(V4LoadA_Safe(¶ms->mData2_PaddedAligned.x), centerV0);
|
||||
const Vec4V absDV = V4Abs(DV);
|
||||
const BoolV res = V4IsGrtr(absDV, V4Add(extentsV, fdirV));
|
||||
const PxU32 test = BGetBitMask(res);
|
||||
if(test&7)
|
||||
return 0;
|
||||
|
||||
if(1)
|
||||
{
|
||||
const Vec4V dataZYX_V = V4LoadA_Safe(¶ms->mData_PaddedAligned.x);
|
||||
const Vec4V dataXZY_V = V4Perm<1, 2, 0, 3>(dataZYX_V);
|
||||
const Vec4V DXZY_V = V4Perm<1, 2, 0, 3>(DV);
|
||||
|
||||
const Vec4V fV = V4Sub(V4Mul(dataZYX_V, DXZY_V), V4Mul(dataXZY_V, DV));
|
||||
|
||||
const Vec4V fdirZYX_V = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V fdirXZY_V = V4Perm<1, 2, 0, 3>(fdirZYX_V);
|
||||
const Vec4V extentsXZY_V = V4Perm<1, 2, 0, 3>(extentsV);
|
||||
// PT: TODO: use V4MulAdd here (TA34704)
|
||||
const Vec4V fg = V4Add(V4Mul(extentsV, fdirXZY_V), V4Mul(extentsXZY_V, fdirZYX_V));
|
||||
|
||||
const Vec4V absfV = V4Abs(fV);
|
||||
const BoolV res2 = V4IsGrtr(absfV, fg);
|
||||
const PxU32 test2 = BGetBitMask(res2);
|
||||
if(test2&7)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_AABB_AABB_SWEEP_TEST_H
|
||||
36
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_AABBSweep.cpp
vendored
Normal file
36
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_AABBSweep.cpp
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
// 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 "GuBV4.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#define SWEEP_AABB_IMPL
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
#include "GuBV4_BoxSweep_Internal.h"
|
||||
198
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxBoxOverlapTest.h
vendored
Normal file
198
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxBoxOverlapTest.h
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
// 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_BV4_BOX_BOX_OVERLAP_TEST_H
|
||||
#define GU_BV4_BOX_BOX_OVERLAP_TEST_H
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
PX_FORCE_INLINE PxIntBool BV4_BoxBoxOverlap(const PxVec3& extents, const PxVec3& center, const OBBTestParams* PX_RESTRICT params)
|
||||
{
|
||||
const Vec4V extentsV = V4LoadU(&extents.x);
|
||||
|
||||
const Vec4V TV = V4Sub(V4LoadA_Safe(¶ms->mTBoxToModel_PaddedAligned.x), V4LoadU(¢er.x));
|
||||
{
|
||||
const Vec4V absTV = V4Abs(TV);
|
||||
const BoolV resTV = V4IsGrtr(absTV, V4Add(extentsV, V4LoadA_Safe(¶ms->mBB_PaddedAligned.x)));
|
||||
const PxU32 test = BGetBitMask(resTV);
|
||||
if(test&7)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vec4V tV;
|
||||
{
|
||||
const Vec4V T_YZX_V = V4Perm<1, 2, 0, 3>(TV);
|
||||
const Vec4V T_ZXY_V = V4Perm<2, 0, 1, 3>(TV);
|
||||
|
||||
tV = V4Mul(TV, V4LoadA_Safe(¶ms->mPreca0_PaddedAligned.x));
|
||||
tV = V4Add(tV, V4Mul(T_YZX_V, V4LoadA_Safe(¶ms->mPreca1_PaddedAligned.x)));
|
||||
tV = V4Add(tV, V4Mul(T_ZXY_V, V4LoadA_Safe(¶ms->mPreca2_PaddedAligned.x)));
|
||||
}
|
||||
|
||||
Vec4V t2V;
|
||||
{
|
||||
const Vec4V extents_YZX_V = V4Perm<1, 2, 0, 3>(extentsV);
|
||||
const Vec4V extents_ZXY_V = V4Perm<2, 0, 1, 3>(extentsV);
|
||||
|
||||
t2V = V4Mul(extentsV, V4LoadA_Safe(¶ms->mPreca0b_PaddedAligned.x));
|
||||
t2V = V4Add(t2V, V4Mul(extents_YZX_V, V4LoadA_Safe(¶ms->mPreca1b_PaddedAligned.x)));
|
||||
t2V = V4Add(t2V, V4Mul(extents_ZXY_V, V4LoadA_Safe(¶ms->mPreca2b_PaddedAligned.x)));
|
||||
t2V = V4Add(t2V, V4LoadA_Safe(¶ms->mBoxExtents_PaddedAligned.x));
|
||||
}
|
||||
|
||||
{
|
||||
const Vec4V abstV = V4Abs(tV);
|
||||
const BoolV resB = V4IsGrtr(abstV, t2V);
|
||||
const PxU32 test = BGetBitMask(resB);
|
||||
if(test&7)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
template<class T>
|
||||
PX_FORCE_INLINE PxIntBool BV4_BoxBoxOverlap(const T* PX_RESTRICT node, const OBBTestParams* PX_RESTRICT params)
|
||||
{
|
||||
// A.B. enable new version only for intel non simd path
|
||||
#if PX_INTEL_FAMILY && !defined(PX_SIMD_DISABLED)
|
||||
// #define NEW_VERSION
|
||||
#endif
|
||||
#ifdef NEW_VERSION
|
||||
SSE_CONST4(maskV, 0x7fffffff);
|
||||
SSE_CONST4(maskQV, 0x0000ffff);
|
||||
#endif
|
||||
|
||||
#ifdef NEW_VERSION
|
||||
Vec4V centerV = V4LoadA((float*)node->mAABB.mData);
|
||||
__m128 extentsV = _mm_castsi128_ps(_mm_and_si128(_mm_castps_si128(centerV), SSE_CONST(maskQV)));
|
||||
extentsV = V4Mul(_mm_cvtepi32_ps(_mm_castps_si128(extentsV)), V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x));
|
||||
centerV = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(centerV), 16));
|
||||
centerV = V4Mul(_mm_cvtepi32_ps(_mm_castps_si128(centerV)), V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x));
|
||||
#else
|
||||
const VecI32V centerVI = I4LoadA((PxI32*)node->mAABB.mData);
|
||||
const VecI32V extentsVI = VecI32V_And(centerVI, I4Load(0x0000ffff));
|
||||
const Vec4V extentsV = V4Mul(Vec4V_From_VecI32V(extentsVI), V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x));
|
||||
const VecI32V centerVShift = VecI32V_RightShift(centerVI, 16);
|
||||
const Vec4V centerV = V4Mul(Vec4V_From_VecI32V(centerVShift), V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x));
|
||||
#endif
|
||||
|
||||
const Vec4V TV = V4Sub(V4LoadA_Safe(¶ms->mTBoxToModel_PaddedAligned.x), centerV);
|
||||
{
|
||||
#ifdef NEW_VERSION
|
||||
const __m128 absTV = _mm_and_ps(TV, SSE_CONSTF(maskV));
|
||||
#else
|
||||
const Vec4V absTV = V4Abs(TV);
|
||||
#endif
|
||||
const BoolV resTV = V4IsGrtr(absTV, V4Add(extentsV, V4LoadA_Safe(¶ms->mBB_PaddedAligned.x)));
|
||||
const PxU32 test = BGetBitMask(resTV);
|
||||
if(test&7)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vec4V tV;
|
||||
{
|
||||
const Vec4V T_YZX_V = V4Perm<1, 2, 0, 3>(TV);
|
||||
const Vec4V T_ZXY_V = V4Perm<2, 0, 1, 3>(TV);
|
||||
|
||||
tV = V4Mul(TV, V4LoadA_Safe(¶ms->mPreca0_PaddedAligned.x));
|
||||
tV = V4Add(tV, V4Mul(T_YZX_V, V4LoadA_Safe(¶ms->mPreca1_PaddedAligned.x)));
|
||||
tV = V4Add(tV, V4Mul(T_ZXY_V, V4LoadA_Safe(¶ms->mPreca2_PaddedAligned.x)));
|
||||
}
|
||||
|
||||
Vec4V t2V;
|
||||
{
|
||||
const Vec4V extents_YZX_V = V4Perm<1, 2, 0, 3>(extentsV);
|
||||
const Vec4V extents_ZXY_V = V4Perm<2, 0, 1, 3>(extentsV);
|
||||
|
||||
t2V = V4Mul(extentsV, V4LoadA_Safe(¶ms->mPreca0b_PaddedAligned.x));
|
||||
t2V = V4Add(t2V, V4Mul(extents_YZX_V, V4LoadA_Safe(¶ms->mPreca1b_PaddedAligned.x)));
|
||||
t2V = V4Add(t2V, V4Mul(extents_ZXY_V, V4LoadA_Safe(¶ms->mPreca2b_PaddedAligned.x)));
|
||||
t2V = V4Add(t2V, V4LoadA_Safe(¶ms->mBoxExtents_PaddedAligned.x));
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef NEW_VERSION
|
||||
const __m128 abstV = _mm_and_ps(tV, SSE_CONSTF(maskV));
|
||||
#else
|
||||
const Vec4V abstV = V4Abs(tV);
|
||||
#endif
|
||||
const BoolV resB = V4IsGrtr(abstV, t2V);
|
||||
const PxU32 test = BGetBitMask(resB);
|
||||
if(test&7)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif // GU_BV4_QUANTIZED_TREE
|
||||
#endif // GU_BV4_USE_SLABS
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
PX_FORCE_INLINE PxIntBool BV4_BoxBoxOverlap(const Vec4V boxCenter, const Vec4V extentsV, const OBBTestParams* PX_RESTRICT params)
|
||||
{
|
||||
const Vec4V TV = V4Sub(V4LoadA_Safe(¶ms->mTBoxToModel_PaddedAligned.x), boxCenter);
|
||||
{
|
||||
const Vec4V absTV = V4Abs(TV);
|
||||
const BoolV res = V4IsGrtr(absTV, V4Add(extentsV, V4LoadA_Safe(¶ms->mBB_PaddedAligned.x)));
|
||||
const PxU32 test = BGetBitMask(res);
|
||||
if(test&7)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Vec4V tV;
|
||||
{
|
||||
const Vec4V T_YZX_V = V4Perm<1, 2, 0, 3>(TV);
|
||||
const Vec4V T_ZXY_V = V4Perm<2, 0, 1, 3>(TV);
|
||||
|
||||
tV = V4Mul(TV, V4LoadA_Safe(¶ms->mPreca0_PaddedAligned.x));
|
||||
tV = V4Add(tV, V4Mul(T_YZX_V, V4LoadA_Safe(¶ms->mPreca1_PaddedAligned.x)));
|
||||
tV = V4Add(tV, V4Mul(T_ZXY_V, V4LoadA_Safe(¶ms->mPreca2_PaddedAligned.x)));
|
||||
}
|
||||
|
||||
Vec4V t2V;
|
||||
{
|
||||
const Vec4V extents_YZX_V = V4Perm<1, 2, 0, 3>(extentsV);
|
||||
const Vec4V extents_ZXY_V = V4Perm<2, 0, 1, 3>(extentsV);
|
||||
|
||||
t2V = V4Mul(extentsV, V4LoadA_Safe(¶ms->mPreca0b_PaddedAligned.x));
|
||||
t2V = V4Add(t2V, V4Mul(extents_YZX_V, V4LoadA_Safe(¶ms->mPreca1b_PaddedAligned.x)));
|
||||
t2V = V4Add(t2V, V4Mul(extents_ZXY_V, V4LoadA_Safe(¶ms->mPreca2b_PaddedAligned.x)));
|
||||
t2V = V4Add(t2V, V4LoadA_Safe(¶ms->mBoxExtents_PaddedAligned.x));
|
||||
}
|
||||
|
||||
{
|
||||
const Vec4V abstV = V4Abs(tV);
|
||||
const BoolV resB = V4IsGrtr(abstV, t2V);
|
||||
const PxU32 test = BGetBitMask(resB);
|
||||
if(test&7)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif // GU_BV4_USE_SLABS
|
||||
|
||||
#endif // GU_BV4_BOX_BOX_OVERLAP_TEST_H
|
||||
532
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxOverlap.cpp
vendored
Normal file
532
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxOverlap.cpp
vendored
Normal file
@@ -0,0 +1,532 @@
|
||||
// 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 "GuBV4.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
using namespace aos;
|
||||
|
||||
#include "GuInternal.h"
|
||||
#include "GuDistancePointSegment.h"
|
||||
#include "GuIntersectionCapsuleTriangle.h"
|
||||
#include "GuBV4_BoxOverlap_Internal.h"
|
||||
#include "GuBV4_BoxBoxOverlapTest.h"
|
||||
|
||||
// Box overlap any
|
||||
|
||||
struct OBBParams : OBBTestParams
|
||||
{
|
||||
const IndTri32* PX_RESTRICT mTris32;
|
||||
const IndTri16* PX_RESTRICT mTris16;
|
||||
const PxVec3* PX_RESTRICT mVerts;
|
||||
|
||||
PxMat33 mRModelToBox_Padded; //!< Rotation from model space to obb space
|
||||
PxVec3p mTModelToBox_Padded; //!< Translation from model space to obb space
|
||||
};
|
||||
|
||||
struct OBBTetParams : OBBTestParams
|
||||
{
|
||||
const IndTetrahedron32* PX_RESTRICT mTets32;
|
||||
const IndTetrahedron16* PX_RESTRICT mTets16;
|
||||
const PxVec3* PX_RESTRICT mVerts;
|
||||
|
||||
PxMat33 mRModelToBox_Padded; //!< Rotation from model space to obb space
|
||||
PxVec3p mTModelToBox_Padded; //!< Translation from model space to obb space
|
||||
};
|
||||
|
||||
// PT: TODO: this used to be inlined so we lost some perf by moving to PhysX's version. Revisit. (TA34704)
|
||||
PxIntBool intersectTriangleBoxBV4(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2,
|
||||
const PxMat33& rotModelToBox, const PxVec3& transModelToBox, const PxVec3& extents);
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_BoxOverlapAny
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const OBBParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
if(intersectTriangleBoxBV4(params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
return 1;
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<class ParamsT, class SourceMeshT>
|
||||
static PX_FORCE_INLINE void setupBoxParams(ParamsT* PX_RESTRICT params, const Box& localBox, const BV4Tree* PX_RESTRICT tree, const SourceMeshT* PX_RESTRICT mesh)
|
||||
{
|
||||
invertBoxMatrix(params->mRModelToBox_Padded, params->mTModelToBox_Padded, localBox);
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
|
||||
|
||||
params->setupFullBoxBoxData(localBox.center, localBox.extents, &localBox.rot);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
#endif
|
||||
#include "GuBV4_ProcessStreamNoOrder_OBBOBB.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_SwizzledNoOrder.h"
|
||||
#endif
|
||||
|
||||
#define GU_BV4_PROCESS_STREAM_NO_ORDER
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
PxIntBool BV4_OverlapBoxAny(const Box& box, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
Box localBox;
|
||||
computeLocalBox(localBox, box, worldm_Aligned);
|
||||
|
||||
OBBParams Params;
|
||||
setupBoxParams(&Params, localBox, &tree, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
return processStreamNoOrder<LeafFunction_BoxOverlapAny>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbPrimitives();
|
||||
PX_ASSERT(nbTris<16);
|
||||
return LeafFunction_BoxOverlapAny::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Box overlap all
|
||||
|
||||
struct OBBParamsAll : OBBParams
|
||||
{
|
||||
PxU32 mNbHits;
|
||||
PxU32 mMaxNbHits;
|
||||
PxU32* mHits;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_BoxOverlapAll
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(OBBParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
if(intersectTriangleBoxBV4(params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
{
|
||||
OBBParamsAll* ParamsAll = static_cast<OBBParamsAll*>(params);
|
||||
if(ParamsAll->mNbHits==ParamsAll->mMaxNbHits)
|
||||
return 1;
|
||||
ParamsAll->mHits[ParamsAll->mNbHits] = primIndex;
|
||||
ParamsAll->mNbHits++;
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
PxU32 BV4_OverlapBoxAll(const Box& box, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxU32* results, PxU32 size, bool& overflow)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
Box localBox;
|
||||
computeLocalBox(localBox, box, worldm_Aligned);
|
||||
|
||||
OBBParamsAll Params;
|
||||
Params.mNbHits = 0;
|
||||
Params.mMaxNbHits = size;
|
||||
Params.mHits = results;
|
||||
setupBoxParams(&Params, localBox, &tree, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
overflow = processStreamNoOrder<LeafFunction_BoxOverlapAll>(tree, &Params)!=0;
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbPrimitives();
|
||||
PX_ASSERT(nbTris<16);
|
||||
overflow = LeafFunction_BoxOverlapAll::doLeafTest(&Params, nbTris)!=0;
|
||||
}
|
||||
return Params.mNbHits;
|
||||
}
|
||||
|
||||
// Box overlap - callback version
|
||||
|
||||
struct OBBParamsCB : OBBParams
|
||||
{
|
||||
MeshOverlapCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
struct OBBTetParamsCB : OBBTetParams
|
||||
{
|
||||
TetMeshOverlapCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_BoxOverlapCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const OBBParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
if (intersectTriangleBoxBV4(params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
{
|
||||
const PxU32 vrefs[3] = { VRef0, VRef1, VRef2 };
|
||||
if ((params->mCallback)(params->mUserData, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const OBBTetParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2, VRef3;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, VRef3, primIndex, params->mTets32, params->mTets16);
|
||||
|
||||
if (intersectTriangleBoxBV4(params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
{
|
||||
const PxU32 vrefs[4] = { VRef0, VRef1, VRef2, VRef3};
|
||||
if ((params->mCallback)(params->mUserData, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mVerts[VRef3], primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (intersectTriangleBoxBV4(params->mVerts[VRef0], params->mVerts[VRef3], params->mVerts[VRef1], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
{
|
||||
const PxU32 vrefs[4] = { VRef0, VRef1, VRef2, VRef3 };
|
||||
if ((params->mCallback)(params->mUserData, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mVerts[VRef3], primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (intersectTriangleBoxBV4(params->mVerts[VRef1], params->mVerts[VRef3], params->mVerts[VRef2], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
{
|
||||
const PxU32 vrefs[4] = { VRef0, VRef1, VRef2, VRef3 };
|
||||
if ((params->mCallback)(params->mUserData, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mVerts[VRef3], primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (intersectTriangleBoxBV4(params->mVerts[VRef0], params->mVerts[VRef3], params->mVerts[VRef2], params->mRModelToBox_Padded, params->mTModelToBox_Padded, params->mBoxExtents_PaddedAligned))
|
||||
{
|
||||
const PxU32 vrefs[4] = { VRef0, VRef1, VRef2, VRef3 };
|
||||
if ((params->mCallback)(params->mUserData, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params->mVerts[VRef3], primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
primIndex++;
|
||||
} while (nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void BV4_OverlapBoxCB(const Box& localBox, const BV4Tree& tree, MeshOverlapCallback callback, void* userData)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
OBBParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
setupBoxParams(&Params, localBox, &tree, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
processStreamNoOrder<LeafFunction_BoxOverlapCB>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbPrimitives();
|
||||
PX_ASSERT(nbTris<16);
|
||||
LeafFunction_BoxOverlapCB::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
void BV4_OverlapBoxCB(const Box& localBox, const BV4Tree& tree, TetMeshOverlapCallback callback, void* userData)
|
||||
{
|
||||
const TetrahedronSourceMesh* PX_RESTRICT mesh = static_cast<TetrahedronSourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
OBBTetParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
setupBoxParams(&Params, localBox, &tree, mesh);
|
||||
|
||||
if (tree.mNodes)
|
||||
processStreamNoOrder<LeafFunction_BoxOverlapCB>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTetrahedrons = mesh->getNbTetrahedrons();
|
||||
PX_ASSERT(nbTetrahedrons<16);
|
||||
LeafFunction_BoxOverlapCB::doLeafTest(&Params, nbTetrahedrons);
|
||||
}
|
||||
}
|
||||
|
||||
// Capsule overlap any
|
||||
|
||||
struct CapsuleParamsAny : OBBParams
|
||||
{
|
||||
Capsule mLocalCapsule; // Capsule in mesh space
|
||||
CapsuleTriangleOverlapData mData;
|
||||
};
|
||||
|
||||
// PT: TODO: try to refactor this one with the PhysX version (TA34704)
|
||||
static bool CapsuleVsTriangle_SAT(const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const CapsuleParamsAny* PX_RESTRICT params)
|
||||
{
|
||||
// PX_ASSERT(capsule.p0!=capsule.p1);
|
||||
|
||||
{
|
||||
const PxReal d2 = distancePointSegmentSquaredInternal(params->mLocalCapsule.p0, params->mData.mCapsuleDir, p0);
|
||||
if(d2<=params->mLocalCapsule.radius*params->mLocalCapsule.radius)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const PxVec3 N = (p0 - p1).cross(p0 - p2);
|
||||
|
||||
if(!testAxis(p0, p1, p2, params->mLocalCapsule, N))
|
||||
return 0;
|
||||
|
||||
const float BDotB = params->mData.mBDotB;
|
||||
const float oneOverBDotB = params->mData.mOneOverBDotB;
|
||||
const PxVec3& capP0 = params->mLocalCapsule.p0;
|
||||
const PxVec3& capDir = params->mData.mCapsuleDir;
|
||||
|
||||
if(!testAxis(p0, p1, p2, params->mLocalCapsule, computeEdgeAxis(p0, p1 - p0, capP0, capDir, BDotB, oneOverBDotB)))
|
||||
return 0;
|
||||
|
||||
if(!testAxis(p0, p1, p2, params->mLocalCapsule, computeEdgeAxis(p1, p2 - p1, capP0, capDir, BDotB, oneOverBDotB)))
|
||||
return 0;
|
||||
|
||||
if(!testAxis(p0, p1, p2, params->mLocalCapsule, computeEdgeAxis(p2, p0 - p2, capP0, capDir, BDotB, oneOverBDotB)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PxIntBool PX_FORCE_INLINE capsuleTriangle(const CapsuleParamsAny* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
return CapsuleVsTriangle_SAT(params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_CapsuleOverlapAny
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const OBBParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(capsuleTriangle(static_cast<const CapsuleParamsAny*>(params), primIndex))
|
||||
return 1;
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
static PX_FORCE_INLINE void setupCapsuleParams(ParamsT* PX_RESTRICT params, const Capsule& capsule, const BV4Tree* PX_RESTRICT tree, const PxMat44* PX_RESTRICT worldm_Aligned, const SourceMesh* PX_RESTRICT mesh)
|
||||
{
|
||||
computeLocalCapsule(params->mLocalCapsule, capsule, worldm_Aligned);
|
||||
|
||||
params->mData.init(params->mLocalCapsule);
|
||||
|
||||
Box localBox;
|
||||
computeBoxAroundCapsule(params->mLocalCapsule, localBox);
|
||||
|
||||
setupBoxParams(params, localBox, tree, mesh);
|
||||
}
|
||||
|
||||
PxIntBool BV4_OverlapCapsuleAny(const Capsule& capsule, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
CapsuleParamsAny Params;
|
||||
setupCapsuleParams(&Params, capsule, &tree, worldm_Aligned, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
return processStreamNoOrder<LeafFunction_CapsuleOverlapAny>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
return LeafFunction_CapsuleOverlapAny::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Capsule overlap all
|
||||
|
||||
struct CapsuleParamsAll : CapsuleParamsAny
|
||||
{
|
||||
PxU32 mNbHits;
|
||||
PxU32 mMaxNbHits;
|
||||
PxU32* mHits;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_CapsuleOverlapAll
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(OBBParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
CapsuleParamsAll* ParamsAll = static_cast<CapsuleParamsAll*>(params);
|
||||
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(capsuleTriangle(ParamsAll, primIndex))
|
||||
{
|
||||
if(ParamsAll->mNbHits==ParamsAll->mMaxNbHits)
|
||||
return 1;
|
||||
ParamsAll->mHits[ParamsAll->mNbHits] = primIndex;
|
||||
ParamsAll->mNbHits++;
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PxU32 BV4_OverlapCapsuleAll(const Capsule& capsule, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxU32* results, PxU32 size, bool& overflow)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
CapsuleParamsAll Params;
|
||||
Params.mNbHits = 0;
|
||||
Params.mMaxNbHits = size;
|
||||
Params.mHits = results;
|
||||
setupCapsuleParams(&Params, capsule, &tree, worldm_Aligned, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
overflow = processStreamNoOrder<LeafFunction_CapsuleOverlapAll>(tree, &Params)!=0;
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
overflow = LeafFunction_CapsuleOverlapAll::doLeafTest(&Params, nbTris)!=0;
|
||||
}
|
||||
return Params.mNbHits;
|
||||
}
|
||||
|
||||
// Capsule overlap - callback version
|
||||
|
||||
struct CapsuleParamsCB : CapsuleParamsAny
|
||||
{
|
||||
MeshOverlapCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_CapsuleOverlapCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const CapsuleParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
if(CapsuleVsTriangle_SAT(p0, p1, p2, params))
|
||||
{
|
||||
const PxU32 vrefs[3] = { VRef0, VRef1, VRef2 };
|
||||
if((params->mCallback)(params->mUserData, p0, p1, p2, primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PT: this one is currently not used
|
||||
void BV4_OverlapCapsuleCB(const Capsule& capsule, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, MeshOverlapCallback callback, void* userData)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
CapsuleParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
setupCapsuleParams(&Params, capsule, &tree, worldm_Aligned, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
processStreamNoOrder<LeafFunction_CapsuleOverlapCB>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
LeafFunction_CapsuleOverlapCB::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
131
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxOverlap_Internal.h
vendored
Normal file
131
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxOverlap_Internal.h
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
// 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_BV4_BOX_OVERLAP_INTERNAL_H
|
||||
#define GU_BV4_BOX_OVERLAP_INTERNAL_H
|
||||
|
||||
#include "GuBV4_Common.h"
|
||||
|
||||
// PT: precompute the constant rotation data used in the OBB-OBB overlap test.
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void setupBoxBoxRotationData(ParamsT* PX_RESTRICT dst, PxMat33* PX_RESTRICT absRot, const PxMat33* PX_RESTRICT boxToModelR)
|
||||
{
|
||||
// Precompute absolute box-to-model rotation matrix
|
||||
dst->mPreca0_PaddedAligned.x = boxToModelR->column0.x;
|
||||
dst->mPreca0_PaddedAligned.y = boxToModelR->column1.y;
|
||||
dst->mPreca0_PaddedAligned.z = boxToModelR->column2.z;
|
||||
|
||||
dst->mPreca1_PaddedAligned.x = boxToModelR->column0.y;
|
||||
dst->mPreca1_PaddedAligned.y = boxToModelR->column1.z;
|
||||
dst->mPreca1_PaddedAligned.z = boxToModelR->column2.x;
|
||||
|
||||
dst->mPreca2_PaddedAligned.x = boxToModelR->column0.z;
|
||||
dst->mPreca2_PaddedAligned.y = boxToModelR->column1.x;
|
||||
dst->mPreca2_PaddedAligned.z = boxToModelR->column2.y;
|
||||
|
||||
// Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID)
|
||||
const PxReal epsilon = 1e-6f;
|
||||
// PT: TODO: it shouldn't be necessary to output both absRot and mPrecaXX_PaddedAligned
|
||||
absRot->column0.x = dst->mPreca0b_PaddedAligned.x = epsilon + fabsf(boxToModelR->column0.x);
|
||||
absRot->column0.y = dst->mPreca1b_PaddedAligned.x = epsilon + fabsf(boxToModelR->column0.y);
|
||||
absRot->column0.z = dst->mPreca2b_PaddedAligned.x = epsilon + fabsf(boxToModelR->column0.z);
|
||||
|
||||
absRot->column1.x = dst->mPreca2b_PaddedAligned.y = epsilon + fabsf(boxToModelR->column1.x);
|
||||
absRot->column1.y = dst->mPreca0b_PaddedAligned.y = epsilon + fabsf(boxToModelR->column1.y);
|
||||
absRot->column1.z = dst->mPreca1b_PaddedAligned.y = epsilon + fabsf(boxToModelR->column1.z);
|
||||
|
||||
absRot->column2.x = dst->mPreca1b_PaddedAligned.z = epsilon + fabsf(boxToModelR->column2.x);
|
||||
absRot->column2.y = dst->mPreca2b_PaddedAligned.z = epsilon + fabsf(boxToModelR->column2.y);
|
||||
absRot->column2.z = dst->mPreca0b_PaddedAligned.z = epsilon + fabsf(boxToModelR->column2.z);
|
||||
}
|
||||
|
||||
// PT: precompute the extent data used in the OBB-OBB overlap test. This is separate from setupBoxBoxRotationData(),
|
||||
// because the extents can shrink during sweep traversals (while the rotation is constant).
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void setupBoxBoxExtentData(ParamsT* PX_RESTRICT dst, const PxVec3& extents, const PxMat33* PX_RESTRICT absRot)
|
||||
{
|
||||
dst->mBoxExtents_PaddedAligned = extents;
|
||||
|
||||
const float Ex = extents.x;
|
||||
const float Ey = extents.y;
|
||||
const float Ez = extents.z;
|
||||
//dst->mBB_PaddedAligned.x = Ex*absRot->column0.x + Ey*absRot->column1.x + Ez*absRot->column2.x;
|
||||
//dst->mBB_PaddedAligned.y = Ex*absRot->column0.y + Ey*absRot->column1.y + Ez*absRot->column2.y;
|
||||
//dst->mBB_PaddedAligned.z = Ex*absRot->column0.z + Ey*absRot->column1.z + Ez*absRot->column2.z;
|
||||
// PT: the above code with absRot should be equivalent to:
|
||||
PX_ASSERT(absRot->column0.x==dst->mPreca0b_PaddedAligned.x);
|
||||
PX_ASSERT(absRot->column0.y==dst->mPreca1b_PaddedAligned.x);
|
||||
PX_ASSERT(absRot->column0.z==dst->mPreca2b_PaddedAligned.x);
|
||||
|
||||
PX_ASSERT(absRot->column1.x==dst->mPreca2b_PaddedAligned.y);
|
||||
PX_ASSERT(absRot->column1.y==dst->mPreca0b_PaddedAligned.y);
|
||||
PX_ASSERT(absRot->column1.z==dst->mPreca1b_PaddedAligned.y);
|
||||
|
||||
PX_ASSERT(absRot->column2.x==dst->mPreca1b_PaddedAligned.z);
|
||||
PX_ASSERT(absRot->column2.y==dst->mPreca2b_PaddedAligned.z);
|
||||
PX_ASSERT(absRot->column2.z==dst->mPreca0b_PaddedAligned.z);
|
||||
PX_UNUSED(absRot);
|
||||
|
||||
dst->mBB_PaddedAligned.x = Ex*dst->mPreca0b_PaddedAligned.x + Ey*dst->mPreca2b_PaddedAligned.y + Ez*dst->mPreca1b_PaddedAligned.z;
|
||||
dst->mBB_PaddedAligned.y = Ex*dst->mPreca1b_PaddedAligned.x + Ey*dst->mPreca0b_PaddedAligned.y + Ez*dst->mPreca2b_PaddedAligned.z;
|
||||
dst->mBB_PaddedAligned.z = Ex*dst->mPreca2b_PaddedAligned.x + Ey*dst->mPreca1b_PaddedAligned.y + Ez*dst->mPreca0b_PaddedAligned.z;
|
||||
}
|
||||
|
||||
struct OBBTestParams // Data needed to perform the OBB-OBB overlap test
|
||||
{
|
||||
BV4_ALIGN16(PxVec3p mCenterOrMinCoeff_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mExtentsOrMaxCoeff_PaddedAligned);
|
||||
|
||||
BV4_ALIGN16(PxVec3p mTBoxToModel_PaddedAligned); // (1) Translation from obb space to model space
|
||||
BV4_ALIGN16(PxVec3p mBB_PaddedAligned); // (2)
|
||||
BV4_ALIGN16(PxVec3p mBoxExtents_PaddedAligned); // (3)
|
||||
|
||||
BV4_ALIGN16(PxVec3p mPreca0_PaddedAligned); // (4)
|
||||
BV4_ALIGN16(PxVec3p mPreca1_PaddedAligned); //
|
||||
BV4_ALIGN16(PxVec3p mPreca2_PaddedAligned); //
|
||||
|
||||
BV4_ALIGN16(PxVec3p mPreca0b_PaddedAligned); // (5)
|
||||
BV4_ALIGN16(PxVec3p mPreca1b_PaddedAligned); //
|
||||
BV4_ALIGN16(PxVec3p mPreca2b_PaddedAligned); //
|
||||
|
||||
// PT: precompute the full data used in the OBB-OBB overlap test.
|
||||
PX_FORCE_INLINE void setupFullBoxBoxData(const PxVec3& center, const PxVec3& extents, const PxMat33* PX_RESTRICT box_to_model)
|
||||
{
|
||||
// PT: setup (1)
|
||||
mTBoxToModel_PaddedAligned = center;
|
||||
|
||||
// PT: setup (4) and (5)
|
||||
PxMat33 absRot; //!< Absolute rotation matrix
|
||||
setupBoxBoxRotationData(this, &absRot, box_to_model);
|
||||
|
||||
// PT: setup (2) and (3)
|
||||
setupBoxBoxExtentData(this, extents, &absRot);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GU_BV4_BOX_OVERLAP_INTERNAL_H
|
||||
519
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxSweep_Internal.h
vendored
Normal file
519
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxSweep_Internal.h
vendored
Normal file
@@ -0,0 +1,519 @@
|
||||
// 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 "GuSweepTriangleUtils.h"
|
||||
#include "GuSweepBoxTriangle_FeatureBased.h"
|
||||
#include "GuSweepBoxTriangle_SAT.h"
|
||||
#include "GuBV4_BoxOverlap_Internal.h"
|
||||
|
||||
// PT: for box-sweeps please refer to %SDKRoot%\InternalDocumentation\GU\Sweep strategies.ppt.
|
||||
// We use:
|
||||
// - method 3 if the box is an AABB (SWEEP_AABB_IMPL is defined)
|
||||
// - method 2 if the box is an OBB (SWEEP_AABB_IMPL is undefined)
|
||||
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
// PT: TODO: refactor structure (TA34704)
|
||||
namespace
|
||||
{
|
||||
struct RayParams
|
||||
{
|
||||
BV4_ALIGN16(PxVec3p mCenterOrMinCoeff_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mExtentsOrMaxCoeff_PaddedAligned);
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
BV4_ALIGN16(PxVec3p mData2_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mFDir_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mData_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mLocalDir_PaddedAligned);
|
||||
#endif
|
||||
BV4_ALIGN16(PxVec3p mOrigin_Padded); // PT: TODO: this one could be switched to PaddedAligned & V4LoadA (TA34704)
|
||||
};
|
||||
}
|
||||
#include "GuBV4_AABBAABBSweepTest.h"
|
||||
#else
|
||||
#include "GuBV4_BoxBoxOverlapTest.h"
|
||||
#endif
|
||||
|
||||
#include "GuBV4_BoxSweep_Params.h"
|
||||
|
||||
static PX_FORCE_INLINE Vec4V multiply3x3V(const Vec4V p, const PxMat33& mat_Padded)
|
||||
{
|
||||
const FloatV xxxV = V4GetX(p);
|
||||
const FloatV yyyV = V4GetY(p);
|
||||
const FloatV zzzV = V4GetZ(p);
|
||||
|
||||
Vec4V ResV = V4Scale(V4LoadU_Safe(&mat_Padded.column0.x), xxxV);
|
||||
ResV = V4Add(ResV, V4Scale(V4LoadU_Safe(&mat_Padded.column1.x), yyyV));
|
||||
ResV = V4Add(ResV, V4Scale(V4LoadU_Safe(&mat_Padded.column2.x), zzzV));
|
||||
|
||||
return ResV;
|
||||
}
|
||||
|
||||
// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
|
||||
static bool /*__fastcall*/ triBoxSweep(BoxSweepParams* PX_RESTRICT params, PxU32 primIndex, bool nodeSorting=true)
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
// Don't bother doing the actual sweep test if the triangle is too far away
|
||||
if(1)
|
||||
{
|
||||
const float dp0 = p0.dot(params->mLocalDir_Padded);
|
||||
const float dp1 = p1.dot(params->mLocalDir_Padded);
|
||||
const float dp2 = p2.dot(params->mLocalDir_Padded);
|
||||
|
||||
float TriMin = PxMin(dp0, dp1);
|
||||
TriMin = PxMin(TriMin, dp2);
|
||||
|
||||
if(TriMin >= params->mOffset + params->mStabbedFace.mDistance)
|
||||
return false;
|
||||
}
|
||||
|
||||
PxTrianglePadded triBoxSpace;
|
||||
const Vec4V transModelToBoxV = V4LoadU_Safe(¶ms->mTModelToBox_Padded.x);
|
||||
const Vec4V v0V = V4Add(multiply3x3V(V4LoadU_Safe(&p0.x), params->mRModelToBox_Padded), transModelToBoxV);
|
||||
V4StoreU_Safe(v0V, &triBoxSpace.verts[0].x);
|
||||
const Vec4V v1V = V4Add(multiply3x3V(V4LoadU_Safe(&p1.x), params->mRModelToBox_Padded), transModelToBoxV);
|
||||
V4StoreU_Safe(v1V, &triBoxSpace.verts[1].x);
|
||||
const Vec4V v2V = V4Add(multiply3x3V(V4LoadU_Safe(&p2.x), params->mRModelToBox_Padded), transModelToBoxV);
|
||||
V4StoreU_Safe(v2V, &triBoxSpace.verts[2].x);
|
||||
|
||||
float Dist;
|
||||
if(triBoxSweepTestBoxSpace_inlined(triBoxSpace, params->mOriginalExtents_Padded, params->mOriginalDir_Padded*params->mStabbedFace.mDistance, params->mOneOverDir_Padded, 1.0f, Dist, params->mBackfaceCulling))
|
||||
{
|
||||
// PT: TODO: these muls & divs may not be needed at all - we just pass the unit dir/inverse dir to the sweep code. Revisit. (TA34704)
|
||||
Dist *= params->mStabbedFace.mDistance;
|
||||
params->mOneOverDir_Padded = params->mOneOverOriginalDir / Dist;
|
||||
params->mStabbedFace.mDistance = Dist;
|
||||
params->mStabbedFace.mTriangleID = primIndex;
|
||||
// PT: TODO: revisit this (TA34704)
|
||||
params->mP0 = triBoxSpace.verts[0];
|
||||
params->mP1 = triBoxSpace.verts[1];
|
||||
params->mP2 = triBoxSpace.verts[2];
|
||||
// V4StoreU_Safe(v0V, ¶ms->mP0.x);
|
||||
// V4StoreU_Safe(v1V, ¶ms->mP1.x);
|
||||
// V4StoreU_Safe(v2V, ¶ms->mP2.x);
|
||||
|
||||
if(nodeSorting)
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, Dist, params->mOrigin_Padded, params->mLocalDir_PaddedAligned);
|
||||
#endif
|
||||
#else
|
||||
params->shrinkOBB(Dist);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_BoxSweepClosest
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void doLeafTest(BoxSweepParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
triBoxSweep(params, primIndex);
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
}
|
||||
};
|
||||
|
||||
class LeafFunction_BoxSweepAny
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(BoxSweepParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(triBoxSweep(params, primIndex))
|
||||
return 1;
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PT: TODO: refactor with sphere/capsule versions (TA34704)
|
||||
static PX_FORCE_INLINE bool computeImpactData(const Box& box, const PxVec3& dir, SweepHit* PX_RESTRICT hit, const BoxSweepParams* PX_RESTRICT params, bool isDoubleSided, bool meshBothSides)
|
||||
{
|
||||
if(params->mStabbedFace.mTriangleID==PX_INVALID_U32)
|
||||
return false; // We didn't touch any triangle
|
||||
|
||||
if(hit)
|
||||
{
|
||||
const float t = params->mStabbedFace.mDistance;
|
||||
hit->mTriangleID = params->mStabbedFace.mTriangleID;
|
||||
hit->mDistance = t;
|
||||
|
||||
if(t==0.0f)
|
||||
{
|
||||
hit->mPos = PxVec3(0.0f);
|
||||
hit->mNormal = -dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
// PT: TODO: revisit/optimize/use this (TA34704)
|
||||
const PxTriangle triInBoxSpace(params->mP0, params->mP1, params->mP2);
|
||||
PxHitFlags outFlags = PxHitFlag::Enum(0);
|
||||
computeBoxLocalImpact(hit->mPos, hit->mNormal, outFlags, box, params->mOriginalDir_Padded, triInBoxSpace, PxHitFlag::ePOSITION|PxHitFlag::eNORMAL, isDoubleSided, meshBothSides, t);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
static PX_FORCE_INLINE void setupBoxSweepParams(ParamsT* PX_RESTRICT params, const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree* PX_RESTRICT tree, const SourceMesh* PX_RESTRICT mesh, PxU32 flags)
|
||||
{
|
||||
params->mStabbedFace.mTriangleID = PX_INVALID_U32;
|
||||
setupParamsFlags(params, flags);
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
|
||||
|
||||
prepareSweepData(localBox, localDir, maxDist, params);
|
||||
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
params->mOrigin_Padded = localBox.center;
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
params->mLocalDir_PaddedAligned = localDir;
|
||||
setupRayData(params, maxDist, localBox.center, localDir);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
#endif
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
#include "GuBV4_ProcessStreamOrdered_SegmentAABB_Inflated.h"
|
||||
#include "GuBV4_ProcessStreamNoOrder_SegmentAABB_Inflated.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_KajiyaNoOrder.h"
|
||||
#include "GuBV4_Slabs_KajiyaOrdered.h"
|
||||
#endif
|
||||
#else
|
||||
#include "GuBV4_ProcessStreamOrdered_OBBOBB.h"
|
||||
#include "GuBV4_ProcessStreamNoOrder_OBBOBB.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_SwizzledNoOrder.h"
|
||||
#include "GuBV4_Slabs_SwizzledOrdered.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_NO_ORDER
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_ORDERED
|
||||
#else
|
||||
#define GU_BV4_PROCESS_STREAM_NO_ORDER
|
||||
#define GU_BV4_PROCESS_STREAM_ORDERED
|
||||
#endif
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
PxIntBool Sweep_AABB_BV4(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags)
|
||||
#else
|
||||
PxIntBool Sweep_OBB_BV4(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags)
|
||||
#endif
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
BoxSweepParams Params;
|
||||
setupBoxSweepParams(&Params, localBox, localDir, maxDist, &tree, mesh, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
if(Params.mEarlyExit)
|
||||
processStreamRayNoOrder<1, LeafFunction_BoxSweepAny>(tree, &Params);
|
||||
else
|
||||
processStreamRayOrdered<1, LeafFunction_BoxSweepClosest>(tree, &Params);
|
||||
#else
|
||||
if(Params.mEarlyExit)
|
||||
processStreamNoOrder<LeafFunction_BoxSweepAny>(tree, &Params);
|
||||
else
|
||||
processStreamOrdered<LeafFunction_BoxSweepClosest>(tree, &Params);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_BoxSweepAny, LeafFunction_BoxSweepClosest>(mesh->getNbTriangles(), &Params);
|
||||
|
||||
return computeImpactData(localBox, localDir, hit, &Params, (flags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (flags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// PT: box sweep callback version - currently not used
|
||||
|
||||
namespace
|
||||
{
|
||||
struct BoxSweepParamsCB : BoxSweepParams
|
||||
{
|
||||
// PT: these new members are only here to call computeImpactData during traversal :(
|
||||
// PT: TODO: most of them may not be needed
|
||||
Box mBoxCB; // Box in original space (maybe not local/mesh space)
|
||||
PxVec3 mDirCB; // Dir in original space (maybe not local/mesh space)
|
||||
const PxMat44* mWorldm_Aligned;
|
||||
PxU32 mFlags;
|
||||
|
||||
SweepUnlimitedCallback mCallback;
|
||||
void* mUserData;
|
||||
float mMaxDist;
|
||||
bool mNodeSorting;
|
||||
};
|
||||
|
||||
class LeafFunction_BoxSweepCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(BoxSweepParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(triBoxSweep(params, primIndex, params->mNodeSorting))
|
||||
{
|
||||
// PT: TODO: in this version we must compute the impact data immediately,
|
||||
// which is a bad idea in general, but I'm not sure what else I can do.
|
||||
SweepHit hit;
|
||||
const bool b = computeImpactData(params->mBoxCB, params->mDirCB, &hit, params, (params->mFlags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (params->mFlags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
PX_ASSERT(b);
|
||||
|
||||
// PT: then replicate part from BV4_BoxSweepSingle:
|
||||
if(b && params->mWorldm_Aligned)
|
||||
{
|
||||
// Move to world space
|
||||
// PT: TODO: optimize (TA34704)
|
||||
hit.mPos = params->mWorldm_Aligned->transform(hit.mPos);
|
||||
hit.mNormal = params->mWorldm_Aligned->rotate(hit.mNormal);
|
||||
}
|
||||
|
||||
reportUnlimitedCallbackHit(params, hit);
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// PT: for design decisions in this function, refer to the comments of BV4_GenericSweepCB().
|
||||
// PT: 'worldm_Aligned' is only here to move back results to world space, but input is already in local space.
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
void Sweep_AABB_BV4_CB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags, bool nodeSorting)
|
||||
#else
|
||||
void Sweep_OBB_BV4_CB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags, bool nodeSorting)
|
||||
#endif
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
BoxSweepParamsCB Params;
|
||||
Params.mBoxCB = localBox;
|
||||
Params.mDirCB = localDir;
|
||||
Params.mWorldm_Aligned = worldm_Aligned;
|
||||
Params.mFlags = flags;
|
||||
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
Params.mMaxDist = maxDist;
|
||||
Params.mNodeSorting = nodeSorting;
|
||||
setupBoxSweepParams(&Params, localBox, localDir, maxDist, &tree, mesh, flags);
|
||||
|
||||
PX_ASSERT(!Params.mEarlyExit);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(nodeSorting)
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
processStreamRayOrdered<1, LeafFunction_BoxSweepCB>(tree, &Params);
|
||||
#else
|
||||
processStreamOrdered<LeafFunction_BoxSweepCB>(tree, &Params);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
processStreamRayNoOrder<1, LeafFunction_BoxSweepCB>(tree, &Params);
|
||||
#else
|
||||
processStreamNoOrder<LeafFunction_BoxSweepCB>(tree, &Params);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_BoxSweepCB, LeafFunction_BoxSweepCB>(mesh->getNbTriangles(), &Params);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// New callback-based box sweeps. Reuses code above, allow early exits. Some init code may be done in vain
|
||||
// since the leaf tests are not performed (we don't do box-sweeps-vs-tri since the box is only a BV around
|
||||
// the actual shape, say a convex)
|
||||
|
||||
namespace
|
||||
{
|
||||
struct GenericSweepParamsCB : BoxSweepParams
|
||||
{
|
||||
MeshSweepCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
class LeafFunction_BoxSweepClosestCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void doLeafTest(GenericSweepParamsCB* PX_RESTRICT params, PxU32 prim_index)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(prim_index);
|
||||
do
|
||||
{
|
||||
// PT: in the regular version we'd do a box-vs-triangle sweep test here
|
||||
// Instead we just grab the triangle and send it to the callback
|
||||
//
|
||||
// This can be used for regular "closest hit" sweeps, when the scale is not identity or
|
||||
// when the box is just around a more complex shape (e.g. convex). In this case we want
|
||||
// the calling code to compute a convex-triangle distance, and then we want to shrink
|
||||
// the ray/box while doing an ordered traversal.
|
||||
//
|
||||
// For "sweep all" or "sweep any" purposes we want to either report all hits or early exit
|
||||
// as soon as we find one. There is no need for shrinking or ordered traversals here.
|
||||
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, prim_index, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
// Don't bother doing the actual sweep test if the triangle is too far away
|
||||
const float dp0 = p0.dot(params->mLocalDir_Padded);
|
||||
const float dp1 = p1.dot(params->mLocalDir_Padded);
|
||||
const float dp2 = p2.dot(params->mLocalDir_Padded);
|
||||
|
||||
float TriMin = PxMin(dp0, dp1);
|
||||
TriMin = PxMin(TriMin, dp2);
|
||||
|
||||
if(TriMin < params->mOffset + params->mStabbedFace.mDistance)
|
||||
{
|
||||
// const PxU32 vrefs[3] = { VRef0, VRef1, VRef2 };
|
||||
float Dist = params->mStabbedFace.mDistance;
|
||||
if((params->mCallback)(params->mUserData, p0, p1, p2, prim_index, /*vrefs,*/ Dist))
|
||||
return; // PT: TODO: we return here but the ordered path doesn't really support early exits (TA34704)
|
||||
|
||||
if(Dist<params->mStabbedFace.mDistance)
|
||||
{
|
||||
params->mStabbedFace.mDistance = Dist;
|
||||
params->mStabbedFace.mTriangleID = prim_index;
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, Dist, params->mOrigin_Padded, params->mLocalDir_PaddedAligned);
|
||||
#endif
|
||||
#else
|
||||
params->shrinkOBB(Dist);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
prim_index++;
|
||||
}while(nbToGo--);
|
||||
}
|
||||
};
|
||||
|
||||
class LeafFunction_BoxSweepAnyCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(GenericSweepParamsCB* PX_RESTRICT params, PxU32 prim_index)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(prim_index);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, prim_index, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
{
|
||||
// const PxU32 vrefs[3] = { VRef0, VRef1, VRef2 };
|
||||
float Dist = params->mStabbedFace.mDistance;
|
||||
if((params->mCallback)(params->mUserData, p0, p1, p2, prim_index, /*vrefs,*/ Dist))
|
||||
return 1;
|
||||
}
|
||||
|
||||
prim_index++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
void GenericSweep_AABB_CB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, MeshSweepCallback callback, void* userData, PxU32 flags)
|
||||
#else
|
||||
void GenericSweep_OBB_CB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, MeshSweepCallback callback, void* userData, PxU32 flags)
|
||||
#endif
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
GenericSweepParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
setupBoxSweepParams(&Params, localBox, localDir, maxDist, &tree, mesh, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
if(Params.mEarlyExit)
|
||||
processStreamRayNoOrder<1, LeafFunction_BoxSweepAnyCB>(tree, &Params);
|
||||
else
|
||||
processStreamRayOrdered<1, LeafFunction_BoxSweepClosestCB>(tree, &Params);
|
||||
#else
|
||||
if(Params.mEarlyExit)
|
||||
processStreamNoOrder<LeafFunction_BoxSweepAnyCB>(tree, &Params);
|
||||
else
|
||||
processStreamOrdered<LeafFunction_BoxSweepClosestCB>(tree, &Params);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_BoxSweepAnyCB, LeafFunction_BoxSweepClosestCB>(mesh->getNbTriangles(), &Params);
|
||||
}
|
||||
210
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxSweep_Params.h
vendored
Normal file
210
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_BoxSweep_Params.h
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
// 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.
|
||||
|
||||
// This is used by the box-sweep & capsule-sweep code
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(disable: 4505) // unreferenced local function has been removed
|
||||
#endif
|
||||
|
||||
#include "foundation/PxBasicTemplates.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
struct BoxSweepParams : RayParams
|
||||
#else
|
||||
struct BoxSweepParams : OBBTestParams
|
||||
#endif
|
||||
{
|
||||
const IndTri32* PX_RESTRICT mTris32;
|
||||
const IndTri16* PX_RESTRICT mTris16;
|
||||
const PxVec3* PX_RESTRICT mVerts;
|
||||
|
||||
#ifndef SWEEP_AABB_IMPL
|
||||
Box mLocalBox;
|
||||
#endif
|
||||
PxVec3 mLocalDir_Padded;
|
||||
RaycastHitInternal mStabbedFace;
|
||||
|
||||
PxU32 mBackfaceCulling;
|
||||
PxU32 mEarlyExit;
|
||||
|
||||
PxVec3 mP0, mP1, mP2;
|
||||
PxVec3 mBestTriNormal;
|
||||
|
||||
float mOffset;
|
||||
PxVec3 mProj;
|
||||
PxVec3 mDP;
|
||||
|
||||
#ifndef SWEEP_AABB_IMPL
|
||||
PxMat33 mAbsRot; //!< Absolute rotation matrix
|
||||
#endif
|
||||
|
||||
PxMat33 mRModelToBox_Padded; //!< Rotation from model space to obb space
|
||||
PxVec3 mTModelToBox_Padded; //!< Translation from model space to obb space
|
||||
PxVec3 mOriginalExtents_Padded;
|
||||
PxVec3 mOriginalDir_Padded;
|
||||
PxVec3 mOneOverDir_Padded;
|
||||
PxVec3 mOneOverOriginalDir;
|
||||
|
||||
#ifndef SWEEP_AABB_IMPL
|
||||
PX_FORCE_INLINE void shrinkOBB(float d)
|
||||
{
|
||||
const PxVec3 BoxExtents = mDP + d * mProj;
|
||||
mTBoxToModel_PaddedAligned = mLocalBox.center + mLocalDir_Padded*d*0.5f;
|
||||
|
||||
setupBoxBoxExtentData(this, BoxExtents, &mAbsRot);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
// PT: TODO: check asm again in PhysX version, compare to original (TA34704)
|
||||
static void prepareSweepData(const Box& box, const PxVec3& dir, float maxDist, BoxSweepParams* PX_RESTRICT params)
|
||||
{
|
||||
invertBoxMatrix(params->mRModelToBox_Padded, params->mTModelToBox_Padded, box);
|
||||
|
||||
params->mOriginalExtents_Padded = box.extents;
|
||||
|
||||
const PxVec3 OriginalDir = params->mRModelToBox_Padded.transform(dir);
|
||||
params->mOriginalDir_Padded = OriginalDir;
|
||||
|
||||
const PxVec3 OneOverOriginalDir(OriginalDir.x!=0.0f ? 1.0f/OriginalDir.x : 0.0f,
|
||||
OriginalDir.y!=0.0f ? 1.0f/OriginalDir.y : 0.0f,
|
||||
OriginalDir.z!=0.0f ? 1.0f/OriginalDir.z : 0.0f);
|
||||
|
||||
params->mOneOverOriginalDir = OneOverOriginalDir;
|
||||
params->mOneOverDir_Padded = OneOverOriginalDir / maxDist;
|
||||
|
||||
{
|
||||
const Box& LocalBox = box;
|
||||
const PxVec3& LocalDir = dir;
|
||||
|
||||
params->mLocalDir_Padded = LocalDir;
|
||||
params->mStabbedFace.mDistance = maxDist;
|
||||
#ifndef SWEEP_AABB_IMPL
|
||||
params->mLocalBox = LocalBox; // PT: TODO: check asm for operator=
|
||||
#endif
|
||||
|
||||
PxMat33 boxToModelR;
|
||||
|
||||
// Original code:
|
||||
// OBB::CreateOBB(LocalBox, LocalDir, 0.5f)
|
||||
{
|
||||
PxVec3 R1, R2;
|
||||
{
|
||||
float dd[3];
|
||||
dd[0] = fabsf(LocalBox.rot.column0.dot(LocalDir));
|
||||
dd[1] = fabsf(LocalBox.rot.column1.dot(LocalDir));
|
||||
dd[2] = fabsf(LocalBox.rot.column2.dot(LocalDir));
|
||||
float dmax = dd[0];
|
||||
PxU32 ax0=1;
|
||||
PxU32 ax1=2;
|
||||
if(dd[1]>dmax)
|
||||
{
|
||||
dmax=dd[1];
|
||||
ax0=0;
|
||||
ax1=2;
|
||||
}
|
||||
if(dd[2]>dmax)
|
||||
{
|
||||
dmax=dd[2];
|
||||
ax0=0;
|
||||
ax1=1;
|
||||
}
|
||||
if(dd[ax1]<dd[ax0])
|
||||
PxSwap(ax0, ax1);
|
||||
|
||||
R1 = LocalBox.rot[ax0];
|
||||
R1 -= R1.dot(LocalDir)*LocalDir; // Project to plane whose normal is dir
|
||||
R1.normalize();
|
||||
R2 = LocalDir.cross(R1);
|
||||
}
|
||||
// Original code:
|
||||
// mRot = params->mRBoxToModel
|
||||
boxToModelR.column0 = LocalDir;
|
||||
boxToModelR.column1 = R1;
|
||||
boxToModelR.column2 = R2;
|
||||
|
||||
// Original code:
|
||||
// float Offset[3];
|
||||
// 0.5f comes from the Offset[r]*0.5f, doesn't mean 'd' is 0.5f
|
||||
params->mProj.x = 0.5f;
|
||||
params->mProj.y = LocalDir.dot(R1)*0.5f;
|
||||
params->mProj.z = LocalDir.dot(R2)*0.5f;
|
||||
|
||||
// Original code:
|
||||
//mExtents[r] = Offset[r]*0.5f + fabsf(box.mRot[0]|R)*box.mExtents.x + fabsf(box.mRot[1]|R)*box.mExtents.y + fabsf(box.mRot[2]|R)*box.mExtents.z;
|
||||
// => we store the first part of the computation, minus 'Offset[r]*0.5f'
|
||||
for(PxU32 r=0;r<3;r++)
|
||||
{
|
||||
const PxVec3& R = boxToModelR[r];
|
||||
params->mDP[r] = fabsf(LocalBox.rot.column0.dot(R)*LocalBox.extents.x)
|
||||
+ fabsf(LocalBox.rot.column1.dot(R)*LocalBox.extents.y)
|
||||
+ fabsf(LocalBox.rot.column2.dot(R)*LocalBox.extents.z);
|
||||
}
|
||||
// In the original code, both mCenter & mExtents depend on 'd', and thus we will need to recompute these two members.
|
||||
//
|
||||
// For mExtents we have:
|
||||
//
|
||||
// float Offset[3];
|
||||
// Offset[0] = d;
|
||||
// Offset[1] = d*(dir|R1);
|
||||
// Offset[2] = d*(dir|R2);
|
||||
//
|
||||
// mExtents[r] = Offset[r]*0.5f + fabsf(box.mRot[0]|R)*box.mExtents.x + fabsf(box.mRot[1]|R)*box.mExtents.y + fabsf(box.mRot[2]|R)*box.mExtents.z;
|
||||
// <=> mExtents[r] = Offset[r]*0.5f + Params.mDP[r]; We precompute the second part that doesn't depend on d, stored in mDP
|
||||
// <=> mExtents[r] = Params.mProj[r]*d + Params.mDP[r]; We extract d from the first part, store what is left in mProj
|
||||
//
|
||||
// Thus in shrinkOBB the code needed to update the extents is just:
|
||||
// mBoxExtents = mDP + d * mProj;
|
||||
//
|
||||
// For mCenter we have:
|
||||
//
|
||||
// mCenter = box.mCenter + dir*d*0.5f;
|
||||
//
|
||||
// So we simply use this formula directly, with the new d. Result is stored in 'mTBoxToModel'
|
||||
/*
|
||||
PX_FORCE_INLINE void shrinkOBB(float d)
|
||||
{
|
||||
mBoxExtents = mDP + d * mProj;
|
||||
mTBoxToModel = mLocalBox.mCenter + mLocalDir*d*0.5f;
|
||||
*/
|
||||
}
|
||||
|
||||
// This one is for culling tris, unrelated to CreateOBB
|
||||
params->mOffset = params->mDP.x + LocalBox.center.dot(LocalDir);
|
||||
|
||||
#ifndef SWEEP_AABB_IMPL
|
||||
setupBoxBoxRotationData(params, ¶ms->mAbsRot, &boxToModelR);
|
||||
|
||||
params->shrinkOBB(maxDist);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
171
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_CapsuleSweep.cpp
vendored
Normal file
171
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_CapsuleSweep.cpp
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "GuBV4.h"
|
||||
#include "GuSweepSphereTriangle.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
|
||||
#include "GuInternal.h"
|
||||
|
||||
#include "GuBV4_BoxOverlap_Internal.h"
|
||||
#include "GuBV4_BoxSweep_Params.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CapsuleSweepParams : BoxSweepParams
|
||||
{
|
||||
Capsule mLocalCapsule;
|
||||
PxVec3 mCapsuleCenter;
|
||||
PxVec3 mExtrusionDir;
|
||||
float mBestAlignmentValue;
|
||||
float mBestDistance;
|
||||
float mMaxDist;
|
||||
|
||||
// PX_FORCE_INLINE float getReportDistance() const { return mStabbedFace.mDistance; }
|
||||
PX_FORCE_INLINE float getReportDistance() const { return mBestDistance; }
|
||||
};
|
||||
}
|
||||
|
||||
#include "GuBV4_CapsuleSweep_Internal.h"
|
||||
#include "GuBV4_BoxBoxOverlapTest.h"
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
#endif
|
||||
#include "GuBV4_ProcessStreamOrdered_OBBOBB.h"
|
||||
#include "GuBV4_ProcessStreamNoOrder_OBBOBB.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_SwizzledNoOrder.h"
|
||||
#include "GuBV4_Slabs_SwizzledOrdered.h"
|
||||
#endif
|
||||
|
||||
#define GU_BV4_PROCESS_STREAM_NO_ORDER
|
||||
#define GU_BV4_PROCESS_STREAM_ORDERED
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
PxIntBool BV4_CapsuleSweepSingle(const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
CapsuleSweepParams Params;
|
||||
setupCapsuleParams(&Params, capsule, dir, maxDist, &tree, mesh, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(Params.mEarlyExit)
|
||||
processStreamNoOrder<LeafFunction_CapsuleSweepAny>(tree, &Params);
|
||||
else
|
||||
processStreamOrdered<LeafFunction_CapsuleSweepClosest>(tree, &Params);
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_CapsuleSweepAny, LeafFunction_CapsuleSweepClosest>(mesh->getNbTriangles(), &Params);
|
||||
|
||||
return computeImpactDataT<ImpactFunctionCapsule>(capsule, dir, hit, &Params, NULL, (flags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (flags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
}
|
||||
|
||||
// PT: capsule sweep callback version - currently not used
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CapsuleSweepParamsCB : CapsuleSweepParams
|
||||
{
|
||||
// PT: these new members are only here to call computeImpactDataT during traversal :(
|
||||
// PT: TODO: most of them may not be needed
|
||||
// PT: TODO: for example mCapsuleCB probably dup of mLocalCapsule
|
||||
Capsule mCapsuleCB; // Capsule in original space (maybe not local/mesh space)
|
||||
PxVec3 mDirCB; // Dir in original space (maybe not local/mesh space)
|
||||
const PxMat44* mWorldm_Aligned;
|
||||
PxU32 mFlags;
|
||||
|
||||
SweepUnlimitedCallback mCallback;
|
||||
void* mUserData;
|
||||
bool mNodeSorting;
|
||||
};
|
||||
|
||||
class LeafFunction_CapsuleSweepCB
|
||||
{
|
||||
public:
|
||||
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(CapsuleSweepParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(triCapsuleSweep(params, primIndex, params->mNodeSorting))
|
||||
{
|
||||
// PT: TODO: in this version we must compute the impact data immediately,
|
||||
// which is a bad idea in general, but I'm not sure what else I can do.
|
||||
SweepHit hit;
|
||||
const bool b = computeImpactDataT<ImpactFunctionCapsule>(params->mCapsuleCB, params->mDirCB, &hit, params, params->mWorldm_Aligned, (params->mFlags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (params->mFlags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
PX_ASSERT(b);
|
||||
PX_UNUSED(b);
|
||||
|
||||
reportUnlimitedCallbackHit(params, hit);
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PT: for design decisions in this function, refer to the comments of BV4_GenericSweepCB().
|
||||
void BV4_CapsuleSweepCB(const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags, bool nodeSorting)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
CapsuleSweepParamsCB Params;
|
||||
Params.mCapsuleCB = capsule;
|
||||
Params.mDirCB = dir;
|
||||
Params.mWorldm_Aligned = worldm_Aligned;
|
||||
Params.mFlags = flags;
|
||||
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
Params.mMaxDist = maxDist;
|
||||
Params.mNodeSorting = nodeSorting;
|
||||
setupCapsuleParams(&Params, capsule, dir, maxDist, &tree, mesh, flags);
|
||||
|
||||
PX_ASSERT(!Params.mEarlyExit);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(nodeSorting)
|
||||
processStreamOrdered<LeafFunction_CapsuleSweepCB>(tree, &Params);
|
||||
else
|
||||
processStreamNoOrder<LeafFunction_CapsuleSweepCB>(tree, &Params);
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_CapsuleSweepCB, LeafFunction_CapsuleSweepCB>(mesh->getNbTriangles(), &Params);
|
||||
}
|
||||
|
||||
111
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_CapsuleSweepAA.cpp
vendored
Normal file
111
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_CapsuleSweepAA.cpp
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// 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 "GuBV4.h"
|
||||
#include "GuSweepSphereTriangle.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
|
||||
#include "GuBV4_Common.h"
|
||||
#include "GuInternal.h"
|
||||
|
||||
#define SWEEP_AABB_IMPL
|
||||
|
||||
// PT: TODO: refactor structure (TA34704)
|
||||
namespace
|
||||
{
|
||||
struct RayParams
|
||||
{
|
||||
BV4_ALIGN16(PxVec3p mCenterOrMinCoeff_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mExtentsOrMaxCoeff_PaddedAligned);
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
BV4_ALIGN16(PxVec3p mData2_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mFDir_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mData_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mLocalDir_PaddedAligned);
|
||||
#endif
|
||||
BV4_ALIGN16(PxVec3p mOrigin_Padded); // PT: TODO: this one could be switched to PaddedAligned & V4LoadA (TA34704)
|
||||
};
|
||||
}
|
||||
#include "GuBV4_BoxSweep_Params.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct CapsuleSweepParams : BoxSweepParams
|
||||
{
|
||||
Capsule mLocalCapsule;
|
||||
PxVec3 mCapsuleCenter;
|
||||
PxVec3 mExtrusionDir;
|
||||
float mBestAlignmentValue;
|
||||
float mBestDistance;
|
||||
float mMaxDist;
|
||||
|
||||
// PX_FORCE_INLINE float getReportDistance() const { return mStabbedFace.mDistance; }
|
||||
PX_FORCE_INLINE float getReportDistance() const { return mBestDistance; }
|
||||
};
|
||||
}
|
||||
|
||||
#include "GuBV4_CapsuleSweep_Internal.h"
|
||||
#include "GuBV4_AABBAABBSweepTest.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
#endif
|
||||
#include "GuBV4_ProcessStreamOrdered_SegmentAABB_Inflated.h"
|
||||
#include "GuBV4_ProcessStreamNoOrder_SegmentAABB_Inflated.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_KajiyaNoOrder.h"
|
||||
#include "GuBV4_Slabs_KajiyaOrdered.h"
|
||||
#endif
|
||||
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_NO_ORDER
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_ORDERED
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
PxIntBool BV4_CapsuleSweepSingleAA(const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
CapsuleSweepParams Params;
|
||||
setupCapsuleParams(&Params, capsule, dir, maxDist, &tree, mesh, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(Params.mEarlyExit)
|
||||
processStreamRayNoOrder<1, LeafFunction_CapsuleSweepAny>(tree, &Params);
|
||||
else
|
||||
processStreamRayOrdered<1, LeafFunction_CapsuleSweepClosest>(tree, &Params);
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_CapsuleSweepAny, LeafFunction_CapsuleSweepClosest>(mesh->getNbPrimitives(), &Params);
|
||||
|
||||
return computeImpactDataT<ImpactFunctionCapsule>(capsule, dir, hit, &Params, NULL, (flags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (flags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
}
|
||||
|
||||
442
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_CapsuleSweep_Internal.h
vendored
Normal file
442
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_CapsuleSweep_Internal.h
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
// 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_BV4_CAPSULE_SWEEP_INTERNAL_H
|
||||
#define GU_BV4_CAPSULE_SWEEP_INTERNAL_H
|
||||
|
||||
// PT: for capsule-sweeps please refer to %SDKRoot%\InternalDocumentation\GU\Sweep strategies.ppt.
|
||||
// We use:
|
||||
// - method 3 if the capsule is axis-aligned (SWEEP_AABB_IMPL is defined)
|
||||
// - method 2 otherwise (SWEEP_AABB_IMPL is undefined)
|
||||
|
||||
// PT: TODO: get rid of that one
|
||||
static PX_FORCE_INLINE bool sweepSphereVSTriangle( const PxVec3& center, const float radius,
|
||||
const PxVec3* PX_RESTRICT triVerts, const PxVec3& triUnitNormal,
|
||||
const PxVec3& unitDir,
|
||||
float& curT, bool& directHit)
|
||||
{
|
||||
float currentDistance;
|
||||
if(!sweepSphereVSTri(triVerts, triUnitNormal, center, radius, unitDir, currentDistance, directHit, true))
|
||||
return false;
|
||||
|
||||
// PT: using ">" or ">=" is enough to block the CCT or not in the DE5967 visual test. Change to ">=" if a repro is needed.
|
||||
if(currentDistance > curT + GU_EPSILON_SAME_DISTANCE * PxMax(1.0f, curT))
|
||||
return false;
|
||||
curT = currentDistance;
|
||||
return true;
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE bool sweepSphereVSQuad( const PxVec3& center, const float radius,
|
||||
const PxVec3* PX_RESTRICT quadVerts, const PxVec3& quadUnitNormal,
|
||||
const PxVec3& unitDir,
|
||||
float& curT)
|
||||
{
|
||||
float currentDistance;
|
||||
if(!sweepSphereVSQuad(quadVerts, quadUnitNormal, center, radius, unitDir, currentDistance))
|
||||
return false;
|
||||
|
||||
// PT: using ">" or ">=" is enough to block the CCT or not in the DE5967 visual test. Change to ">=" if a repro is needed.
|
||||
if(currentDistance > curT + GU_EPSILON_SAME_DISTANCE * PxMax(1.0f, curT))
|
||||
return false;
|
||||
curT = currentDistance;
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
|
||||
static bool /*__fastcall*/ testTri( const CapsuleSweepParams* PX_RESTRICT params, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& N,
|
||||
const PxVec3& unitDir, const float capsuleRadius, const float dpc0, float& curT, bool& status)
|
||||
{
|
||||
// PT: TODO: check the assembly here (TA34704)
|
||||
PxVec3 currentTri[3];
|
||||
// PT: TODO: optimize this copy (TA34704)
|
||||
currentTri[0] = p0;
|
||||
currentTri[1] = p1;
|
||||
currentTri[2] = p2;
|
||||
|
||||
// PT: beware, culling is only ok on the sphere I think
|
||||
if(rejectTriangle(params->mCapsuleCenter, unitDir, curT, capsuleRadius, currentTri, dpc0))
|
||||
return false;
|
||||
|
||||
float magnitude = N.magnitude();
|
||||
if(magnitude==0.0f)
|
||||
return false;
|
||||
|
||||
PxVec3 triNormal = N / magnitude;
|
||||
|
||||
bool DirectHit;
|
||||
if(sweepSphereVSTriangle(params->mCapsuleCenter, capsuleRadius, currentTri, triNormal, unitDir, curT, DirectHit))
|
||||
{
|
||||
status = true;
|
||||
}
|
||||
return DirectHit;
|
||||
}
|
||||
|
||||
// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
|
||||
static void /*__fastcall*/ testQuad(const CapsuleSweepParams* PX_RESTRICT params, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3, const PxVec3& N,
|
||||
const PxVec3& unitDir, const float capsuleRadius, const float dpc0, float& curT, bool& status)
|
||||
{
|
||||
// PT: TODO: optimize this copy (TA34704)
|
||||
PxVec3 currentQuad[4];
|
||||
currentQuad[0] = p0;
|
||||
currentQuad[1] = p1;
|
||||
currentQuad[2] = p2;
|
||||
currentQuad[3] = p3;
|
||||
|
||||
// PT: beware, culling is only ok on the sphere I think
|
||||
if(rejectQuad(params->mCapsuleCenter, unitDir, curT, capsuleRadius, currentQuad, dpc0))
|
||||
return;
|
||||
|
||||
float magnitude = N.magnitude();
|
||||
if(magnitude==0.0f)
|
||||
return;
|
||||
|
||||
PxVec3 triNormal = N / magnitude;
|
||||
|
||||
if(sweepSphereVSQuad(params->mCapsuleCenter, capsuleRadius, currentQuad, triNormal, unitDir, curT))
|
||||
{
|
||||
status = true;
|
||||
}
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE float Set2(const PxVec3& p0, const PxVec3& n, const PxVec3& p)
|
||||
{
|
||||
return (p-p0).dot(n);
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE bool sweepCapsuleVsTriangle(const CapsuleSweepParams* PX_RESTRICT params, const PxTriangle& triangle, float& t, bool isDoubleSided, PxVec3& normal)
|
||||
{
|
||||
const PxVec3& unitDir = params->mLocalDir_Padded;
|
||||
|
||||
// Create triangle normal
|
||||
PxVec3 denormalizedNormal = (triangle.verts[0] - triangle.verts[1]).cross(triangle.verts[0] - triangle.verts[2]);
|
||||
|
||||
normal = denormalizedNormal;
|
||||
|
||||
// Backface culling
|
||||
const bool culled = denormalizedNormal.dot(unitDir) > 0.0f;
|
||||
if(culled)
|
||||
{
|
||||
if(!isDoubleSided)
|
||||
return false;
|
||||
|
||||
denormalizedNormal = -denormalizedNormal;
|
||||
}
|
||||
|
||||
const float capsuleRadius = params->mLocalCapsule.radius;
|
||||
float curT = params->mStabbedFace.mDistance;// + GU_EPSILON_SAME_DISTANCE*20.0f;
|
||||
const float dpc0 = params->mCapsuleCenter.dot(unitDir);
|
||||
|
||||
bool status = false;
|
||||
|
||||
// Extrude mesh on the fly
|
||||
const PxVec3 p0 = triangle.verts[0] - params->mExtrusionDir;
|
||||
const PxVec3 p1 = triangle.verts[1+culled] - params->mExtrusionDir;
|
||||
const PxVec3 p2 = triangle.verts[2-culled] - params->mExtrusionDir;
|
||||
|
||||
const PxVec3 p0b = triangle.verts[0] + params->mExtrusionDir;
|
||||
const PxVec3 p1b = triangle.verts[1+culled] + params->mExtrusionDir;
|
||||
const PxVec3 p2b = triangle.verts[2-culled] + params->mExtrusionDir;
|
||||
|
||||
const float extrusionSign = denormalizedNormal.dot(params->mExtrusionDir);
|
||||
|
||||
const PxVec3 p2b_p1b = p2b - p1b;
|
||||
const PxVec3 p0b_p1b = p0b - p1b;
|
||||
const PxVec3 p2b_p2 = 2.0f * params->mExtrusionDir;
|
||||
const PxVec3 p1_p1b = -p2b_p2;
|
||||
|
||||
const PxVec3 N1 = p2b_p1b.cross(p0b_p1b);
|
||||
const float dp0 = Set2(p0b, N1, params->mCapsuleCenter);
|
||||
|
||||
const PxVec3 N2 = (p2 - p1).cross(p0 - p1);
|
||||
const float dp1 = -Set2(p0, N2, params->mCapsuleCenter);
|
||||
|
||||
bool directHit;
|
||||
if(extrusionSign >= 0.0f)
|
||||
directHit = testTri(params, p0b, p1b, p2b, N1, unitDir, capsuleRadius, dpc0, curT, status);
|
||||
else
|
||||
directHit = testTri(params, p0, p1, p2, N2, unitDir, capsuleRadius, dpc0, curT, status);
|
||||
|
||||
const PxVec3 N3 = p2b_p1b.cross(p1_p1b);
|
||||
const float dp2 = -Set2(p1, N3, params->mCapsuleCenter);
|
||||
if(!directHit)
|
||||
{
|
||||
const float dp = N3.dot(unitDir);
|
||||
if(dp*extrusionSign>=0.0f)
|
||||
testQuad(params, p1, p1b, p2, p2b, N3, unitDir, capsuleRadius, dpc0, curT, status);
|
||||
}
|
||||
|
||||
const PxVec3 N5 = p2b_p2.cross(p0 - p2);
|
||||
const float dp3 = -Set2(p0, N5, params->mCapsuleCenter);
|
||||
if(!directHit)
|
||||
{
|
||||
const float dp = N5.dot(unitDir);
|
||||
if(dp*extrusionSign>=0.0f)
|
||||
testQuad(params, p2, p2b, p0, p0b, N5, unitDir, capsuleRadius, dpc0, curT, status);
|
||||
}
|
||||
|
||||
const PxVec3 N7 = p1_p1b.cross(p0b_p1b);
|
||||
const float dp4 = -Set2(p0b, N7, params->mCapsuleCenter);
|
||||
if(!directHit)
|
||||
{
|
||||
const float dp = N7.dot(unitDir);
|
||||
if(dp*extrusionSign>=0.0f)
|
||||
testQuad(params, p0, p0b, p1, p1b, N7, unitDir, capsuleRadius, dpc0, curT, status);
|
||||
}
|
||||
|
||||
if(1)
|
||||
{
|
||||
bool originInside = true;
|
||||
if(extrusionSign<0.0f)
|
||||
{
|
||||
if(dp0<0.0f || dp1<0.0f || dp2<0.0f || dp3<0.0f || dp4<0.0f)
|
||||
originInside = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(dp0>0.0f || dp1>0.0f || dp2>0.0f || dp3>0.0f || dp4>0.0f)
|
||||
originInside = false;
|
||||
}
|
||||
if(originInside)
|
||||
{
|
||||
t = 0.0f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(!status)
|
||||
return false; // We didn't touch any triangle
|
||||
|
||||
t = curT;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
|
||||
static bool /*__fastcall*/ triCapsuleSweep(CapsuleSweepParams* PX_RESTRICT params, PxU32 primIndex, bool nodeSorting=true)
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
const PxTriangle Tri(p0, p1, p2); // PT: TODO: check calls to empty ctor/dtor here (TA34704)
|
||||
|
||||
const bool isDoubleSided = params->mBackfaceCulling==0;
|
||||
|
||||
float dist;
|
||||
PxVec3 denormalizedNormal;
|
||||
if(sweepCapsuleVsTriangle(params, Tri, dist, isDoubleSided, denormalizedNormal))
|
||||
{
|
||||
denormalizedNormal.normalize();
|
||||
const PxReal alignmentValue = computeAlignmentValue(denormalizedNormal, params->mLocalDir_Padded);
|
||||
|
||||
if(keepTriangle(dist, alignmentValue, params->mBestDistance, params->mBestAlignmentValue, params->mMaxDist))
|
||||
{
|
||||
params->mStabbedFace.mDistance = dist;
|
||||
params->mStabbedFace.mTriangleID = primIndex;
|
||||
|
||||
params->mP0 = p0;
|
||||
params->mP1 = p1;
|
||||
params->mP2 = p2;
|
||||
|
||||
params->mBestDistance = PxMin(params->mBestDistance, dist); // exact lower bound
|
||||
params->mBestAlignmentValue = alignmentValue;
|
||||
params->mBestTriNormal = denormalizedNormal;
|
||||
|
||||
if(nodeSorting)
|
||||
{
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
//setupRayData(params, dist, params->mOrigin_Padded, params->mLocalDir_PaddedAligned);
|
||||
setupRayData(params, params->mBestDistance, params->mOrigin_Padded, params->mLocalDir_PaddedAligned);
|
||||
#endif
|
||||
#else
|
||||
//params->shrinkOBB(dist);
|
||||
params->shrinkOBB(params->mBestDistance);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
///
|
||||
else if(keepTriangleBasic(dist, params->mBestDistance, params->mMaxDist))
|
||||
{
|
||||
params->mStabbedFace.mDistance = dist;
|
||||
params->mBestDistance = PxMin(params->mBestDistance, dist); // exact lower bound
|
||||
}
|
||||
///
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#include "GuDistanceSegmentTriangle.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_CapsuleSweepClosest
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void doLeafTest(CapsuleSweepParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
triCapsuleSweep(params, primIndex);
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
}
|
||||
};
|
||||
|
||||
class LeafFunction_CapsuleSweepAny
|
||||
{
|
||||
public:
|
||||
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(CapsuleSweepParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(triCapsuleSweep(params, primIndex))
|
||||
return 1;
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class ImpactFunctionCapsule
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void computeImpact(PxVec3& impactPos, PxVec3& impactNormal, const Capsule& capsule, const PxVec3& dir, const PxReal t, const PxTrianglePadded& triangle)
|
||||
{
|
||||
const PxVec3 delta = dir * t;
|
||||
const PxVec3p P0 = capsule.p0 + delta;
|
||||
const PxVec3p P1 = capsule.p1 + delta;
|
||||
Vec3V pointOnSeg, pointOnTri;
|
||||
distanceSegmentTriangleSquared(
|
||||
// PT: we use PxVec3p so it is safe to V4LoadU P0 and P1
|
||||
V3LoadU_SafeReadW(P0), V3LoadU_SafeReadW(P1),
|
||||
// PT: we use PxTrianglePadded so it is safe to V4LoadU the triangle vertices
|
||||
V3LoadU_SafeReadW(triangle.verts[0]), V3LoadU_SafeReadW(triangle.verts[1]), V3LoadU_SafeReadW(triangle.verts[2]),
|
||||
pointOnSeg, pointOnTri);
|
||||
|
||||
PxVec3 localImpactPos, tmp;
|
||||
V3StoreU(pointOnTri, localImpactPos);
|
||||
V3StoreU(pointOnSeg, tmp);
|
||||
|
||||
// PT: TODO: refactor with computeSphereTriImpactData (TA34704)
|
||||
PxVec3 localImpactNormal = tmp - localImpactPos;
|
||||
const float M = localImpactNormal.magnitude();
|
||||
if(M<1e-3f)
|
||||
{
|
||||
localImpactNormal = (triangle.verts[0] - triangle.verts[1]).cross(triangle.verts[0] - triangle.verts[2]);
|
||||
localImpactNormal.normalize();
|
||||
}
|
||||
else
|
||||
localImpactNormal /= M;
|
||||
|
||||
impactPos = localImpactPos;
|
||||
impactNormal = localImpactNormal;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static void computeBoxAroundCapsule(const Capsule& capsule, Box& box, PxVec3& extrusionDir)
|
||||
{
|
||||
// Box center = center of the two capsule's endpoints
|
||||
box.center = capsule.computeCenter();
|
||||
|
||||
extrusionDir = (capsule.p0 - capsule.p1)*0.5f;
|
||||
const PxF32 d = extrusionDir.magnitude();
|
||||
|
||||
// Box extents
|
||||
box.extents.x = capsule.radius + d;
|
||||
box.extents.y = capsule.radius;
|
||||
box.extents.z = capsule.radius;
|
||||
|
||||
// Box orientation
|
||||
if(d==0.0f)
|
||||
{
|
||||
box.rot = PxMat33(PxIdentity);
|
||||
}
|
||||
else
|
||||
{
|
||||
PxVec3 dir, right, up;
|
||||
PxComputeBasisVectors(capsule.p0, capsule.p1, dir, right, up);
|
||||
box.setAxes(dir, right, up);
|
||||
}
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
static PX_FORCE_INLINE void setupCapsuleParams(ParamsT* PX_RESTRICT params, const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree* PX_RESTRICT tree, const SourceMesh* PX_RESTRICT mesh, PxU32 flags)
|
||||
{
|
||||
params->mStabbedFace.mTriangleID = PX_INVALID_U32;
|
||||
params->mBestAlignmentValue = 2.0f;
|
||||
params->mBestDistance = maxDist + GU_EPSILON_SAME_DISTANCE;
|
||||
params->mMaxDist = maxDist;
|
||||
|
||||
setupParamsFlags(params, flags);
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
|
||||
|
||||
params->mLocalCapsule = capsule;
|
||||
|
||||
Box localBox;
|
||||
computeBoxAroundCapsule(capsule, localBox, params->mExtrusionDir);
|
||||
|
||||
params->mCapsuleCenter = localBox.center;
|
||||
|
||||
const PxVec3& localDir = dir;
|
||||
|
||||
#ifdef SWEEP_AABB_IMPL
|
||||
const PxVec3& localP0 = params->mLocalCapsule.p0;
|
||||
const PxVec3& localP1 = params->mLocalCapsule.p1;
|
||||
const PxVec3 sweepOrigin = (localP0+localP1)*0.5f;
|
||||
const PxVec3 sweepExtents = PxVec3(params->mLocalCapsule.radius) + (localP0-localP1).abs()*0.5f;
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
params->mLocalDir_PaddedAligned = localDir;
|
||||
#endif
|
||||
params->mOrigin_Padded = sweepOrigin;
|
||||
|
||||
const Box aabb(sweepOrigin, sweepExtents, PxMat33(PxIdentity));
|
||||
prepareSweepData(aabb, localDir, maxDist, params); // PT: TODO: optimize this call for idt rotation (TA34704)
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, maxDist, sweepOrigin, localDir);
|
||||
#endif
|
||||
#else
|
||||
prepareSweepData(localBox, localDir, maxDist, params);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // GU_BV4_CAPSULE_SWEEP_INTERNAL_H
|
||||
457
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Common.h
vendored
Normal file
457
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Common.h
vendored
Normal file
@@ -0,0 +1,457 @@
|
||||
// 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_BV4_COMMON_H
|
||||
#define GU_BV4_COMMON_H
|
||||
|
||||
#include "foundation/PxMat44.h"
|
||||
#include "geometry/PxTriangle.h"
|
||||
#include "GuBox.h"
|
||||
#include "GuSphere.h"
|
||||
#include "GuCapsule.h"
|
||||
#include "GuBV4.h"
|
||||
|
||||
#define BV4_ALIGN16(x) PX_ALIGN_PREFIX(16) x PX_ALIGN_SUFFIX(16)
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
enum QueryModifierFlag
|
||||
{
|
||||
QUERY_MODIFIER_ANY_HIT = (1<<0),
|
||||
QUERY_MODIFIER_DOUBLE_SIDED = (1<<1),
|
||||
QUERY_MODIFIER_MESH_BOTH_SIDES = (1<<2)
|
||||
};
|
||||
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void setupParamsFlags(ParamsT* PX_RESTRICT params, PxU32 flags)
|
||||
{
|
||||
params->mBackfaceCulling = (flags & (QUERY_MODIFIER_DOUBLE_SIDED|QUERY_MODIFIER_MESH_BOTH_SIDES)) ? 0 : 1u;
|
||||
params->mEarlyExit = flags & QUERY_MODIFIER_ANY_HIT;
|
||||
}
|
||||
|
||||
enum HitCode
|
||||
{
|
||||
HIT_NONE = 0, //!< No hit
|
||||
HIT_CONTINUE = 1, //!< Hit found, but keep looking for closer one
|
||||
HIT_EXIT = 2 //!< Hit found, you can early-exit (raycast any)
|
||||
};
|
||||
|
||||
class RaycastHitInternal : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE RaycastHitInternal() {}
|
||||
PX_FORCE_INLINE ~RaycastHitInternal() {}
|
||||
|
||||
float mDistance;
|
||||
PxU32 mTriangleID;
|
||||
};
|
||||
|
||||
class SweepHit : public physx::PxUserAllocated
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE SweepHit() {}
|
||||
PX_FORCE_INLINE ~SweepHit() {}
|
||||
|
||||
PxU32 mTriangleID; //!< Index of touched face
|
||||
float mDistance; //!< Impact distance
|
||||
|
||||
PxVec3 mPos;
|
||||
PxVec3 mNormal;
|
||||
};
|
||||
|
||||
typedef HitCode (*MeshRayCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, float dist, float u, float v);
|
||||
typedef bool (*MeshOverlapCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* vertexIndices);
|
||||
typedef bool (*TetMeshOverlapCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, const PxVec3& p3, PxU32 tetIndex, const PxU32* vertexIndices);
|
||||
typedef bool (*MeshSweepCallback) (void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, /*const PxU32* vertexIndices,*/ float& dist);
|
||||
typedef bool (*SweepUnlimitedCallback) (void* userData, const SweepHit& hit);
|
||||
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void reportUnlimitedCallbackHit(ParamsT* PX_RESTRICT params, const SweepHit& hit)
|
||||
{
|
||||
// PT: we can't reuse the MeshSweepCallback here since it's designed for doing the sweep test inside the callback
|
||||
// (in the user's code) rather than inside the traversal code. So we use the SweepUnlimitedCallback instead to
|
||||
// report the already fully computed hit to users.
|
||||
// PT: TODO: this may not be very efficient, since computing the full hit is expensive. If we use this codepath
|
||||
// to implement the Epic Tweak, the resulting code will not be optimal.
|
||||
(params->mCallback)(params->mUserData, hit);
|
||||
|
||||
// PT: the existing traversal code already shrunk the ray. For real "sweep all" calls we must undo that by reseting the max dist.
|
||||
// (params->mStabbedFace.mDistance is used in computeImpactDataX code, so we need it before that point - we can't simply avoid
|
||||
// modifying this value before this point).
|
||||
if(!params->mNodeSorting)
|
||||
params->mStabbedFace.mDistance = params->mMaxDist;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void invertPRMatrix(PxMat44* PX_RESTRICT dest, const PxMat44* PX_RESTRICT src)
|
||||
{
|
||||
const float m30 = src->column3.x;
|
||||
const float m31 = src->column3.y;
|
||||
const float m32 = src->column3.z;
|
||||
|
||||
const float m00 = src->column0.x;
|
||||
const float m01 = src->column0.y;
|
||||
const float m02 = src->column0.z;
|
||||
|
||||
dest->column0.x = m00;
|
||||
dest->column1.x = m01;
|
||||
dest->column2.x = m02;
|
||||
dest->column3.x = -(m30*m00 + m31*m01 + m32*m02);
|
||||
|
||||
const float m10 = src->column1.x;
|
||||
const float m11 = src->column1.y;
|
||||
const float m12 = src->column1.z;
|
||||
|
||||
dest->column0.y = m10;
|
||||
dest->column1.y = m11;
|
||||
dest->column2.y = m12;
|
||||
dest->column3.y = -(m30*m10 + m31*m11 + m32*m12);
|
||||
|
||||
const float m20 = src->column2.x;
|
||||
const float m21 = src->column2.y;
|
||||
const float m22 = src->column2.z;
|
||||
|
||||
dest->column0.z = m20;
|
||||
dest->column1.z = m21;
|
||||
dest->column2.z = m22;
|
||||
dest->column3.z = -(m30*m20 + m31*m21 + m32*m22);
|
||||
|
||||
dest->column0.w = 0.0f;
|
||||
dest->column1.w = 0.0f;
|
||||
dest->column2.w = 0.0f;
|
||||
dest->column3.w = 1.0f;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void invertBoxMatrix(PxMat33& m, PxVec3& t, const Gu::Box& box)
|
||||
{
|
||||
const float m30 = box.center.x;
|
||||
const float m31 = box.center.y;
|
||||
const float m32 = box.center.z;
|
||||
|
||||
const float m00 = box.rot.column0.x;
|
||||
const float m01 = box.rot.column0.y;
|
||||
const float m02 = box.rot.column0.z;
|
||||
|
||||
m.column0.x = m00;
|
||||
m.column1.x = m01;
|
||||
m.column2.x = m02;
|
||||
t.x = -(m30*m00 + m31*m01 + m32*m02);
|
||||
|
||||
const float m10 = box.rot.column1.x;
|
||||
const float m11 = box.rot.column1.y;
|
||||
const float m12 = box.rot.column1.z;
|
||||
|
||||
m.column0.y = m10;
|
||||
m.column1.y = m11;
|
||||
m.column2.y = m12;
|
||||
t.y = -(m30*m10 + m31*m11 + m32*m12);
|
||||
|
||||
const float m20 = box.rot.column2.x;
|
||||
const float m21 = box.rot.column2.y;
|
||||
const float m22 = box.rot.column2.z;
|
||||
|
||||
m.column0.z = m20;
|
||||
m.column1.z = m21;
|
||||
m.column2.z = m22;
|
||||
t.z = -(m30*m20 + m31*m21 + m32*m22);
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
// PT: this class moved here to make things compile with pedantic compilers.
|
||||
|
||||
// PT: now duplicated because not easy to do otherwise
|
||||
|
||||
struct BVDataSwizzledQ : public physx::PxUserAllocated
|
||||
{
|
||||
struct Data
|
||||
{
|
||||
PxI16 mMin; //!< Quantized min
|
||||
PxI16 mMax; //!< Quantized max
|
||||
};
|
||||
|
||||
Data mX[4];
|
||||
Data mY[4];
|
||||
Data mZ[4];
|
||||
|
||||
PxU32 mData[4];
|
||||
|
||||
PX_FORCE_INLINE PxU32 isLeaf(PxU32 i) const { return mData[i]&1; }
|
||||
PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return mData[i]>>1; }
|
||||
PX_FORCE_INLINE PxU32 getChildOffset(PxU32 i) const { return mData[i]>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
|
||||
PX_FORCE_INLINE PxU32 getChildType(PxU32 i) const { return (mData[i]>>1)&3; }
|
||||
PX_FORCE_INLINE PxU32 getChildData(PxU32 i) const { return mData[i]; }
|
||||
PX_FORCE_INLINE PxU32 decodePNSNoShift(PxU32 i) const { return mData[i]; }
|
||||
};
|
||||
|
||||
struct BVDataSwizzledNQ : public physx::PxUserAllocated
|
||||
{
|
||||
float mMinX[4];
|
||||
float mMinY[4];
|
||||
float mMinZ[4];
|
||||
float mMaxX[4];
|
||||
float mMaxY[4];
|
||||
float mMaxZ[4];
|
||||
|
||||
PxU32 mData[4];
|
||||
|
||||
PX_FORCE_INLINE PxU32 isLeaf(PxU32 i) const { return mData[i]&1; }
|
||||
PX_FORCE_INLINE PxU32 getPrimitive(PxU32 i) const { return mData[i]>>1; }
|
||||
PX_FORCE_INLINE PxU32 getChildOffset(PxU32 i) const { return mData[i]>>GU_BV4_CHILD_OFFSET_SHIFT_COUNT; }
|
||||
PX_FORCE_INLINE PxU32 getChildType(PxU32 i) const { return (mData[i]>>1)&3; }
|
||||
PX_FORCE_INLINE PxU32 getChildData(PxU32 i) const { return mData[i]; }
|
||||
PX_FORCE_INLINE PxU32 decodePNSNoShift(PxU32 i) const { return mData[i]; }
|
||||
};
|
||||
|
||||
#else
|
||||
#define SSE_CONST4(name, val) static const __declspec(align(16)) PxU32 name[4] = { (val), (val), (val), (val) }
|
||||
#define SSE_CONST(name) *(const __m128i *)&name
|
||||
#define SSE_CONSTF(name) *(const __m128 *)&name
|
||||
#endif
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbPrimitives(PxU32& primIndex)
|
||||
{
|
||||
PxU32 NbToGo = (primIndex & 15)-1;
|
||||
primIndex>>=4;
|
||||
return NbToGo;
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void setupMeshPointersAndQuantizedCoeffs(ParamsT* PX_RESTRICT params, const SourceMesh* PX_RESTRICT mesh, const BV4Tree* PX_RESTRICT tree)
|
||||
{
|
||||
using namespace physx::aos;
|
||||
|
||||
params->mTris32 = mesh->getTris32();
|
||||
params->mTris16 = mesh->getTris16();
|
||||
params->mVerts = mesh->getVerts();
|
||||
|
||||
V4StoreA_Safe(V4LoadU_Safe(&tree->mCenterOrMinCoeff.x), ¶ms->mCenterOrMinCoeff_PaddedAligned.x);
|
||||
V4StoreA_Safe(V4LoadU_Safe(&tree->mExtentsOrMaxCoeff.x), ¶ms->mExtentsOrMaxCoeff_PaddedAligned.x);
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void setupMeshPointersAndQuantizedCoeffs(ParamsT* PX_RESTRICT params, const TetrahedronSourceMesh* PX_RESTRICT mesh, const BV4Tree* PX_RESTRICT tree)
|
||||
{
|
||||
params->mTets32 = mesh->getTetrahedrons32();
|
||||
params->mTets16 = mesh->getTetrahedrons16();
|
||||
params->mVerts = mesh->getVerts();
|
||||
|
||||
V4StoreA_Safe(V4LoadU_Safe(&tree->mCenterOrMinCoeff.x), ¶ms->mCenterOrMinCoeff_PaddedAligned.x);
|
||||
V4StoreA_Safe(V4LoadU_Safe(&tree->mExtentsOrMaxCoeff.x), ¶ms->mExtentsOrMaxCoeff_PaddedAligned.x);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void rotateBox(Gu::Box& dst, const PxMat44& m, const Gu::Box& src)
|
||||
{
|
||||
// The extents remain constant
|
||||
dst.extents = src.extents;
|
||||
// The center gets x-formed
|
||||
dst.center = m.transform(src.center);
|
||||
// Combine rotations
|
||||
// PT: TODO: revisit.. this is awkward... grab 3x3 part of 4x4 matrix (TA34704)
|
||||
const PxMat33 tmp( PxVec3(m.column0.x, m.column0.y, m.column0.z),
|
||||
PxVec3(m.column1.x, m.column1.y, m.column1.z),
|
||||
PxVec3(m.column2.x, m.column2.y, m.column2.z));
|
||||
dst.rot = tmp * src.rot;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxVec3 inverseRotate(const PxMat44* PX_RESTRICT src, const PxVec3& p)
|
||||
{
|
||||
const float m00 = src->column0.x;
|
||||
const float m01 = src->column0.y;
|
||||
const float m02 = src->column0.z;
|
||||
|
||||
const float m10 = src->column1.x;
|
||||
const float m11 = src->column1.y;
|
||||
const float m12 = src->column1.z;
|
||||
|
||||
const float m20 = src->column2.x;
|
||||
const float m21 = src->column2.y;
|
||||
const float m22 = src->column2.z;
|
||||
|
||||
return PxVec3( m00*p.x + m01*p.y + m02*p.z,
|
||||
m10*p.x + m11*p.y + m12*p.z,
|
||||
m20*p.x + m21*p.y + m22*p.z);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxVec3 inverseTransform(const PxMat44* PX_RESTRICT src, const PxVec3& p)
|
||||
{
|
||||
const float m30 = src->column3.x;
|
||||
const float m31 = src->column3.y;
|
||||
const float m32 = src->column3.z;
|
||||
|
||||
const float m00 = src->column0.x;
|
||||
const float m01 = src->column0.y;
|
||||
const float m02 = src->column0.z;
|
||||
|
||||
const float m10 = src->column1.x;
|
||||
const float m11 = src->column1.y;
|
||||
const float m12 = src->column1.z;
|
||||
|
||||
const float m20 = src->column2.x;
|
||||
const float m21 = src->column2.y;
|
||||
const float m22 = src->column2.z;
|
||||
|
||||
return PxVec3( m00*p.x + m01*p.y + m02*p.z -(m30*m00 + m31*m01 + m32*m02),
|
||||
m10*p.x + m11*p.y + m12*p.z -(m30*m10 + m31*m11 + m32*m12),
|
||||
m20*p.x + m21*p.y + m22*p.z -(m30*m20 + m31*m21 + m32*m22));
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void computeLocalRay(PxVec3& localDir, PxVec3& localOrigin, const PxVec3& dir, const PxVec3& origin, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
if(worldm_Aligned)
|
||||
{
|
||||
localDir = inverseRotate(worldm_Aligned, dir);
|
||||
localOrigin = inverseTransform(worldm_Aligned, origin);
|
||||
}
|
||||
else
|
||||
{
|
||||
localDir = dir;
|
||||
localOrigin = origin;
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void computeLocalSphere(float& radius2, PxVec3& local_center, const Sphere& sphere, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
radius2 = sphere.radius * sphere.radius;
|
||||
if(worldm_Aligned)
|
||||
{
|
||||
local_center = inverseTransform(worldm_Aligned, sphere.center);
|
||||
}
|
||||
else
|
||||
{
|
||||
local_center = sphere.center;
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void computeLocalCapsule(Capsule& localCapsule, const Capsule& capsule, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
localCapsule.radius = capsule.radius;
|
||||
if(worldm_Aligned)
|
||||
{
|
||||
localCapsule.p0 = inverseTransform(worldm_Aligned, capsule.p0);
|
||||
localCapsule.p1 = inverseTransform(worldm_Aligned, capsule.p1);
|
||||
}
|
||||
else
|
||||
{
|
||||
localCapsule.p0 = capsule.p0;
|
||||
localCapsule.p1 = capsule.p1;
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void computeLocalBox(Gu::Box& dst, const Gu::Box& src, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
if(worldm_Aligned)
|
||||
{
|
||||
PxMat44 invWorldM;
|
||||
invertPRMatrix(&invWorldM, worldm_Aligned);
|
||||
|
||||
rotateBox(dst, invWorldM, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst = src; // PT: TODO: check asm for operator= (TA34704)
|
||||
}
|
||||
}
|
||||
|
||||
template<class ImpactFunctionT, class ShapeT, class ParamsT>
|
||||
static PX_FORCE_INLINE bool computeImpactDataT(const ShapeT& shape, const PxVec3& dir, SweepHit* PX_RESTRICT hit, const ParamsT* PX_RESTRICT params, const PxMat44* PX_RESTRICT worldm, bool isDoubleSided, bool meshBothSides)
|
||||
{
|
||||
if(params->mStabbedFace.mTriangleID==PX_INVALID_U32)
|
||||
return false; // We didn't touch any triangle
|
||||
|
||||
if(hit)
|
||||
{
|
||||
const float t = params->getReportDistance();
|
||||
hit->mTriangleID = params->mStabbedFace.mTriangleID;
|
||||
hit->mDistance = t;
|
||||
|
||||
if(t==0.0f)
|
||||
{
|
||||
hit->mPos = PxVec3(0.0f);
|
||||
hit->mNormal = -dir;
|
||||
}
|
||||
else
|
||||
{
|
||||
// PT: TODO: we shouldn't compute impact in world space, and in fact moving this to local space is necessary if we want to reuse this for box-sweeps (TA34704)
|
||||
PxTrianglePadded WP;
|
||||
if(worldm)
|
||||
{
|
||||
WP.verts[0] = worldm->transform(params->mP0);
|
||||
WP.verts[1] = worldm->transform(params->mP1);
|
||||
WP.verts[2] = worldm->transform(params->mP2);
|
||||
}
|
||||
else
|
||||
{
|
||||
WP.verts[0] = params->mP0;
|
||||
WP.verts[1] = params->mP1;
|
||||
WP.verts[2] = params->mP2;
|
||||
}
|
||||
|
||||
PxVec3 impactNormal;
|
||||
ImpactFunctionT::computeImpact(hit->mPos, impactNormal, shape, dir, t, WP);
|
||||
|
||||
// PT: by design, returned normal is opposed to the sweep direction.
|
||||
if(shouldFlipNormal(impactNormal, meshBothSides, isDoubleSided, params->mBestTriNormal, dir))
|
||||
impactNormal = -impactNormal;
|
||||
|
||||
hit->mNormal = impactNormal;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// PT: we don't create a structure for small meshes with just a few triangles. We use brute-force tests on these.
|
||||
template<class LeafFunction_AnyT, class LeafFunction_ClosestT, class ParamsT>
|
||||
void doBruteForceTests(PxU32 nbTris, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
PX_ASSERT(nbTris<16);
|
||||
if(params->mEarlyExit)
|
||||
LeafFunction_AnyT::doLeafTest(params, nbTris);
|
||||
else
|
||||
LeafFunction_ClosestT::doLeafTest(params, nbTris);
|
||||
}
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
template<class ParamsT>
|
||||
PX_FORCE_INLINE void setupRayData(ParamsT* PX_RESTRICT params, float max_dist, const PxVec3& origin, const PxVec3& dir)
|
||||
{
|
||||
const float Half = 0.5f*max_dist;
|
||||
const FloatV HalfV = FLoad(Half);
|
||||
const Vec4V DataV = V4Scale(V4LoadU(&dir.x), HalfV);
|
||||
const Vec4V Data2V = V4Add(V4LoadU(&origin.x), DataV);
|
||||
const Vec4V FDirV = V4Abs(DataV);
|
||||
V4StoreA_Safe(DataV, ¶ms->mData_PaddedAligned.x);
|
||||
V4StoreA_Safe(Data2V, ¶ms->mData2_PaddedAligned.x);
|
||||
V4StoreA_Safe(FDirV, ¶ms->mFDir_PaddedAligned.x);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // GU_BV4_COMMON_H
|
||||
298
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Internal.h
vendored
Normal file
298
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Internal.h
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
// 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_BV4_INTERNAL_H
|
||||
#define GU_BV4_INTERNAL_H
|
||||
|
||||
#include "foundation/PxFPU.h"
|
||||
|
||||
// PT: the general structure is that there is a root "process stream" function which is the entry point for the query.
|
||||
// It then calls "process node" functions for each traversed node, except for the Slabs-based raycast versions that deal
|
||||
// with 4 nodes at a time within the "process stream" function itself. When a leaf is found, "doLeafTest" functors
|
||||
// passed to the "process stream" entry point are called.
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
// PT: Linux tries to compile templates even when they're not used so I had to wrap them all with defines to avoid build errors. Blame the only platform that does this.
|
||||
#ifdef GU_BV4_PROCESS_STREAM_NO_ORDER
|
||||
template<class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool processStreamNoOrder(const BV4Tree& tree, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
if(tree.mQuantized)
|
||||
return BV4_ProcessStreamSwizzledNoOrderQ<LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedQ*>(tree.mNodes), tree.mInitData, params);
|
||||
else
|
||||
return BV4_ProcessStreamSwizzledNoOrderNQ<LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedNQ*>(tree.mNodes), tree.mInitData, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GU_BV4_PROCESS_STREAM_ORDERED
|
||||
template<class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE void processStreamOrdered(const BV4Tree& tree, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
if(tree.mQuantized)
|
||||
BV4_ProcessStreamSwizzledOrderedQ<LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedQ*>(tree.mNodes), tree.mInitData, params);
|
||||
else
|
||||
BV4_ProcessStreamSwizzledOrderedNQ<LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedNQ*>(tree.mNodes), tree.mInitData, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GU_BV4_PROCESS_STREAM_RAY_NO_ORDER
|
||||
template<int inflateT, class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool processStreamRayNoOrder(const BV4Tree& tree, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
if(tree.mQuantized)
|
||||
return BV4_ProcessStreamKajiyaNoOrderQ<inflateT, LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedQ*>(tree.mNodes), tree.mInitData, params);
|
||||
else
|
||||
return BV4_ProcessStreamKajiyaNoOrderNQ<inflateT, LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedNQ*>(tree.mNodes), tree.mInitData, params);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef GU_BV4_PROCESS_STREAM_RAY_ORDERED
|
||||
template<int inflateT, class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE void processStreamRayOrdered(const BV4Tree& tree, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
if(tree.mQuantized)
|
||||
BV4_ProcessStreamKajiyaOrderedQ<inflateT, LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedQ*>(tree.mNodes), tree.mInitData, params);
|
||||
else
|
||||
BV4_ProcessStreamKajiyaOrderedNQ<inflateT, LeafTestT, ParamsT>(reinterpret_cast<const BVDataPackedNQ*>(tree.mNodes), tree.mInitData, params);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define processStreamNoOrder BV4_ProcessStreamNoOrder
|
||||
#define processStreamOrdered BV4_ProcessStreamOrdered2
|
||||
#define processStreamRayNoOrder(a, b) BV4_ProcessStreamNoOrder<b>
|
||||
#define processStreamRayOrdered(a, b) BV4_ProcessStreamOrdered2<b>
|
||||
#endif
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
#ifdef GU_BV4_PRECOMPUTED_NODE_SORT
|
||||
// PT: see http://www.codercorner.com/blog/?p=734
|
||||
|
||||
// PT: TODO: refactor with dup in bucket pruner (TA34704)
|
||||
PX_FORCE_INLINE PxU32 computeDirMask(const PxVec3& dir)
|
||||
{
|
||||
// XYZ
|
||||
// ---
|
||||
// --+
|
||||
// -+-
|
||||
// -++
|
||||
// +--
|
||||
// +-+
|
||||
// ++-
|
||||
// +++
|
||||
|
||||
const PxU32 X = PX_IR(dir.x)>>31;
|
||||
const PxU32 Y = PX_IR(dir.y)>>31;
|
||||
const PxU32 Z = PX_IR(dir.z)>>31;
|
||||
const PxU32 bitIndex = Z|(Y<<1)|(X<<2);
|
||||
return 1u<<bitIndex;
|
||||
}
|
||||
|
||||
// 0 0 0 PP PN NP NN 0 1 2 3
|
||||
// 0 0 1 PP PN NN NP 0 1 3 2
|
||||
// 0 1 0 PN PP NP NN 1 0 2 3
|
||||
// 0 1 1 PN PP NN NP 1 0 3 2
|
||||
// 1 0 0 NP NN PP PN 2 3 0 1
|
||||
// 1 0 1 NN NP PP PN 3 2 0 1
|
||||
// 1 1 0 NP NN PN PP 2 3 1 0
|
||||
// 1 1 1 NN NP PN PP 3 2 1 0
|
||||
static const PxU8 order[] = {
|
||||
0,1,2,3,
|
||||
0,1,3,2,
|
||||
1,0,2,3,
|
||||
1,0,3,2,
|
||||
2,3,0,1,
|
||||
3,2,0,1,
|
||||
2,3,1,0,
|
||||
3,2,1,0,
|
||||
};
|
||||
|
||||
PX_FORCE_INLINE PxU32 decodePNS(const BVDataPacked* PX_RESTRICT node, const PxU32 dirMask)
|
||||
{
|
||||
const PxU32 bit0 = (node[0].decodePNSNoShift() & dirMask) ? 1u : 0;
|
||||
const PxU32 bit1 = (node[1].decodePNSNoShift() & dirMask) ? 1u : 0;
|
||||
const PxU32 bit2 = (node[2].decodePNSNoShift() & dirMask) ? 1u : 0; //### potentially reads past the end of the stream here!
|
||||
return bit2|(bit1<<1)|(bit0<<2);
|
||||
}
|
||||
#endif // GU_BV4_PRECOMPUTED_NODE_SORT
|
||||
|
||||
#define PNS_BLOCK(i, a, b, c, d) \
|
||||
case i: \
|
||||
{ \
|
||||
if(code & (1<<a)) { stack[nb++] = node[a].getChildData(); } \
|
||||
if(code & (1<<b)) { stack[nb++] = node[b].getChildData(); } \
|
||||
if(code & (1<<c)) { stack[nb++] = node[c].getChildData(); } \
|
||||
if(code & (1<<d)) { stack[nb++] = node[d].getChildData(); } \
|
||||
}break;
|
||||
|
||||
#define PNS_BLOCK1(i, a, b, c, d) \
|
||||
case i: \
|
||||
{ \
|
||||
stack[nb] = node[a].getChildData(); nb += (code & (1<<a))?1:0; \
|
||||
stack[nb] = node[b].getChildData(); nb += (code & (1<<b))?1:0; \
|
||||
stack[nb] = node[c].getChildData(); nb += (code & (1<<c))?1:0; \
|
||||
stack[nb] = node[d].getChildData(); nb += (code & (1<<d))?1:0; \
|
||||
}break;
|
||||
|
||||
#define PNS_BLOCK2(a, b, c, d) { \
|
||||
if(code & (1<<a)) { stack[nb++] = node[a].getChildData(); } \
|
||||
if(code & (1<<b)) { stack[nb++] = node[b].getChildData(); } \
|
||||
if(code & (1<<c)) { stack[nb++] = node[c].getChildData(); } \
|
||||
if(code & (1<<d)) { stack[nb++] = node[d].getChildData(); } } \
|
||||
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamNoOrder(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(nodeType>1 && BV4_ProcessNodeNoOrder<LeafTestT, 3>(stack, nb, node, params))
|
||||
return 1;
|
||||
if(nodeType>0 && BV4_ProcessNodeNoOrder<LeafTestT, 2>(stack, nb, node, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder<LeafTestT, 1>(stack, nb, node, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder<LeafTestT, 0>(stack, nb, node, params))
|
||||
return 1;
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamOrdered(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
const PxU32 dirMask = computeDirMask(params->mLocalDir)<<3;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const PxU8* PX_RESTRICT ord = order + decodePNS(node, dirMask)*4;
|
||||
const PxU32 limit = 2 + getChildType(childData);
|
||||
|
||||
BV4_ProcessNodeOrdered<LeafTestT>(stack, nb, node, params, ord[0], limit);
|
||||
BV4_ProcessNodeOrdered<LeafTestT>(stack, nb, node, params, ord[1], limit);
|
||||
BV4_ProcessNodeOrdered<LeafTestT>(stack, nb, node, params, ord[2], limit);
|
||||
BV4_ProcessNodeOrdered<LeafTestT>(stack, nb, node, params, ord[3], limit);
|
||||
}while(Nb);
|
||||
}
|
||||
|
||||
// Alternative, experimental version using PNS
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamOrdered2(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
PxU32 code = 0;
|
||||
BV4_ProcessNodeOrdered2<LeafTestT, 0>(code, node, params);
|
||||
BV4_ProcessNodeOrdered2<LeafTestT, 1>(code, node, params);
|
||||
if(nodeType>0)
|
||||
BV4_ProcessNodeOrdered2<LeafTestT, 2>(code, node, params);
|
||||
if(nodeType>1)
|
||||
BV4_ProcessNodeOrdered2<LeafTestT, 3>(code, node, params);
|
||||
|
||||
if(code)
|
||||
{
|
||||
// PT: TODO: check which implementation is best on each platform (TA34704)
|
||||
#define FOURTH_TEST // Version avoids computing the PNS index, and also avoids all non-constant shifts. Full of branches though. Fastest on Win32.
|
||||
#ifdef FOURTH_TEST
|
||||
{
|
||||
if(node[0].decodePNSNoShift() & dirMask) // Bit2
|
||||
{
|
||||
if(node[1].decodePNSNoShift() & dirMask) // Bit1
|
||||
{
|
||||
if(node[2].decodePNSNoShift() & dirMask) // Bit0
|
||||
PNS_BLOCK2(3,2,1,0) // 7
|
||||
else
|
||||
PNS_BLOCK2(2,3,1,0) // 6
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node[2].decodePNSNoShift() & dirMask) // Bit0
|
||||
PNS_BLOCK2(3,2,0,1) // 5
|
||||
else
|
||||
PNS_BLOCK2(2,3,0,1) // 4
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node[1].decodePNSNoShift() & dirMask) // Bit1
|
||||
{
|
||||
if(node[2].decodePNSNoShift() & dirMask) // Bit0
|
||||
PNS_BLOCK2(1,0,3,2) // 3
|
||||
else
|
||||
PNS_BLOCK2(1,0,2,3) // 2
|
||||
}
|
||||
else
|
||||
{
|
||||
if(node[2].decodePNSNoShift() & dirMask) // Bit0
|
||||
PNS_BLOCK2(0,1,3,2) // 1
|
||||
else
|
||||
PNS_BLOCK2(0,1,2,3) // 0
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}while(nb);
|
||||
}
|
||||
#endif // GU_BV4_USE_SLABS
|
||||
|
||||
#endif // GU_BV4_INTERNAL_H
|
||||
1955
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_MeshMeshOverlap.cpp
vendored
Normal file
1955
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_MeshMeshOverlap.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
167
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_OBBSweep.cpp
vendored
Normal file
167
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_OBBSweep.cpp
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "GuBV4.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
#include "GuBV4_BoxSweep_Internal.h"
|
||||
|
||||
PxIntBool Sweep_AABB_BV4(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags);
|
||||
void GenericSweep_AABB_CB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, MeshSweepCallback callback, void* userData, PxU32 flags);
|
||||
void Sweep_AABB_BV4_CB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags, bool nodeSorting);
|
||||
|
||||
// PT: TODO: optimize this (TA34704)
|
||||
static PX_FORCE_INLINE void computeLocalData(Box& localBox, PxVec3& localDir, const Box& box, const PxVec3& dir, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
if(worldm_Aligned)
|
||||
{
|
||||
PxMat44 IWM;
|
||||
invertPRMatrix(&IWM, worldm_Aligned);
|
||||
|
||||
localDir = IWM.rotate(dir);
|
||||
|
||||
rotateBox(localBox, IWM, box);
|
||||
}
|
||||
else
|
||||
{
|
||||
localDir = dir;
|
||||
localBox = box; // PT: TODO: check asm for operator= (TA34704)
|
||||
}
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE bool isAxisAligned(const PxVec3& axis)
|
||||
{
|
||||
const PxReal minLimit = 1e-3f;
|
||||
const PxReal maxLimit = 1.0f - 1e-3f;
|
||||
|
||||
const PxReal absX = PxAbs(axis.x);
|
||||
if(absX>minLimit && absX<maxLimit)
|
||||
return false;
|
||||
|
||||
const PxReal absY = PxAbs(axis.y);
|
||||
if(absY>minLimit && absY<maxLimit)
|
||||
return false;
|
||||
|
||||
const PxReal absZ = PxAbs(axis.z);
|
||||
if(absZ>minLimit && absZ<maxLimit)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE bool isAABB(const Box& box)
|
||||
{
|
||||
if(!isAxisAligned(box.rot.column0))
|
||||
return false;
|
||||
if(!isAxisAligned(box.rot.column1))
|
||||
return false;
|
||||
if(!isAxisAligned(box.rot.column2))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
PxIntBool BV4_BoxSweepSingle(const Box& box, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepHit* PX_RESTRICT hit, PxU32 flags)
|
||||
{
|
||||
Box localBox;
|
||||
PxVec3 localDir;
|
||||
computeLocalData(localBox, localDir, box, dir, worldm_Aligned);
|
||||
|
||||
PxIntBool Status;
|
||||
if(isAABB(localBox))
|
||||
Status = Sweep_AABB_BV4(localBox, localDir, maxDist, tree, hit, flags);
|
||||
else
|
||||
Status = Sweep_OBB_BV4(localBox, localDir, maxDist, tree, hit, flags);
|
||||
if(Status && worldm_Aligned)
|
||||
{
|
||||
// Move to world space
|
||||
// PT: TODO: optimize (TA34704)
|
||||
hit->mPos = worldm_Aligned->transform(hit->mPos);
|
||||
hit->mNormal = worldm_Aligned->rotate(hit->mNormal);
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
|
||||
// PT: for design decisions in this function, refer to the comments of BV4_GenericSweepCB().
|
||||
void BV4_BoxSweepCB(const Box& box, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags, bool nodeSorting)
|
||||
{
|
||||
Box localBox;
|
||||
PxVec3 localDir;
|
||||
computeLocalData(localBox, localDir, box, dir, worldm_Aligned);
|
||||
|
||||
if(isAABB(localBox))
|
||||
Sweep_AABB_BV4_CB(localBox, localDir, maxDist, tree, worldm_Aligned, callback, userData, flags, nodeSorting);
|
||||
else
|
||||
Sweep_OBB_BV4_CB(localBox, localDir, maxDist, tree, worldm_Aligned, callback, userData, flags, nodeSorting);
|
||||
}
|
||||
|
||||
|
||||
// PT: this generic sweep uses an OBB because this is the most versatile volume, but it does not mean this function is
|
||||
// a "box sweep function" per-se. In fact it could be used all alone to implement all sweeps in the SDK (but that would
|
||||
// have an impact on performance).
|
||||
//
|
||||
// So the idea here is simply to provide and use a generic function for everything that the BV4 code does not support directly.
|
||||
// In particular this should be used:
|
||||
// - for convex sweeps (where the OBB is the box around the swept convex)
|
||||
// - for non-trivial sphere/capsule/box sweeps where mesh scaling or inflation
|
||||
//
|
||||
// By design we don't do leaf tests inside the BV4 traversal code here (because we don't support them, e.g. convex
|
||||
// sweeps. If we could do them inside the BV4 traversal code, like we do for regular sweeps, then this would not be a generic
|
||||
// sweep function, but instead a built-in, natively supported query). So the leaf tests are performed outside of BV4, in the
|
||||
// client code, through MeshSweepCallback. This has a direct impact on the design & parameters of MeshSweepCallback.
|
||||
//
|
||||
// On the other hand this is used for "regular sweeps with shapes we don't natively support", i.e. SweepSingle kind of queries.
|
||||
// This means that we need to support an early-exit codepath (without node-sorting) and a regular sweep single codepath (with
|
||||
// node sorting) for this generic function. The leaf tests are external, but everything traversal-related should be exactly the
|
||||
// same as the regular box-sweep function otherwise.
|
||||
//
|
||||
// As a consequence, this function is not well-suited to implement "unlimited results" kind of queries, a.k.a. "sweep all":
|
||||
//
|
||||
// - for regular sphere/capsule/box "sweep all" queries, the leaf tests should be internal (same as sweep single queries). This
|
||||
// means the existing MeshSweepCallback can't be reused.
|
||||
//
|
||||
// - there is no need to support "sweep any" (it is already supported by the other sweep functions).
|
||||
//
|
||||
// - there may be no need for ordered traversal/node sorting/ray shrinking, since we want to return all results anyway. But this
|
||||
// may not be true if the "sweep all" function is used to emulate the Epic Tweak. In that case we still want to shrink the ray
|
||||
// and use node sorting. Since both versions are useful, we should probably have a bool param to enable/disable node sorting.
|
||||
//
|
||||
// - we are interested in all hits so we can't delay the computation of impact data (computing it only once in the end, for the
|
||||
// closest hit). We actually need to compute the data for all hits, possibly within the traversal code.
|
||||
void BV4_GenericSweepCB(const Box& localBox, const PxVec3& localDir, float maxDist, const BV4Tree& tree, MeshSweepCallback callback, void* userData, bool anyHit)
|
||||
{
|
||||
const PxU32 flags = anyHit ? PxU32(QUERY_MODIFIER_ANY_HIT) : 0;
|
||||
|
||||
if(isAABB(localBox))
|
||||
GenericSweep_AABB_CB(localBox, localDir, maxDist, tree, callback, userData, flags);
|
||||
else
|
||||
GenericSweep_OBB_CB(localBox, localDir, maxDist, tree, callback, userData, flags);
|
||||
}
|
||||
|
||||
109
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamNoOrder_OBBOBB.h
vendored
Normal file
109
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamNoOrder_OBBOBB.h
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_PROCESS_STREAM_NOORDER_OBB_OBB_H
|
||||
#define GU_BV4_PROCESS_STREAM_NOORDER_OBB_OBB_H
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
/* template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder_Swizzled(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzled* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CE(i)
|
||||
|
||||
if(BV4_BoxBoxOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node->getPrimitive(i)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder_SwizzledQ(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzledQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CEQ(i)
|
||||
|
||||
if(BV4_BoxBoxOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node->getPrimitive(i)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder_SwizzledNQ(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzledNQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CENQ(i)
|
||||
|
||||
if(BV4_BoxBoxOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node->getPrimitive(i)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_BoxBoxOverlap(node+i, params))
|
||||
#else
|
||||
if(BV4_BoxBoxOverlap(node[i].mAABB.mExtents, node[i].mAABB.mCenter, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node[i].getPrimitive()))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_NOORDER_OBB_OBB_H
|
||||
54
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamNoOrder_SegmentAABB.h
vendored
Normal file
54
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamNoOrder_SegmentAABB.h
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_PROCESS_STREAM_NOORDER_SEGMENT_AABB_H
|
||||
#define GU_BV4_PROCESS_STREAM_NOORDER_SEGMENT_AABB_H
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_SegmentAABBOverlap(node+i, params))
|
||||
#else
|
||||
if(BV4_SegmentAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node[i].getPrimitive()))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_NOORDER_SEGMENT_AABB_H
|
||||
@@ -0,0 +1,54 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_PROCESS_STREAM_NOORDER_SEGMENT_AABB_INFLATED_H
|
||||
#define GU_BV4_PROCESS_STREAM_NOORDER_SEGMENT_AABB_INFLATED_H
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_SegmentAABBOverlap(node+i, params->mOriginalExtents_Padded, params))
|
||||
#else
|
||||
if(BV4_SegmentAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params->mOriginalExtents_Padded, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node[i].getPrimitive()))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_NOORDER_SEGMENT_AABB_INFLATED_H
|
||||
110
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamNoOrder_SphereAABB.h
vendored
Normal file
110
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamNoOrder_SphereAABB.h
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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_BV4_PROCESS_STREAM_NOORDER_SPHERE_AABB_H
|
||||
#define GU_BV4_PROCESS_STREAM_NOORDER_SPHERE_AABB_H
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
/* template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder_Swizzled(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzled* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
// OPC_SLABS_GET_CE(i)
|
||||
OPC_SLABS_GET_CE2(i)
|
||||
|
||||
if(BV4_SphereAABBOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node->getPrimitive(i)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder_SwizzledQ(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzledQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CE2Q(i)
|
||||
|
||||
if(BV4_SphereAABBOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node->getPrimitive(i)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder_SwizzledNQ(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzledNQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CE2NQ(i)
|
||||
|
||||
if(BV4_SphereAABBOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node->getPrimitive(i)))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE PxIntBool BV4_ProcessNodeNoOrder(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_SphereAABBOverlap(node+i, params))
|
||||
#else
|
||||
if(BV4_SphereAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
{
|
||||
if(LeafTestT::doLeafTest(params, node[i].getPrimitive()))
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_NOORDER_SPHERE_AABB_H
|
||||
109
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamOrdered_OBBOBB.h
vendored
Normal file
109
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamOrdered_OBBOBB.h
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_PROCESS_STREAM_ORDERED_OBB_OBB_H
|
||||
#define GU_BV4_PROCESS_STREAM_ORDERED_OBB_OBB_H
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
/* template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered2_Swizzled(PxU32& code, const BVDataSwizzled* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CE(i)
|
||||
|
||||
if(BV4_BoxBoxOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
LeafTestT::doLeafTest(params, node->getPrimitive(i));
|
||||
else
|
||||
code |= 1<<i;
|
||||
}
|
||||
}*/
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered2_SwizzledQ(PxU32& code, const BVDataSwizzledQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CEQ(i)
|
||||
|
||||
if(BV4_BoxBoxOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
LeafTestT::doLeafTest(params, node->getPrimitive(i));
|
||||
else
|
||||
code |= 1<<i;
|
||||
}
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered2_SwizzledNQ(PxU32& code, const BVDataSwizzledNQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
OPC_SLABS_GET_CENQ(i)
|
||||
|
||||
if(BV4_BoxBoxOverlap(centerV, extentsV, params))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
LeafTestT::doLeafTest(params, node->getPrimitive(i));
|
||||
else
|
||||
code |= 1<<i;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
template<class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params, PxU32 i, PxU32 limit)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(i<limit && BV4_BoxBoxOverlap(node+i, params))
|
||||
#else
|
||||
if(i<limit && BV4_BoxBoxOverlap(node[i].mAABB.mExtents, node[i].mAABB.mCenter, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
LeafTestT::doLeafTest(params, node[i].getPrimitive());
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered2(PxU32& code, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_BoxBoxOverlap(node+i, params))
|
||||
#else
|
||||
if(BV4_BoxBoxOverlap(node[i].mAABB.mExtents, node[i].mAABB.mCenter, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
LeafTestT::doLeafTest(params, node[i].getPrimitive());
|
||||
else
|
||||
code |= 1<<i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_ORDERED_OBB_OBB_H
|
||||
66
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamOrdered_SegmentAABB.h
vendored
Normal file
66
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_ProcessStreamOrdered_SegmentAABB.h
vendored
Normal 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_BV4_PROCESS_STREAM_ORDERED_SEGMENT_AABB_H
|
||||
#define GU_BV4_PROCESS_STREAM_ORDERED_SEGMENT_AABB_H
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
template<class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params, PxU32 i, PxU32 limit)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(i<limit && BV4_SegmentAABBOverlap(node+i, params))
|
||||
#else
|
||||
if(i<limit && BV4_SegmentAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
LeafTestT::doLeafTest(params, node[i].getPrimitive());
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered2(PxU32& code, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_SegmentAABBOverlap(node+i, params))
|
||||
#else
|
||||
if(BV4_SegmentAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
LeafTestT::doLeafTest(params, node[i].getPrimitive());
|
||||
else
|
||||
code |= 1<<i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_ORDERED_SEGMENT_AABB_H
|
||||
@@ -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_BV4_PROCESS_STREAM_ORDERED_SEGMENT_AABB_INFLATED_H
|
||||
#define GU_BV4_PROCESS_STREAM_ORDERED_SEGMENT_AABB_INFLATED_H
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
template<class LeafTestT, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params, PxU32 i, PxU32 limit)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(i<limit && BV4_SegmentAABBOverlap(node+i, params->mOriginalExtents, params))
|
||||
#else
|
||||
if(i<limit && BV4_SegmentAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params->mOriginalExtents, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
LeafTestT::doLeafTest(params, node[i].getPrimitive());
|
||||
else
|
||||
Stack[Nb++] = node[i].getChildData();
|
||||
}
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeOrdered2(PxU32& code, const BVDataPacked* PX_RESTRICT node, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
if(BV4_SegmentAABBOverlap(node+i, params->mOriginalExtents_Padded, params))
|
||||
#else
|
||||
if(BV4_SegmentAABBOverlap(node[i].mAABB.mCenter, node[i].mAABB.mExtents, params->mOriginalExtents_Padded, params))
|
||||
#endif
|
||||
{
|
||||
if(node[i].isLeaf())
|
||||
LeafTestT::doLeafTest(params, node[i].getPrimitive());
|
||||
else
|
||||
code |= 1<<i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // GU_BV4_PROCESS_STREAM_ORDERED_SEGMENT_AABB_INFLATED_H
|
||||
906
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Raycast.cpp
vendored
Normal file
906
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Raycast.cpp
vendored
Normal file
@@ -0,0 +1,906 @@
|
||||
// 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 "GuBV4.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
// PT: this one avoids a divide but doesn't seem to make a difference
|
||||
//#define TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
|
||||
// PT: works but unclear performance benefits. Needs more testing.
|
||||
//#define USE_SIMD_RAY_VS_TRI
|
||||
|
||||
#include "PxQueryReport.h"
|
||||
#include "GuInternal.h"
|
||||
|
||||
#include "GuIntersectionRayTriangle.h"
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
|
||||
#include "GuBV4_Common.h"
|
||||
|
||||
class RaycastHitInternalUV : public RaycastHitInternal
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE RaycastHitInternalUV() {}
|
||||
PX_FORCE_INLINE ~RaycastHitInternalUV() {}
|
||||
|
||||
float mU, mV;
|
||||
};
|
||||
|
||||
#ifdef USE_SIMD_RAY_VS_TRI
|
||||
|
||||
//#define DotV V4Dot
|
||||
#define DotV V4Dot3
|
||||
//PX_FORCE_INLINE FloatV V4Dot3_SSE42(const Vec4V a, const Vec4V b) { return _mm_dp_ps(a, b, 0x7f); }
|
||||
//#define DotV V4Dot3_SSE42
|
||||
|
||||
template<class T>
|
||||
static PX_FORCE_INLINE PxIntBool SimdRayTriOverlapT(PxGeomRaycastHit& mStabbedFace, const PxVec3& vert0, const PxVec3& vert1, const PxVec3& vert2, const T* PX_RESTRICT params)
|
||||
{
|
||||
// Find vectors for two edges sharing vert0
|
||||
const Vec4V vert0V = V4LoadU(&vert0.x);
|
||||
|
||||
const Vec4V edge1V = V4Sub(V4LoadU(&vert1.x), vert0V); // const PxVec3 edge1 = vert1 - vert0;
|
||||
const Vec4V edge2V = V4Sub(V4LoadU(&vert2.x), vert0V); // const PxVec3 edge2 = vert2 - vert0;
|
||||
|
||||
// Begin calculating determinant - also used to calculate U parameter
|
||||
const Vec4V localDirV = V4LoadU(¶ms->mLocalDir_Padded.x);
|
||||
/*const*/ Vec4V pvecV = V4Cross(localDirV, edge2V); // const PxVec3 pvec = params->mLocalDir_Padded.cross(edge2);
|
||||
//pvecV = V4ClearW(pvecV);
|
||||
// If determinant is near zero, ray lies in plane of triangle
|
||||
const FloatV detV = DotV(edge1V, pvecV); // const float det = edge1.dot(pvec);
|
||||
|
||||
// PT: TODO: if we zero W in pvecV and qvecV we can switch to V4Dot *************
|
||||
|
||||
// PT: because the SIMD version delays the branches we can share more computations between culling & non-culling codepaths
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
const Vec4V tvecV = V4Sub(V4LoadU(¶ms->mOrigin_Padded.x), vert0V); // const PxVec3 tvec = params->mOrigin_Padded - vert0;
|
||||
|
||||
// Prepare to test V parameter
|
||||
/*const*/ Vec4V qvecV = V4Cross(tvecV, edge1V); // const PxVec3 qvec = tvec.cross(edge1);
|
||||
//qvecV = V4ClearW(qvecV);
|
||||
|
||||
const FloatV localEpsilonV = FLoad(GU_CULLING_EPSILON_RAY_TRIANGLE);
|
||||
const FloatV geomEpsilonV = FLoad(params->mGeomEpsilon);
|
||||
|
||||
if(params->mBackfaceCulling)
|
||||
{
|
||||
// Calculate U parameter and test bounds
|
||||
const FloatV uV = DotV(tvecV, pvecV); // const float u = tvec.dot(pvec);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const FloatV vV = DotV(localDirV, qvecV); // const float v = params->mLocalDir_Padded.dot(qvec);
|
||||
|
||||
// Calculate t, scale parameters, ray intersects triangle
|
||||
const FloatV dV = DotV(edge2V, qvecV); // const float d = edge2.dot(qvec);
|
||||
|
||||
/////
|
||||
|
||||
// if(det<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
// return 0;
|
||||
BoolV res = FIsGrtr(localEpsilonV, detV);
|
||||
|
||||
/////
|
||||
|
||||
// const PxReal enlargeCoeff = params->mGeomEpsilon*det;
|
||||
const FloatV enlargeCoeffV = FMul(detV, geomEpsilonV);
|
||||
/*
|
||||
const PxReal uvlimit = -enlargeCoeff;
|
||||
const PxReal uvlimit2 = det + enlargeCoeff;
|
||||
|
||||
if(u < uvlimit || u > uvlimit2)
|
||||
return 0;
|
||||
|
||||
if(v < uvlimit || (u + v) > uvlimit2)
|
||||
return 0;
|
||||
|
||||
// Det > 0 so we can early exit here
|
||||
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
|
||||
if(d<0.0f)
|
||||
return 0;
|
||||
*/
|
||||
res = BOr(res, FIsGrtr(FZero(), FMin(dV, FMin(FAdd(uV, enlargeCoeffV), FAdd(vV, enlargeCoeffV)))));
|
||||
res = BOr(res, FIsGrtr(FMax(uV, FAdd(uV, vV)), FAdd(detV, enlargeCoeffV)));
|
||||
// if(!BAllEqFFFF(res))
|
||||
// return 0;
|
||||
if(BGetBitMask(res))
|
||||
return 0;
|
||||
|
||||
// Else go on
|
||||
// const float OneOverDet = 1.0f / det;
|
||||
const FloatV oneOverDetV = FDiv(FLoad(1.0f), detV);
|
||||
FStore(FMul(dV, oneOverDetV), &mStabbedFace.distance); // mStabbedFace.distance = d * OneOverDet;
|
||||
FStore(FMul(uV, oneOverDetV), &mStabbedFace.u); // mStabbedFace.u = u * OneOverDet;
|
||||
FStore(FMul(vV, oneOverDetV), &mStabbedFace.v); // mStabbedFace.v = v * OneOverDet;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if(PxAbs(det)<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
// return 0;
|
||||
BoolV res = FIsGrtr(localEpsilonV, FAbs(detV));
|
||||
|
||||
const FloatV oneV = FLoad(1.0f);
|
||||
const FloatV oneOverDetV = FDiv(oneV, detV); // const float OneOverDet = 1.0f / det;
|
||||
|
||||
const FloatV uV = FMul(DotV(tvecV, pvecV), oneOverDetV); // const float u = tvec.dot(pvec) * OneOverDet;
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const FloatV vV = FMul(DotV(localDirV, qvecV), oneOverDetV); // const float v = params->mLocalDir_Padded.dot(qvec) * OneOverDet;
|
||||
|
||||
// Calculate t, ray intersects triangle
|
||||
const FloatV dV = FMul(DotV(edge2V, qvecV), oneOverDetV); // const float d = edge2.dot(qvec) * OneOverDet;
|
||||
/*
|
||||
if(u<-params->mGeomEpsilon || u>1.0f+params->mGeomEpsilon)
|
||||
return 0;
|
||||
|
||||
if(v < -params->mGeomEpsilon || (u + v) > 1.0f + params->mGeomEpsilon)
|
||||
return 0;
|
||||
|
||||
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
|
||||
if(d<0.0f)
|
||||
return 0;
|
||||
*/
|
||||
res = BOr(res, FIsGrtr(FZero(), FMin(dV, FMin(FAdd(uV, geomEpsilonV), FAdd(vV, geomEpsilonV)))));
|
||||
res = BOr(res, FIsGrtr(FMax(uV, FAdd(uV, vV)), FAdd(oneV, geomEpsilonV)));
|
||||
//if(!BAllEqFFFF(res))
|
||||
// return 0;
|
||||
if(BGetBitMask(res))
|
||||
return 0;
|
||||
|
||||
FStore(dV, &mStabbedFace.distance); // mStabbedFace.distance = d;
|
||||
FStore(uV, &mStabbedFace.u); // mStabbedFace.u = u;
|
||||
FStore(vV, &mStabbedFace.v); // mStabbedFace.v = v;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static PX_FORCE_INLINE PxIntBool SimdRayTriOverlapT2(PxGeomRaycastHit& mStabbedFace, const PxVec3& vert0, const PxVec3& vert1, const PxVec3& vert2, const T* PX_RESTRICT params)
|
||||
{
|
||||
// Find vectors for two edges sharing vert0
|
||||
const Vec4V vert0V = V4LoadU(&vert0.x);
|
||||
|
||||
const Vec4V edge1V = V4Sub(V4LoadU(&vert1.x), vert0V); // const PxVec3 edge1 = vert1 - vert0;
|
||||
const Vec4V edge2V = V4Sub(V4LoadU(&vert2.x), vert0V); // const PxVec3 edge2 = vert2 - vert0;
|
||||
|
||||
// Begin calculating determinant - also used to calculate U parameter
|
||||
const Vec4V localDirV = V4LoadU(¶ms->mLocalDir_Padded.x);
|
||||
const Vec4V pvecV = V4Cross(localDirV, edge2V); // const PxVec3 pvec = params->mLocalDir_Padded.cross(edge2);
|
||||
// If determinant is near zero, ray lies in plane of triangle
|
||||
const FloatV detV = DotV(edge1V, pvecV); // const float det = edge1.dot(pvec);
|
||||
|
||||
const FloatV localEpsilonV = FLoad(GU_CULLING_EPSILON_RAY_TRIANGLE);
|
||||
|
||||
if(params->mBackfaceCulling)
|
||||
{
|
||||
// if(det<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
// return 0;
|
||||
BoolV res = FIsGrtr(localEpsilonV, detV);
|
||||
if(BGetBitMask(res))
|
||||
return 0;
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
const Vec4V tvecV = V4Sub(V4LoadU(¶ms->mOrigin_Padded.x), vert0V); // const PxVec3 tvec = params->mOrigin_Padded - vert0;
|
||||
|
||||
// Prepare to test V parameter
|
||||
const Vec4V qvecV = V4Cross(tvecV, edge1V); // const PxVec3 qvec = tvec.cross(edge1);
|
||||
|
||||
const FloatV geomEpsilonV = FLoad(params->mGeomEpsilon);
|
||||
|
||||
// Calculate U parameter and test bounds
|
||||
const FloatV uV = DotV(tvecV, pvecV); // const float u = tvec.dot(pvec);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const FloatV vV = DotV(localDirV, qvecV); // const float v = params->mLocalDir_Padded.dot(qvec);
|
||||
|
||||
// Calculate t, scale parameters, ray intersects triangle
|
||||
const FloatV dV = DotV(edge2V, qvecV); // const float d = edge2.dot(qvec);
|
||||
|
||||
/////
|
||||
|
||||
// const PxReal enlargeCoeff = params->mGeomEpsilon*det;
|
||||
const FloatV enlargeCoeffV = FMul(detV, geomEpsilonV);
|
||||
|
||||
res = BOr(res, FIsGrtr(FZero(), FMin(dV, FMin(FAdd(uV, enlargeCoeffV), FAdd(vV, enlargeCoeffV)))));
|
||||
res = BOr(res, FIsGrtr(FMax(uV, FAdd(uV, vV)), FAdd(detV, enlargeCoeffV)));
|
||||
// if(!BAllEqFFFF(res))
|
||||
// return 0;
|
||||
if(BGetBitMask(res))
|
||||
return 0;
|
||||
|
||||
// Else go on
|
||||
// const float OneOverDet = 1.0f / det;
|
||||
const FloatV oneOverDetV = FDiv(FLoad(1.0f), detV);
|
||||
FStore(FMul(dV, oneOverDetV), &mStabbedFace.distance); // mStabbedFace.distance = d * OneOverDet;
|
||||
FStore(FMul(uV, oneOverDetV), &mStabbedFace.u); // mStabbedFace.u = u * OneOverDet;
|
||||
FStore(FMul(vV, oneOverDetV), &mStabbedFace.v); // mStabbedFace.v = v * OneOverDet;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//if(PxAbs(det)<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
// return 0;
|
||||
BoolV res = FIsGrtr(localEpsilonV, FAbs(detV));
|
||||
if(BGetBitMask(res))
|
||||
return 0;
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
const Vec4V tvecV = V4Sub(V4LoadU(¶ms->mOrigin_Padded.x), vert0V); // const PxVec3 tvec = params->mOrigin_Padded - vert0;
|
||||
|
||||
// Prepare to test V parameter
|
||||
const Vec4V qvecV = V4Cross(tvecV, edge1V); // const PxVec3 qvec = tvec.cross(edge1);
|
||||
|
||||
const FloatV geomEpsilonV = FLoad(params->mGeomEpsilon);
|
||||
|
||||
|
||||
const FloatV oneV = FLoad(1.0f);
|
||||
const FloatV oneOverDetV = FDiv(oneV, detV); // const float OneOverDet = 1.0f / det;
|
||||
|
||||
const FloatV uV = FMul(DotV(tvecV, pvecV), oneOverDetV); // const float u = tvec.dot(pvec) * OneOverDet;
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const FloatV vV = FMul(DotV(localDirV, qvecV), oneOverDetV); // const float v = params->mLocalDir_Padded.dot(qvec) * OneOverDet;
|
||||
|
||||
// Calculate t, ray intersects triangle
|
||||
const FloatV dV = FMul(DotV(edge2V, qvecV), oneOverDetV); // const float d = edge2.dot(qvec) * OneOverDet;
|
||||
|
||||
res = BOr(res, FIsGrtr(FZero(), FMin(dV, FMin(FAdd(uV, geomEpsilonV), FAdd(vV, geomEpsilonV)))));
|
||||
res = BOr(res, FIsGrtr(FMax(uV, FAdd(uV, vV)), FAdd(oneV, geomEpsilonV)));
|
||||
|
||||
if(BGetBitMask(res))
|
||||
return 0;
|
||||
|
||||
FStore(dV, &mStabbedFace.distance); // mStabbedFace.distance = d;
|
||||
FStore(uV, &mStabbedFace.u); // mStabbedFace.u = u;
|
||||
FStore(vV, &mStabbedFace.v); // mStabbedFace.v = v;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template<class T>
|
||||
static PX_FORCE_INLINE PxIntBool RayTriOverlapT(PxGeomRaycastHit& mStabbedFace, const PxVec3& vert0, const PxVec3& vert1, const PxVec3& vert2, const T* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef USE_SIMD_RAY_VS_TRI
|
||||
if(0)
|
||||
return SimdRayTriOverlapT(mStabbedFace, vert0, vert1, vert2, params);
|
||||
if(0)
|
||||
return SimdRayTriOverlapT2(mStabbedFace, vert0, vert1, vert2, params);
|
||||
#endif
|
||||
|
||||
// Find vectors for two edges sharing vert0
|
||||
const PxVec3 edge1 = vert1 - vert0;
|
||||
const PxVec3 edge2 = vert2 - vert0;
|
||||
|
||||
// Begin calculating determinant - also used to calculate U parameter
|
||||
const PxVec3 pvec = params->mLocalDir_Padded.cross(edge2);
|
||||
|
||||
// If determinant is near zero, ray lies in plane of triangle
|
||||
const float det = edge1.dot(pvec);
|
||||
|
||||
if(params->mBackfaceCulling)
|
||||
{
|
||||
if(det<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
return 0;
|
||||
|
||||
// Calculate distance from vert0 to ray origin
|
||||
const PxVec3 tvec = params->mOrigin_Padded - vert0;
|
||||
|
||||
// Calculate U parameter and test bounds
|
||||
const float u = tvec.dot(pvec);
|
||||
|
||||
const PxReal enlargeCoeff = params->mGeomEpsilon*det;
|
||||
const PxReal uvlimit = -enlargeCoeff;
|
||||
const PxReal uvlimit2 = det + enlargeCoeff;
|
||||
|
||||
if(u < uvlimit || u > uvlimit2)
|
||||
return 0;
|
||||
|
||||
// Prepare to test V parameter
|
||||
const PxVec3 qvec = tvec.cross(edge1);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const float v = params->mLocalDir_Padded.dot(qvec);
|
||||
if(v < uvlimit || (u + v) > uvlimit2)
|
||||
return 0;
|
||||
|
||||
// Calculate t, scale parameters, ray intersects triangle
|
||||
const float d = edge2.dot(qvec);
|
||||
// Det > 0 so we can early exit here
|
||||
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
|
||||
if(d<0.0f)
|
||||
return 0;
|
||||
|
||||
#ifdef TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
if(d>=det*params->mStabbedFace.mDistance) //### just for a corner case UT in PhysX :(
|
||||
return 0;
|
||||
#endif
|
||||
// Else go on
|
||||
const float OneOverDet = 1.0f / det;
|
||||
mStabbedFace.distance = d * OneOverDet;
|
||||
mStabbedFace.u = u * OneOverDet;
|
||||
mStabbedFace.v = v * OneOverDet;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(PxAbs(det)<GU_CULLING_EPSILON_RAY_TRIANGLE)
|
||||
return 0;
|
||||
|
||||
const float OneOverDet = 1.0f / det;
|
||||
|
||||
const PxVec3 tvec = params->mOrigin_Padded - vert0;
|
||||
|
||||
const float u = tvec.dot(pvec) * OneOverDet;
|
||||
if(u<-params->mGeomEpsilon || u>1.0f+params->mGeomEpsilon)
|
||||
return 0;
|
||||
|
||||
// prepare to test V parameter
|
||||
const PxVec3 qvec = tvec.cross(edge1);
|
||||
|
||||
// Calculate V parameter and test bounds
|
||||
const float v = params->mLocalDir_Padded.dot(qvec) * OneOverDet;
|
||||
if(v < -params->mGeomEpsilon || (u + v) > 1.0f + params->mGeomEpsilon)
|
||||
return 0;
|
||||
|
||||
// Calculate t, ray intersects triangle
|
||||
const float d = edge2.dot(qvec) * OneOverDet;
|
||||
// Intersection point is valid if distance is positive (else it can just be a face behind the orig point)
|
||||
if(d<0.0f)
|
||||
return 0;
|
||||
|
||||
#ifdef TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
if(d>=params->mStabbedFace.mDistance) //### just for a corner case UT in PhysX :(
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
mStabbedFace.distance = d;
|
||||
mStabbedFace.u = u;
|
||||
mStabbedFace.v = v;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning ( disable : 4324 )
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RayParams_Raycast // PT: compiler gets confused otherwise
|
||||
{
|
||||
BV4_ALIGN16(PxVec3p mCenterOrMinCoeff_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mExtentsOrMaxCoeff_PaddedAligned);
|
||||
// Organized in the order they are accessed
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
BV4_ALIGN16(PxVec3p mData2_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mFDir_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mData_PaddedAligned);
|
||||
#endif
|
||||
const IndTri32* PX_RESTRICT mTris32;
|
||||
const IndTri16* PX_RESTRICT mTris16;
|
||||
const PxVec3* PX_RESTRICT mVerts;
|
||||
PxVec3 mLocalDir_Padded;
|
||||
PxVec3 mOrigin_Padded;
|
||||
|
||||
float mGeomEpsilon;
|
||||
PxU32 mBackfaceCulling;
|
||||
|
||||
RaycastHitInternalUV mStabbedFace;
|
||||
PxU32 mEarlyExit;
|
||||
|
||||
PxVec3 mOriginalExtents_Padded; // Added to please the slabs code
|
||||
|
||||
BV4_ALIGN16(PxVec3p mP0_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mP1_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mP2_PaddedAligned);
|
||||
};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static PX_FORCE_INLINE void updateParamsAfterImpact(RayParams_Raycast* PX_RESTRICT params, PxU32 primIndex, PxU32 VRef0, PxU32 VRef1, PxU32 VRef2, const PxGeomRaycastHit& StabbedFace)
|
||||
{
|
||||
V4StoreA_Safe(V4LoadU_Safe(¶ms->mVerts[VRef0].x), ¶ms->mP0_PaddedAligned.x);
|
||||
V4StoreA_Safe(V4LoadU_Safe(¶ms->mVerts[VRef1].x), ¶ms->mP1_PaddedAligned.x);
|
||||
V4StoreA_Safe(V4LoadU_Safe(¶ms->mVerts[VRef2].x), ¶ms->mP2_PaddedAligned.x);
|
||||
|
||||
params->mStabbedFace.mTriangleID = primIndex;
|
||||
params->mStabbedFace.mDistance = StabbedFace.distance;
|
||||
params->mStabbedFace.mU = StabbedFace.u;
|
||||
params->mStabbedFace.mV = StabbedFace.v;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_RaycastClosest
|
||||
{
|
||||
public:
|
||||
static /*PX_FORCE_INLINE*/ PxIntBool doLeafTest(RayParams_Raycast* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PX_ALIGN_PREFIX(16) char buffer[sizeof(PxGeomRaycastHit)] PX_ALIGN_SUFFIX(16);
|
||||
PxGeomRaycastHit& StabbedFace = reinterpret_cast<PxGeomRaycastHit&>(buffer);
|
||||
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
if(RayTriOverlapT<RayParams_Raycast>(StabbedFace, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params))
|
||||
{
|
||||
#ifndef TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
if(StabbedFace.distance<params->mStabbedFace.mDistance) //### just for a corner case UT in PhysX :(
|
||||
#endif
|
||||
{
|
||||
updateParamsAfterImpact(params, primIndex, VRef0, VRef1, VRef2, StabbedFace);
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, StabbedFace.distance, params->mOrigin_Padded, params->mLocalDir_Padded);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class LeafFunction_RaycastAny
|
||||
{
|
||||
public:
|
||||
static /*PX_FORCE_INLINE*/ PxIntBool doLeafTest(RayParams_Raycast* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
PX_ALIGN_PREFIX(16) char buffer[sizeof(PxGeomRaycastHit)] PX_ALIGN_SUFFIX(16);
|
||||
PxGeomRaycastHit& StabbedFace = reinterpret_cast<PxGeomRaycastHit&>(buffer);
|
||||
if(RayTriOverlapT<RayParams_Raycast>(StabbedFace, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params))
|
||||
{
|
||||
#ifndef TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
if(StabbedFace.distance<params->mStabbedFace.mDistance) //### just for a corner case UT in PhysX :(
|
||||
#endif
|
||||
{
|
||||
updateParamsAfterImpact(params, primIndex, VRef0, VRef1, VRef2, StabbedFace);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE Vec4V multiply3x3V_Aligned(const Vec4V p, const PxMat44* PX_RESTRICT mat)
|
||||
{
|
||||
const FloatV xxxV = V4GetX(p);
|
||||
const FloatV yyyV = V4GetY(p);
|
||||
const FloatV zzzV = V4GetZ(p);
|
||||
|
||||
Vec4V ResV = V4Scale(V4LoadA(&mat->column0.x), xxxV);
|
||||
ResV = V4Add(ResV, V4Scale(V4LoadA(&mat->column1.x), yyyV));
|
||||
ResV = V4Add(ResV, V4Scale(V4LoadA(&mat->column2.x), zzzV));
|
||||
return ResV;
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE PxIntBool computeImpactData(PxGeomRaycastHit* PX_RESTRICT hit, const RayParams_Raycast* PX_RESTRICT params, const PxMat44* PX_RESTRICT worldm_Aligned, PxHitFlags /*hitFlags*/)
|
||||
{
|
||||
if(params->mStabbedFace.mTriangleID!=PX_INVALID_U32 /*&& !params->mEarlyExit*/) //### PhysX needs the raycast data even for "any hit" :(
|
||||
{
|
||||
const float u = params->mStabbedFace.mU;
|
||||
const float v = params->mStabbedFace.mV;
|
||||
const float d = params->mStabbedFace.mDistance;
|
||||
const PxU32 id = params->mStabbedFace.mTriangleID;
|
||||
hit->u = u;
|
||||
hit->v = v;
|
||||
hit->distance = d;
|
||||
hit->faceIndex = id;
|
||||
|
||||
{
|
||||
const Vec4V P0V = V4LoadA_Safe(¶ms->mP0_PaddedAligned.x);
|
||||
const Vec4V P1V = V4LoadA_Safe(¶ms->mP1_PaddedAligned.x);
|
||||
const Vec4V P2V = V4LoadA_Safe(¶ms->mP2_PaddedAligned.x);
|
||||
|
||||
const FloatV uV = FLoad(params->mStabbedFace.mU);
|
||||
const FloatV vV = FLoad(params->mStabbedFace.mV);
|
||||
const float w = 1.0f - params->mStabbedFace.mU - params->mStabbedFace.mV;
|
||||
const FloatV wV = FLoad(w);
|
||||
//pt = (1.0f - u - v)*p0 + u*p1 + v*p2;
|
||||
Vec4V LocalPtV = V4Scale(P1V, uV);
|
||||
LocalPtV = V4Add(LocalPtV, V4Scale(P2V, vV));
|
||||
LocalPtV = V4Add(LocalPtV, V4Scale(P0V, wV));
|
||||
|
||||
const Vec4V LocalNormalV = V4Cross(V4Sub(P0V, P1V), V4Sub(P0V, P2V));
|
||||
|
||||
BV4_ALIGN16(PxVec3p tmp_PaddedAligned);
|
||||
if(worldm_Aligned)
|
||||
{
|
||||
const Vec4V TransV = V4LoadA(&worldm_Aligned->column3.x);
|
||||
V4StoreU_Safe(V4Add(multiply3x3V_Aligned(LocalPtV, worldm_Aligned), TransV), &hit->position.x);
|
||||
V4StoreA_Safe(multiply3x3V_Aligned(LocalNormalV, worldm_Aligned), &tmp_PaddedAligned.x);
|
||||
}
|
||||
else
|
||||
{
|
||||
V4StoreU_Safe(LocalPtV, &hit->position.x);
|
||||
V4StoreA_Safe(LocalNormalV, &tmp_PaddedAligned.x);
|
||||
}
|
||||
tmp_PaddedAligned.normalize();
|
||||
hit->normal = tmp_PaddedAligned; // PT: TODO: check asm here (TA34704)
|
||||
}
|
||||
}
|
||||
return params->mStabbedFace.mTriangleID!=PX_INVALID_U32;
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE float clipRay(const PxVec3& ray_orig, const PxVec3& ray_dir, const LocalBounds& local_bounds)
|
||||
{
|
||||
const float dpc = local_bounds.mCenter.dot(ray_dir);
|
||||
const float dpMin = dpc - local_bounds.mExtentsMagnitude;
|
||||
const float dpMax = dpc + local_bounds.mExtentsMagnitude;
|
||||
const float dpO = ray_orig.dot(ray_dir);
|
||||
const float boxLength = local_bounds.mExtentsMagnitude * 2.0f;
|
||||
const float distToBox = PxMin(fabsf(dpMin - dpO), fabsf(dpMax - dpO));
|
||||
return distToBox + boxLength * 2.0f;
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
static PX_FORCE_INLINE void setupRayParams(ParamsT* PX_RESTRICT params, const PxVec3& origin, const PxVec3& dir, const BV4Tree* PX_RESTRICT tree, const PxMat44* PX_RESTRICT world, const SourceMesh* PX_RESTRICT mesh, float maxDist, float geomEpsilon, PxU32 flags)
|
||||
{
|
||||
params->mGeomEpsilon = geomEpsilon;
|
||||
setupParamsFlags(params, flags);
|
||||
|
||||
computeLocalRay(params->mLocalDir_Padded, params->mOrigin_Padded, dir, origin, world);
|
||||
|
||||
// PT: TODO: clipRay may not be needed with GU_BV4_USE_SLABS (TA34704)
|
||||
const float MaxDist = clipRay(params->mOrigin_Padded, params->mLocalDir_Padded, tree->mLocalBounds);
|
||||
maxDist = PxMin(maxDist, MaxDist);
|
||||
params->mStabbedFace.mDistance = maxDist;
|
||||
params->mStabbedFace.mTriangleID = PX_INVALID_U32;
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, maxDist, params->mOrigin_Padded, params->mLocalDir_Padded);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
#endif
|
||||
#include "GuBV4_ProcessStreamOrdered_SegmentAABB.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_KajiyaNoOrder.h"
|
||||
#include "GuBV4_Slabs_KajiyaOrdered.h"
|
||||
#endif
|
||||
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_NO_ORDER
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_ORDERED
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
|
||||
// A.B. enable new version only for intel non simd path
|
||||
#if PX_INTEL_FAMILY && !defined(PX_SIMD_DISABLED)
|
||||
// #define NEW_VERSION
|
||||
#endif // PX_INTEL_FAMILY && !PX_SIMD_DISABLED
|
||||
|
||||
static PX_FORCE_INLINE /*PX_NOINLINE*/ PxIntBool BV4_SegmentAABBOverlap(const BVDataPacked* PX_RESTRICT node, const RayParams* PX_RESTRICT params)
|
||||
{
|
||||
#ifdef NEW_VERSION
|
||||
SSE_CONST4(maskV, 0x7fffffff);
|
||||
SSE_CONST4(maskQV, 0x0000ffff);
|
||||
#endif
|
||||
|
||||
#ifdef NEW_VERSION
|
||||
Vec4V centerV = V4LoadA((float*)node->mAABB.mData);
|
||||
__m128 extentsV = _mm_castsi128_ps(_mm_and_si128(_mm_castps_si128(centerV), SSE_CONST(maskQV)));
|
||||
extentsV = V4Mul(_mm_cvtepi32_ps(_mm_castps_si128(extentsV)), V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x));
|
||||
centerV = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(centerV), 16));
|
||||
centerV = V4Mul(_mm_cvtepi32_ps(_mm_castps_si128(centerV)), V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x));
|
||||
#else
|
||||
const VecI32V centerVI = I4LoadA((PxI32*)node->mAABB.mData);
|
||||
const VecI32V extentsVI = VecI32V_And(centerVI, I4Load(0x0000ffff));
|
||||
const Vec4V extentsV = V4Mul(Vec4V_From_VecI32V(extentsVI), V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x));
|
||||
const VecI32V centerVShift = VecI32V_RightShift(centerVI, 16);
|
||||
const Vec4V centerV = V4Mul(Vec4V_From_VecI32V(centerVShift), V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x));
|
||||
#endif
|
||||
|
||||
const Vec4V fdirV = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V DV = V4Sub(V4LoadA_Safe(¶ms->mData2_PaddedAligned.x), centerV);
|
||||
|
||||
#ifdef NEW_VERSION
|
||||
__m128 absDV = _mm_and_ps(DV, SSE_CONSTF(maskV));
|
||||
#else
|
||||
Vec4V absDV = V4Abs(DV);
|
||||
#endif
|
||||
|
||||
const BoolV resDV = V4IsGrtr(absDV, V4Add(extentsV, fdirV));
|
||||
const PxU32 test = BGetBitMask(resDV);
|
||||
if(test&7)
|
||||
return 0;
|
||||
|
||||
if(1)
|
||||
{
|
||||
const Vec4V dataZYX_V = V4LoadA_Safe(¶ms->mData_PaddedAligned.x);
|
||||
const Vec4V dataXZY_V = V4Perm<1, 2, 0, 3>(dataZYX_V);
|
||||
const Vec4V DXZY_V = V4Perm<1, 2, 0, 3>(DV);
|
||||
|
||||
const Vec4V fV = V4Sub(V4Mul(dataZYX_V, DXZY_V), V4Mul(dataXZY_V, DV));
|
||||
|
||||
const Vec4V fdirZYX_V = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V fdirXZY_V = V4Perm<1, 2, 0, 3>(fdirZYX_V);
|
||||
const Vec4V extentsXZY_V = V4Perm<1, 2, 0, 3>(extentsV);
|
||||
|
||||
// PT: TODO: use V4MulAdd here (TA34704)
|
||||
const Vec4V fg = V4Add(V4Mul(extentsV, fdirXZY_V), V4Mul(extentsXZY_V, fdirZYX_V));
|
||||
|
||||
#ifdef NEW_VERSION
|
||||
__m128 absfV = _mm_and_ps(fV, SSE_CONSTF(maskV));
|
||||
#else
|
||||
Vec4V absfV = V4Abs(fV);
|
||||
#endif
|
||||
const BoolV resfV = V4IsGrtr(absfV, fg);
|
||||
const PxU32 test2 = BGetBitMask(resfV);
|
||||
if(test2&7)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static PX_FORCE_INLINE /*PX_NOINLINE*/ PxIntBool BV4_SegmentAABBOverlap(const PxVec3& center, const PxVec3& extents, const RayParams* PX_RESTRICT params)
|
||||
{
|
||||
const PxU32 maskI = 0x7fffffff;
|
||||
|
||||
const Vec4V fdirV = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const Vec4V extentsV = V4LoadU(&extents.x);
|
||||
|
||||
const Vec4V DV = V4Sub(V4LoadA_Safe(¶ms->mData2_PaddedAligned.x), V4LoadU(¢er.x)); //###center should be aligned
|
||||
|
||||
__m128 absDV = _mm_and_ps(DV, _mm_load1_ps((float*)&maskI));
|
||||
|
||||
absDV = _mm_cmpgt_ps(absDV, V4Add(extentsV, fdirV));
|
||||
const PxU32 test = (PxU32)_mm_movemask_ps(absDV);
|
||||
if(test&7)
|
||||
return 0;
|
||||
|
||||
if(1)
|
||||
{
|
||||
const Vec4V dataZYX_V = V4LoadA_Safe(¶ms->mData_PaddedAligned.x);
|
||||
const __m128 dataXZY_V = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(dataZYX_V), _MM_SHUFFLE(3,0,2,1)));
|
||||
const __m128 DXZY_V = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(DV), _MM_SHUFFLE(3,0,2,1)));
|
||||
const Vec4V fV = V4Sub(V4Mul(dataZYX_V, DXZY_V), V4Mul(dataXZY_V, DV));
|
||||
|
||||
const Vec4V fdirZYX_V = V4LoadA_Safe(¶ms->mFDir_PaddedAligned.x);
|
||||
const __m128 fdirXZY_V = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(fdirZYX_V), _MM_SHUFFLE(3,0,2,1)));
|
||||
const __m128 extentsXZY_V = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(extentsV), _MM_SHUFFLE(3,0,2,1)));
|
||||
// PT: TODO: use V4MulAdd here (TA34704)
|
||||
const Vec4V fg = V4Add(V4Mul(extentsV, fdirXZY_V), V4Mul(extentsXZY_V, fdirZYX_V));
|
||||
|
||||
__m128 absfV = _mm_and_ps(fV, _mm_load1_ps((float*)&maskI));
|
||||
absfV = _mm_cmpgt_ps(absfV, fg);
|
||||
const PxU32 test2 = (PxU32)_mm_movemask_ps(absfV);
|
||||
if(test2&7)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
PxIntBool BV4_RaycastSingle(const PxVec3& origin, const PxVec3& dir, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxGeomRaycastHit* PX_RESTRICT hit, float maxDist, float geomEpsilon, PxU32 flags, PxHitFlags hitFlags)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
RayParams_Raycast Params;
|
||||
setupRayParams(&Params, origin, dir, &tree, worldm_Aligned, mesh, maxDist, geomEpsilon, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(Params.mEarlyExit)
|
||||
processStreamRayNoOrder<0, LeafFunction_RaycastAny>(tree, &Params);
|
||||
else
|
||||
processStreamRayOrdered<0, LeafFunction_RaycastClosest>(tree, &Params);
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_RaycastAny, LeafFunction_RaycastClosest>(mesh->getNbTriangles(), &Params);
|
||||
|
||||
return computeImpactData(hit, &Params, worldm_Aligned, hitFlags);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Callback-based version
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RayParamsCB : RayParams_Raycast
|
||||
{
|
||||
MeshRayCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
class LeafFunction_RaycastCB
|
||||
{
|
||||
public:
|
||||
static PxIntBool doLeafTest(RayParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
PX_ALIGN_PREFIX(16) char buffer[sizeof(PxGeomRaycastHit)] PX_ALIGN_SUFFIX(16);
|
||||
PxGeomRaycastHit& StabbedFace = reinterpret_cast<PxGeomRaycastHit&>(buffer);
|
||||
if(RayTriOverlapT<RayParams_Raycast>(StabbedFace, p0, p1, p2, params))
|
||||
{
|
||||
#ifndef TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
if(StabbedFace.distance<params->mStabbedFace.mDistance)
|
||||
#endif
|
||||
{
|
||||
HitCode Code = (params->mCallback)(params->mUserData, p0, p1, p2, primIndex, StabbedFace.distance, StabbedFace.u, StabbedFace.v);
|
||||
if(Code==HIT_EXIT)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// PT: TODO: no shrinking here? (TA34704)
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include "GuBV4_ProcessStreamNoOrder_SegmentAABB.h"
|
||||
|
||||
void BV4_RaycastCB(const PxVec3& origin, const PxVec3& dir, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, float maxDist, float geomEpsilon, PxU32 flags, MeshRayCallback callback, void* userData)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
//### beware, some parameters in the struct aren't used
|
||||
RayParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
setupRayParams(&Params, origin, dir, &tree, worldm_Aligned, mesh, maxDist, geomEpsilon, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
processStreamRayNoOrder<0, LeafFunction_RaycastCB>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
// if(Params.mEarlyExit)
|
||||
// LeafFunction_BoxSweepAnyCB::doLeafTest(&Params, nbTris);
|
||||
// else
|
||||
LeafFunction_RaycastCB::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
// Raycast all
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RayParamsAll : RayParams_Raycast
|
||||
{
|
||||
PX_FORCE_INLINE RayParamsAll(PxGeomRaycastHit* hits, PxU32 maxNbHits, PxU32 stride, const PxMat44* mat, PxHitFlags hitFlags) :
|
||||
mHits (reinterpret_cast<PxU8*>(hits)),
|
||||
mNbHits (0),
|
||||
mMaxNbHits (maxNbHits),
|
||||
mStride (stride),
|
||||
mWorld_Aligned (mat),
|
||||
mHitFlags (hitFlags)
|
||||
{
|
||||
}
|
||||
|
||||
PxU8* mHits;
|
||||
PxU32 mNbHits;
|
||||
const PxU32 mMaxNbHits;
|
||||
const PxU32 mStride;
|
||||
const PxMat44* mWorld_Aligned;
|
||||
const PxHitFlags mHitFlags;
|
||||
|
||||
PX_NOCOPY(RayParamsAll)
|
||||
};
|
||||
|
||||
class LeafFunction_RaycastAll
|
||||
{
|
||||
public:
|
||||
static /*PX_FORCE_INLINE*/ PxIntBool doLeafTest(RayParams_Raycast* PX_RESTRICT p, PxU32 primIndex)
|
||||
{
|
||||
RayParamsAll* params = static_cast<RayParamsAll*>(p);
|
||||
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
PxGeomRaycastHit& StabbedFace = *reinterpret_cast<PxGeomRaycastHit*>(params->mHits);
|
||||
if(RayTriOverlapT<RayParams_Raycast>(StabbedFace, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], params))
|
||||
{
|
||||
#ifndef TEST_DISTANCE_INSIDE_RAY_TRI
|
||||
if(StabbedFace.distance<params->mStabbedFace.mDistance)
|
||||
#endif
|
||||
{
|
||||
updateParamsAfterImpact(params, primIndex, VRef0, VRef1, VRef2, StabbedFace);
|
||||
|
||||
computeImpactData(&StabbedFace, params, params->mWorld_Aligned, params->mHitFlags);
|
||||
|
||||
params->mNbHits++;
|
||||
params->mHits += params->mStride;
|
||||
if(params->mNbHits==params->mMaxNbHits)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PT: this function is not used yet, but eventually it should be
|
||||
PxU32 BV4_RaycastAll(const PxVec3& origin, const PxVec3& dir, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxGeomRaycastHit* PX_RESTRICT hits, PxU32 maxNbHits, PxU32 stride, float maxDist, float geomEpsilon, PxU32 flags, PxHitFlags hitFlags)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
RayParamsAll Params(hits, maxNbHits, stride, worldm_Aligned, hitFlags);
|
||||
setupRayParams(&Params, origin, dir, &tree, worldm_Aligned, mesh, maxDist, geomEpsilon, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
processStreamRayNoOrder<0, LeafFunction_RaycastAll>(tree, &Params);
|
||||
else
|
||||
{
|
||||
PX_ASSERT(0);
|
||||
}
|
||||
return Params.mNbHits;
|
||||
}
|
||||
|
||||
176
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs.h
vendored
Normal file
176
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_SLABS_H
|
||||
#define GU_BV4_SLABS_H
|
||||
|
||||
#include "foundation/PxFPU.h"
|
||||
#include "GuBV4_Common.h"
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
|
||||
// PT: contains code for tree-traversal using the swizzled format.
|
||||
// PT: ray traversal based on Kay & Kajiya's slab intersection code, but using SIMD to do 4 ray-vs-AABB tests at a time.
|
||||
// PT: other (ordered or unordered) traversals just process one node at a time, similar to the non-swizzled format.
|
||||
|
||||
#define BV4_SLABS_FIX
|
||||
#define BV4_SLABS_SORT
|
||||
|
||||
#define PNS_BLOCK3(a, b, c, d) { \
|
||||
if(code2 & (1<<a)) { stack[nb++] = tn->getChildData(a); } \
|
||||
if(code2 & (1<<b)) { stack[nb++] = tn->getChildData(b); } \
|
||||
if(code2 & (1<<c)) { stack[nb++] = tn->getChildData(c); } \
|
||||
if(code2 & (1<<d)) { stack[nb++] = tn->getChildData(d); } } \
|
||||
|
||||
#define OPC_SLABS_GET_MIN_MAX(i) \
|
||||
const VecI32V minVi = I4LoadXYZW(node->mX[i].mMin, node->mY[i].mMin, node->mZ[i].mMin, 0); \
|
||||
const Vec4V minCoeffV = V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x); \
|
||||
Vec4V minV = V4Mul(Vec4V_From_VecI32V(minVi), minCoeffV); \
|
||||
const VecI32V maxVi = I4LoadXYZW(node->mX[i].mMax, node->mY[i].mMax, node->mZ[i].mMax, 0); \
|
||||
const Vec4V maxCoeffV = V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x); \
|
||||
Vec4V maxV = V4Mul(Vec4V_From_VecI32V(maxVi), maxCoeffV); \
|
||||
|
||||
#define OPC_SLABS_GET_CEQ(i) \
|
||||
OPC_SLABS_GET_MIN_MAX(i) \
|
||||
const FloatV HalfV = FLoad(0.5f); \
|
||||
const Vec4V centerV = V4Scale(V4Add(maxV, minV), HalfV); \
|
||||
const Vec4V extentsV = V4Scale(V4Sub(maxV, minV), HalfV);
|
||||
|
||||
#define OPC_SLABS_GET_CE2Q(i) \
|
||||
OPC_SLABS_GET_MIN_MAX(i) \
|
||||
const Vec4V centerV = V4Add(maxV, minV); \
|
||||
const Vec4V extentsV = V4Sub(maxV, minV);
|
||||
|
||||
#define OPC_SLABS_GET_CENQ(i) \
|
||||
const FloatV HalfV = FLoad(0.5f); \
|
||||
const Vec4V minV = V4LoadXYZW(node->mMinX[i], node->mMinY[i], node->mMinZ[i], 0.0f); \
|
||||
const Vec4V maxV = V4LoadXYZW(node->mMaxX[i], node->mMaxY[i], node->mMaxZ[i], 0.0f); \
|
||||
const Vec4V centerV = V4Scale(V4Add(maxV, minV), HalfV); \
|
||||
const Vec4V extentsV = V4Scale(V4Sub(maxV, minV), HalfV);
|
||||
|
||||
#define OPC_SLABS_GET_CE2NQ(i) \
|
||||
const Vec4V minV = V4LoadXYZW(node->mMinX[i], node->mMinY[i], node->mMinZ[i], 0.0f); \
|
||||
const Vec4V maxV = V4LoadXYZW(node->mMaxX[i], node->mMaxY[i], node->mMaxZ[i], 0.0f); \
|
||||
const Vec4V centerV = V4Add(maxV, minV); \
|
||||
const Vec4V extentsV = V4Sub(maxV, minV);
|
||||
|
||||
#define OPC_DEQ4(part2xV, part1xV, mMember, minCoeff, maxCoeff) \
|
||||
{ \
|
||||
part2xV = V4LoadA(reinterpret_cast<const float*>(tn->mMember)); \
|
||||
part1xV = Vec4V_ReinterpretFrom_VecI32V(VecI32V_And(VecI32V_ReinterpretFrom_Vec4V(part2xV), I4Load(0x0000ffff))); \
|
||||
part1xV = Vec4V_ReinterpretFrom_VecI32V(VecI32V_RightShift(VecI32V_LeftShift(VecI32V_ReinterpretFrom_Vec4V(part1xV),16), 16)); \
|
||||
part1xV = V4Mul(Vec4V_From_VecI32V(VecI32V_ReinterpretFrom_Vec4V(part1xV)), minCoeff); \
|
||||
part2xV = Vec4V_ReinterpretFrom_VecI32V(VecI32V_RightShift(VecI32V_ReinterpretFrom_Vec4V(part2xV), 16)); \
|
||||
part2xV = V4Mul(Vec4V_From_VecI32V(VecI32V_ReinterpretFrom_Vec4V(part2xV)), maxCoeff); \
|
||||
}
|
||||
|
||||
#define SLABS_INIT\
|
||||
Vec4V maxT4 = V4Load(params->mStabbedFace.mDistance);\
|
||||
const Vec4V rayP = V4LoadU_Safe(¶ms->mOrigin_Padded.x);\
|
||||
Vec4V rayD = V4LoadU_Safe(¶ms->mLocalDir_Padded.x);\
|
||||
const VecU32V raySign = V4U32and(VecU32V_ReinterpretFrom_Vec4V(rayD), signMask);\
|
||||
const Vec4V rayDAbs = V4Abs(rayD);\
|
||||
Vec4V rayInvD = Vec4V_ReinterpretFrom_VecU32V(V4U32or(raySign, VecU32V_ReinterpretFrom_Vec4V(V4Max(rayDAbs, epsFloat4))));\
|
||||
rayD = rayInvD;\
|
||||
rayInvD = V4RecipFast(rayInvD);\
|
||||
rayInvD = V4Mul(rayInvD, V4NegMulSub(rayD, rayInvD, twos));\
|
||||
const Vec4V rayPinvD = V4NegMulSub(rayInvD, rayP, zeroes);\
|
||||
const Vec4V rayInvDsplatX = V4SplatElement<0>(rayInvD);\
|
||||
const Vec4V rayInvDsplatY = V4SplatElement<1>(rayInvD);\
|
||||
const Vec4V rayInvDsplatZ = V4SplatElement<2>(rayInvD);\
|
||||
const Vec4V rayPinvDsplatX = V4SplatElement<0>(rayPinvD);\
|
||||
const Vec4V rayPinvDsplatY = V4SplatElement<1>(rayPinvD);\
|
||||
const Vec4V rayPinvDsplatZ = V4SplatElement<2>(rayPinvD);
|
||||
|
||||
#define SLABS_TEST\
|
||||
const Vec4V tminxa0 = V4MulAdd(minx4a, rayInvDsplatX, rayPinvDsplatX);\
|
||||
const Vec4V tminya0 = V4MulAdd(miny4a, rayInvDsplatY, rayPinvDsplatY);\
|
||||
const Vec4V tminza0 = V4MulAdd(minz4a, rayInvDsplatZ, rayPinvDsplatZ);\
|
||||
const Vec4V tmaxxa0 = V4MulAdd(maxx4a, rayInvDsplatX, rayPinvDsplatX);\
|
||||
const Vec4V tmaxya0 = V4MulAdd(maxy4a, rayInvDsplatY, rayPinvDsplatY);\
|
||||
const Vec4V tmaxza0 = V4MulAdd(maxz4a, rayInvDsplatZ, rayPinvDsplatZ);\
|
||||
const Vec4V tminxa = V4Min(tminxa0, tmaxxa0);\
|
||||
const Vec4V tmaxxa = V4Max(tminxa0, tmaxxa0);\
|
||||
const Vec4V tminya = V4Min(tminya0, tmaxya0);\
|
||||
const Vec4V tmaxya = V4Max(tminya0, tmaxya0);\
|
||||
const Vec4V tminza = V4Min(tminza0, tmaxza0);\
|
||||
const Vec4V tmaxza = V4Max(tminza0, tmaxza0);\
|
||||
const Vec4V maxOfNeasa = V4Max(V4Max(tminxa, tminya), tminza);\
|
||||
const Vec4V minOfFarsa = V4Min(V4Min(tmaxxa, tmaxya), tmaxza);\
|
||||
|
||||
#define SLABS_TEST2\
|
||||
BoolV ignore4a = V4IsGrtr(epsFloat4, minOfFarsa); /* if tfar is negative, ignore since its a ray, not a line */\
|
||||
ignore4a = BOr(ignore4a, V4IsGrtr(maxOfNeasa, maxT4)); /* if tnear is over maxT, ignore this result */\
|
||||
BoolV resa4 = V4IsGrtr(maxOfNeasa, minOfFarsa); /* if 1 => fail */\
|
||||
resa4 = BOr(resa4, ignore4a);\
|
||||
const PxU32 code = BGetBitMask(resa4);\
|
||||
if(code==15)\
|
||||
continue;
|
||||
|
||||
#define SLABS_PNS \
|
||||
if(code2) \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(0) & dirMask) \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(1) & dirMask) \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(2) & dirMask) \
|
||||
PNS_BLOCK3(3,2,1,0) \
|
||||
else \
|
||||
PNS_BLOCK3(2,3,1,0) \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(2) & dirMask) \
|
||||
PNS_BLOCK3(3,2,0,1) \
|
||||
else \
|
||||
PNS_BLOCK3(2,3,0,1) \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(1) & dirMask) \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(2) & dirMask) \
|
||||
PNS_BLOCK3(1,0,3,2) \
|
||||
else \
|
||||
PNS_BLOCK3(1,0,2,3) \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if(tn->decodePNSNoShift(2) & dirMask) \
|
||||
PNS_BLOCK3(0,1,3,2) \
|
||||
else \
|
||||
PNS_BLOCK3(0,1,2,3) \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif // GU_BV4_USE_SLABS
|
||||
|
||||
#endif // GU_BV4_SLABS_H
|
||||
305
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_KajiyaNoOrder.h
vendored
Normal file
305
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_KajiyaNoOrder.h
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
// 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_BV4_SLABS_KAJIYA_NO_ORDER_H
|
||||
#define GU_BV4_SLABS_KAJIYA_NO_ORDER_H
|
||||
|
||||
#include "GuBVConstants.h"
|
||||
|
||||
#ifdef REMOVED
|
||||
// Kajiya, no sort
|
||||
template<int inflateT, class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamKajiyaNoOrder(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
///
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
if(inflateT)
|
||||
{
|
||||
Vec4V fattenAABBs4 = V4LoadU_Safe(¶ms->mOriginalExtents_Padded.x);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
SLABS_INIT
|
||||
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
const Vec4V minCoeffV = V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x);
|
||||
const Vec4V maxCoeffV = V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x);
|
||||
const Vec4V minCoeffxV = V4SplatElement<0>(minCoeffV);
|
||||
const Vec4V minCoeffyV = V4SplatElement<1>(minCoeffV);
|
||||
const Vec4V minCoeffzV = V4SplatElement<2>(minCoeffV);
|
||||
const Vec4V maxCoeffxV = V4SplatElement<0>(maxCoeffV);
|
||||
const Vec4V maxCoeffyV = V4SplatElement<1>(maxCoeffV);
|
||||
const Vec4V maxCoeffzV = V4SplatElement<2>(maxCoeffV);
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzled* tn = reinterpret_cast<const BVDataSwizzled*>(node);
|
||||
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
Vec4V minx4a;
|
||||
Vec4V maxx4a;
|
||||
OPC_DEQ4(maxx4a, minx4a, mX, minCoeffxV, maxCoeffxV)
|
||||
|
||||
Vec4V miny4a;
|
||||
Vec4V maxy4a;
|
||||
OPC_DEQ4(maxy4a, miny4a, mY, minCoeffyV, maxCoeffyV)
|
||||
|
||||
Vec4V minz4a;
|
||||
Vec4V maxz4a;
|
||||
OPC_DEQ4(maxz4a, minz4a, mZ, minCoeffzV, maxCoeffzV)
|
||||
#else
|
||||
Vec4V minx4a = V4LoadA(tn->mMinX);
|
||||
Vec4V miny4a = V4LoadA(tn->mMinY);
|
||||
Vec4V minz4a = V4LoadA(tn->mMinZ);
|
||||
|
||||
Vec4V maxx4a = V4LoadA(tn->mMaxX);
|
||||
Vec4V maxy4a = V4LoadA(tn->mMaxY);
|
||||
Vec4V maxz4a = V4LoadA(tn->mMaxZ);
|
||||
#endif
|
||||
if(inflateT)
|
||||
{
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
SLABS_TEST
|
||||
|
||||
SLABS_TEST2
|
||||
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
if(LeafTestT::doLeafTest(params, tn->getPrimitive(x))) \
|
||||
return 1; \
|
||||
} \
|
||||
else \
|
||||
stack[nb++] = tn->getChildData(x);}
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef DO_LEAF_TEST
|
||||
#endif
|
||||
|
||||
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
if(LeafTestT::doLeafTest(params, tn->getPrimitive(x))) \
|
||||
return 1; \
|
||||
} \
|
||||
else \
|
||||
stack[nb++] = tn->getChildData(x);}
|
||||
|
||||
|
||||
// Kajiya, no sort
|
||||
template<int inflateT, class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamKajiyaNoOrderQ(const BVDataPackedQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
///
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
if(inflateT)
|
||||
{
|
||||
Vec4V fattenAABBs4 = V4LoadU_Safe(¶ms->mOriginalExtents_Padded.x);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
SLABS_INIT
|
||||
|
||||
const Vec4V minCoeffV = V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x);
|
||||
const Vec4V maxCoeffV = V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x);
|
||||
const Vec4V minCoeffxV = V4SplatElement<0>(minCoeffV);
|
||||
const Vec4V minCoeffyV = V4SplatElement<1>(minCoeffV);
|
||||
const Vec4V minCoeffzV = V4SplatElement<2>(minCoeffV);
|
||||
const Vec4V maxCoeffxV = V4SplatElement<0>(maxCoeffV);
|
||||
const Vec4V maxCoeffyV = V4SplatElement<1>(maxCoeffV);
|
||||
const Vec4V maxCoeffzV = V4SplatElement<2>(maxCoeffV);
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledQ* tn = reinterpret_cast<const BVDataSwizzledQ*>(node);
|
||||
|
||||
Vec4V minx4a;
|
||||
Vec4V maxx4a;
|
||||
OPC_DEQ4(maxx4a, minx4a, mX, minCoeffxV, maxCoeffxV)
|
||||
|
||||
Vec4V miny4a;
|
||||
Vec4V maxy4a;
|
||||
OPC_DEQ4(maxy4a, miny4a, mY, minCoeffyV, maxCoeffyV)
|
||||
|
||||
Vec4V minz4a;
|
||||
Vec4V maxz4a;
|
||||
OPC_DEQ4(maxz4a, minz4a, mZ, minCoeffzV, maxCoeffzV)
|
||||
|
||||
if(inflateT)
|
||||
{
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
SLABS_TEST
|
||||
|
||||
SLABS_TEST2
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Kajiya, no sort
|
||||
template<int inflateT, class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamKajiyaNoOrderNQ(const BVDataPackedNQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedNQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
///
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
if(inflateT)
|
||||
{
|
||||
Vec4V fattenAABBs4 = V4LoadU_Safe(¶ms->mOriginalExtents_Padded.x);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
SLABS_INIT
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledNQ* tn = reinterpret_cast<const BVDataSwizzledNQ*>(node);
|
||||
|
||||
Vec4V minx4a = V4LoadA(tn->mMinX);
|
||||
Vec4V miny4a = V4LoadA(tn->mMinY);
|
||||
Vec4V minz4a = V4LoadA(tn->mMinZ);
|
||||
|
||||
Vec4V maxx4a = V4LoadA(tn->mMaxX);
|
||||
Vec4V maxy4a = V4LoadA(tn->mMaxY);
|
||||
Vec4V maxz4a = V4LoadA(tn->mMaxZ);
|
||||
|
||||
if(inflateT)
|
||||
{
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
SLABS_TEST
|
||||
|
||||
SLABS_TEST2
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#undef DO_LEAF_TEST
|
||||
|
||||
#endif // GU_BV4_SLABS_KAJIYA_NO_ORDER_H
|
||||
570
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_KajiyaOrdered.h
vendored
Normal file
570
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_KajiyaOrdered.h
vendored
Normal file
@@ -0,0 +1,570 @@
|
||||
// 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_BV4_SLABS_KAJIYA_ORDERED_H
|
||||
#define GU_BV4_SLABS_KAJIYA_ORDERED_H
|
||||
|
||||
#include "GuBVConstants.h"
|
||||
|
||||
#ifdef REMOVED
|
||||
// Kajiya + PNS
|
||||
template<const int inflateT, class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamKajiyaOrdered(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
const PxU32* tmp = reinterpret_cast<const PxU32*>(¶ms->mLocalDir_Padded);
|
||||
const PxU32 X = tmp[0]>>31;
|
||||
const PxU32 Y = tmp[1]>>31;
|
||||
const PxU32 Z = tmp[2]>>31;
|
||||
// const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
// const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
// const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
#endif
|
||||
|
||||
#ifdef BV4_SLABS_FIX
|
||||
BV4_ALIGN16(float distances4[4]);
|
||||
#endif
|
||||
///
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
if(inflateT)
|
||||
{
|
||||
Vec4V fattenAABBs4 = V4LoadU_Safe(¶ms->mOriginalExtents_Padded.x);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
SLABS_INIT
|
||||
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
const Vec4V minCoeffV = V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x);
|
||||
const Vec4V maxCoeffV = V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x);
|
||||
const Vec4V minCoeffxV = V4SplatElement<0>(minCoeffV);
|
||||
const Vec4V minCoeffyV = V4SplatElement<1>(minCoeffV);
|
||||
const Vec4V minCoeffzV = V4SplatElement<2>(minCoeffV);
|
||||
const Vec4V maxCoeffxV = V4SplatElement<0>(maxCoeffV);
|
||||
const Vec4V maxCoeffyV = V4SplatElement<1>(maxCoeffV);
|
||||
const Vec4V maxCoeffzV = V4SplatElement<2>(maxCoeffV);
|
||||
#endif
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzled* tn = reinterpret_cast<const BVDataSwizzled*>(node);
|
||||
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
Vec4V minx4a;
|
||||
Vec4V maxx4a;
|
||||
OPC_DEQ4(maxx4a, minx4a, mX, minCoeffxV, maxCoeffxV)
|
||||
|
||||
Vec4V miny4a;
|
||||
Vec4V maxy4a;
|
||||
OPC_DEQ4(maxy4a, miny4a, mY, minCoeffyV, maxCoeffyV)
|
||||
|
||||
Vec4V minz4a;
|
||||
Vec4V maxz4a;
|
||||
OPC_DEQ4(maxz4a, minz4a, mZ, minCoeffzV, maxCoeffzV)
|
||||
#else
|
||||
Vec4V minx4a = V4LoadA(tn->mMinX);
|
||||
Vec4V miny4a = V4LoadA(tn->mMinY);
|
||||
Vec4V minz4a = V4LoadA(tn->mMinZ);
|
||||
|
||||
Vec4V maxx4a = V4LoadA(tn->mMaxX);
|
||||
Vec4V maxy4a = V4LoadA(tn->mMaxY);
|
||||
Vec4V maxz4a = V4LoadA(tn->mMaxZ);
|
||||
#endif
|
||||
if(inflateT)
|
||||
{
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
SLABS_TEST
|
||||
|
||||
#ifdef BV4_SLABS_FIX
|
||||
if(inflateT)
|
||||
V4StoreA(maxOfNeasa, &distances4[0]);
|
||||
#endif
|
||||
|
||||
SLABS_TEST2
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
#ifdef BV4_SLABS_FIX
|
||||
// PT: for some unknown reason the Linux/OSX compilers fail to understand this version
|
||||
/* #define DO_LEAF_TEST(x) \
|
||||
{ \
|
||||
if(!inflateT) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if(distances4[x]<params->mStabbedFace.mDistance) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}*/
|
||||
|
||||
// PT: TODO: check that this version compiles to the same code as above. Redo benchmarks.
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{ \
|
||||
if(!inflateT || distances4[x]<params->mStabbedFace.mDistance + GU_EPSILON_SAME_DISTANCE) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
PxU32 code2 = 0;
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
|
||||
SLABS_PNS
|
||||
#else
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
stack[nb++] = tn->getChildData(x); \
|
||||
}}
|
||||
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
#endif
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
#undef DO_LEAF_TEST
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
#ifdef BV4_SLABS_FIX
|
||||
// PT: for some unknown reason the Linux/OSX compilers fail to understand this version
|
||||
/* #define DO_LEAF_TEST(x) \
|
||||
{ \
|
||||
if(!inflateT) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if(distances4[x]<params->mStabbedFace.mDistance) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}*/
|
||||
|
||||
// PT: TODO: check that this version compiles to the same code as above. Redo benchmarks.
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{ \
|
||||
if(!inflateT || distances4[x]<params->mStabbedFace.mDistance + GU_EPSILON_SAME_DISTANCE) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; nbHits++; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#else
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{ \
|
||||
if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
code2 |= 1<<x; nbHits++; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#define DO_LEAF_TEST(x) \
|
||||
{if(tn->isLeaf(x)) \
|
||||
{ \
|
||||
LeafTestT::doLeafTest(params, tn->getPrimitive(x)); \
|
||||
maxT4 = V4Load(params->mStabbedFace.mDistance); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
stack[nb++] = tn->getChildData(x); \
|
||||
}}
|
||||
#endif
|
||||
|
||||
// Kajiya + PNS
|
||||
template<const int inflateT, class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamKajiyaOrderedQ(const BVDataPackedQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
const PxU32* tmp = reinterpret_cast<const PxU32*>(¶ms->mLocalDir_Padded);
|
||||
const PxU32 X = tmp[0]>>31;
|
||||
const PxU32 Y = tmp[1]>>31;
|
||||
const PxU32 Z = tmp[2]>>31;
|
||||
// const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
// const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
// const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
#endif
|
||||
|
||||
#ifdef BV4_SLABS_FIX
|
||||
BV4_ALIGN16(float distances4[4]);
|
||||
#endif
|
||||
///
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
if(inflateT)
|
||||
{
|
||||
Vec4V fattenAABBs4 = V4LoadU_Safe(¶ms->mOriginalExtents_Padded.x);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
SLABS_INIT
|
||||
|
||||
const Vec4V minCoeffV = V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x);
|
||||
const Vec4V maxCoeffV = V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x);
|
||||
const Vec4V minCoeffxV = V4SplatElement<0>(minCoeffV);
|
||||
const Vec4V minCoeffyV = V4SplatElement<1>(minCoeffV);
|
||||
const Vec4V minCoeffzV = V4SplatElement<2>(minCoeffV);
|
||||
const Vec4V maxCoeffxV = V4SplatElement<0>(maxCoeffV);
|
||||
const Vec4V maxCoeffyV = V4SplatElement<1>(maxCoeffV);
|
||||
const Vec4V maxCoeffzV = V4SplatElement<2>(maxCoeffV);
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledQ* tn = reinterpret_cast<const BVDataSwizzledQ*>(node);
|
||||
|
||||
Vec4V minx4a;
|
||||
Vec4V maxx4a;
|
||||
OPC_DEQ4(maxx4a, minx4a, mX, minCoeffxV, maxCoeffxV)
|
||||
|
||||
Vec4V miny4a;
|
||||
Vec4V maxy4a;
|
||||
OPC_DEQ4(maxy4a, miny4a, mY, minCoeffyV, maxCoeffyV)
|
||||
|
||||
Vec4V minz4a;
|
||||
Vec4V maxz4a;
|
||||
OPC_DEQ4(maxz4a, minz4a, mZ, minCoeffzV, maxCoeffzV)
|
||||
|
||||
if(inflateT)
|
||||
{
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
SLABS_TEST
|
||||
|
||||
#ifdef BV4_SLABS_FIX
|
||||
if(inflateT)
|
||||
V4StoreA(maxOfNeasa, &distances4[0]);
|
||||
#endif
|
||||
|
||||
SLABS_TEST2
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
PxU32 code2 = 0;
|
||||
PxU32 nbHits = 0;
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
|
||||
//SLABS_PNS
|
||||
|
||||
if(nbHits==1)
|
||||
{
|
||||
PNS_BLOCK3(0,1,2,3)
|
||||
}
|
||||
else
|
||||
{
|
||||
SLABS_PNS
|
||||
}
|
||||
#else
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
#endif
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
|
||||
|
||||
// Kajiya + PNS
|
||||
template<const int inflateT, class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamKajiyaOrderedNQ(const BVDataPackedNQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedNQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
const PxU32* tmp = reinterpret_cast<const PxU32*>(¶ms->mLocalDir_Padded);
|
||||
const PxU32 X = tmp[0]>>31;
|
||||
const PxU32 Y = tmp[1]>>31;
|
||||
const PxU32 Z = tmp[2]>>31;
|
||||
// const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
// const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
// const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
#endif
|
||||
|
||||
#ifdef BV4_SLABS_FIX
|
||||
BV4_ALIGN16(float distances4[4]);
|
||||
#endif
|
||||
///
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
if(inflateT)
|
||||
{
|
||||
Vec4V fattenAABBs4 = V4LoadU_Safe(¶ms->mOriginalExtents_Padded.x);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
SLABS_INIT
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledNQ* tn = reinterpret_cast<const BVDataSwizzledNQ*>(node);
|
||||
|
||||
Vec4V minx4a = V4LoadA(tn->mMinX);
|
||||
Vec4V miny4a = V4LoadA(tn->mMinY);
|
||||
Vec4V minz4a = V4LoadA(tn->mMinZ);
|
||||
|
||||
Vec4V maxx4a = V4LoadA(tn->mMaxX);
|
||||
Vec4V maxy4a = V4LoadA(tn->mMaxY);
|
||||
Vec4V maxz4a = V4LoadA(tn->mMaxZ);
|
||||
|
||||
if(inflateT)
|
||||
{
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
SLABS_TEST
|
||||
|
||||
#ifdef BV4_SLABS_FIX
|
||||
if(inflateT)
|
||||
V4StoreA(maxOfNeasa, &distances4[0]);
|
||||
#endif
|
||||
|
||||
SLABS_TEST2
|
||||
|
||||
#ifdef BV4_SLABS_SORT
|
||||
PxU32 code2 = 0;
|
||||
PxU32 nbHits = 0;
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
|
||||
//SLABS_PNS
|
||||
if(nbHits==1)
|
||||
{
|
||||
PNS_BLOCK3(0,1,2,3)
|
||||
}
|
||||
else
|
||||
{
|
||||
SLABS_PNS
|
||||
}
|
||||
#else
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
if(!(code&8) && nodeType>1)
|
||||
DO_LEAF_TEST(3)
|
||||
|
||||
if(!(code&4) && nodeType>0)
|
||||
DO_LEAF_TEST(2)
|
||||
|
||||
if(!(code&2))
|
||||
DO_LEAF_TEST(1)
|
||||
|
||||
if(!(code&1))
|
||||
DO_LEAF_TEST(0)
|
||||
#endif
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
|
||||
#undef DO_LEAF_TEST
|
||||
|
||||
#endif // GU_BV4_SLABS_KAJIYA_ORDERED_H
|
||||
129
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_SwizzledNoOrder.h
vendored
Normal file
129
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_SwizzledNoOrder.h
vendored
Normal file
@@ -0,0 +1,129 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_BV4_SLABS_SWIZZLED_NO_ORDER_H
|
||||
#define GU_BV4_SLABS_SWIZZLED_NO_ORDER_H
|
||||
|
||||
// Generic, no sort
|
||||
/* template<class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamSwizzledNoOrder(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzled* tn = reinterpret_cast<const BVDataSwizzled*>(node);
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(nodeType>1 && BV4_ProcessNodeNoOrder_Swizzled<LeafTestT, 3>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(nodeType>0 && BV4_ProcessNodeNoOrder_Swizzled<LeafTestT, 2>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder_Swizzled<LeafTestT, 1>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder_Swizzled<LeafTestT, 0>(stack, nb, tn, params))
|
||||
return 1;
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}*/
|
||||
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamSwizzledNoOrderQ(const BVDataPackedQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledQ* tn = reinterpret_cast<const BVDataSwizzledQ*>(node);
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(nodeType>1 && BV4_ProcessNodeNoOrder_SwizzledQ<LeafTestT, 3>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(nodeType>0 && BV4_ProcessNodeNoOrder_SwizzledQ<LeafTestT, 2>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder_SwizzledQ<LeafTestT, 1>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder_SwizzledQ<LeafTestT, 0>(stack, nb, tn, params))
|
||||
return 1;
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static PxIntBool BV4_ProcessStreamSwizzledNoOrderNQ(const BVDataPackedNQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedNQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledNQ* tn = reinterpret_cast<const BVDataSwizzledNQ*>(node);
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
if(nodeType>1 && BV4_ProcessNodeNoOrder_SwizzledNQ<LeafTestT, 3>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(nodeType>0 && BV4_ProcessNodeNoOrder_SwizzledNQ<LeafTestT, 2>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder_SwizzledNQ<LeafTestT, 1>(stack, nb, tn, params))
|
||||
return 1;
|
||||
if(BV4_ProcessNodeNoOrder_SwizzledNQ<LeafTestT, 0>(stack, nb, tn, params))
|
||||
return 1;
|
||||
|
||||
}while(nb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // GU_BV4_SLABS_SWIZZLED_NO_ORDER_H
|
||||
156
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_SwizzledOrdered.h
vendored
Normal file
156
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_Slabs_SwizzledOrdered.h
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
// 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_BV4_SLABS_SWIZZLED_ORDERED_H
|
||||
#define GU_BV4_SLABS_SWIZZLED_ORDERED_H
|
||||
|
||||
// Generic + PNS
|
||||
/* template<class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamSwizzledOrdered(const BVDataPacked* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPacked* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
const PxU32* tmp = reinterpret_cast<const PxU32*>(¶ms->mLocalDir_Padded);
|
||||
const PxU32 X = tmp[0]>>31;
|
||||
const PxU32 Y = tmp[1]>>31;
|
||||
const PxU32 Z = tmp[2]>>31;
|
||||
// const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
// const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
// const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
const BVDataSwizzled* tn = reinterpret_cast<const BVDataSwizzled*>(node);
|
||||
|
||||
PxU32 code2 = 0;
|
||||
BV4_ProcessNodeOrdered2_Swizzled<LeafTestT, 0>(code2, tn, params);
|
||||
BV4_ProcessNodeOrdered2_Swizzled<LeafTestT, 1>(code2, tn, params);
|
||||
if(nodeType>0)
|
||||
BV4_ProcessNodeOrdered2_Swizzled<LeafTestT, 2>(code2, tn, params);
|
||||
if(nodeType>1)
|
||||
BV4_ProcessNodeOrdered2_Swizzled<LeafTestT, 3>(code2, tn, params);
|
||||
|
||||
SLABS_PNS
|
||||
|
||||
}while(nb);
|
||||
}*/
|
||||
|
||||
// Generic + PNS
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamSwizzledOrderedQ(const BVDataPackedQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
const PxU32* tmp = reinterpret_cast<const PxU32*>(¶ms->mLocalDir_Padded);
|
||||
const PxU32 X = tmp[0]>>31;
|
||||
const PxU32 Y = tmp[1]>>31;
|
||||
const PxU32 Z = tmp[2]>>31;
|
||||
// const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
// const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
// const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
const BVDataSwizzledQ* tn = reinterpret_cast<const BVDataSwizzledQ*>(node);
|
||||
|
||||
PxU32 code2 = 0;
|
||||
BV4_ProcessNodeOrdered2_SwizzledQ<LeafTestT, 0>(code2, tn, params);
|
||||
BV4_ProcessNodeOrdered2_SwizzledQ<LeafTestT, 1>(code2, tn, params);
|
||||
if(nodeType>0)
|
||||
BV4_ProcessNodeOrdered2_SwizzledQ<LeafTestT, 2>(code2, tn, params);
|
||||
if(nodeType>1)
|
||||
BV4_ProcessNodeOrdered2_SwizzledQ<LeafTestT, 3>(code2, tn, params);
|
||||
|
||||
SLABS_PNS
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
|
||||
// Generic + PNS
|
||||
template<class LeafTestT, class ParamsT>
|
||||
static void BV4_ProcessStreamSwizzledOrderedNQ(const BVDataPackedNQ* PX_RESTRICT node, PxU32 initData, ParamsT* PX_RESTRICT params)
|
||||
{
|
||||
const BVDataPackedNQ* root = node;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
const PxU32* tmp = reinterpret_cast<const PxU32*>(¶ms->mLocalDir_Padded);
|
||||
const PxU32 X = tmp[0]>>31;
|
||||
const PxU32 Y = tmp[1]>>31;
|
||||
const PxU32 Z = tmp[2]>>31;
|
||||
// const PxU32 X = PX_IR(params->mLocalDir_Padded.x)>>31;
|
||||
// const PxU32 Y = PX_IR(params->mLocalDir_Padded.y)>>31;
|
||||
// const PxU32 Z = PX_IR(params->mLocalDir_Padded.z)>>31;
|
||||
const PxU32 bitIndex = 3+(Z|(Y<<1)|(X<<2));
|
||||
const PxU32 dirMask = 1u<<bitIndex;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
node = root + getChildOffset(childData);
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
const BVDataSwizzledNQ* tn = reinterpret_cast<const BVDataSwizzledNQ*>(node);
|
||||
|
||||
PxU32 code2 = 0;
|
||||
BV4_ProcessNodeOrdered2_SwizzledNQ<LeafTestT, 0>(code2, tn, params);
|
||||
BV4_ProcessNodeOrdered2_SwizzledNQ<LeafTestT, 1>(code2, tn, params);
|
||||
if(nodeType>0)
|
||||
BV4_ProcessNodeOrdered2_SwizzledNQ<LeafTestT, 2>(code2, tn, params);
|
||||
if(nodeType>1)
|
||||
BV4_ProcessNodeOrdered2_SwizzledNQ<LeafTestT, 3>(code2, tn, params);
|
||||
|
||||
SLABS_PNS
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
|
||||
|
||||
#endif // GU_BV4_SLABS_SWIZZLED_ORDERED_H
|
||||
617
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_SphereOverlap.cpp
vendored
Normal file
617
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_SphereOverlap.cpp
vendored
Normal file
@@ -0,0 +1,617 @@
|
||||
// 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 "GuBV4.h"
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#include "foundation/PxBasicTemplates.h"
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
|
||||
#include "GuBV4_Common.h"
|
||||
#include "GuSphere.h"
|
||||
#include "GuDistancePointTriangle.h"
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning ( disable : 4324 )
|
||||
#endif
|
||||
|
||||
// Sphere overlap any
|
||||
|
||||
struct SphereParams
|
||||
{
|
||||
const IndTri32* PX_RESTRICT mTris32;
|
||||
const IndTri16* PX_RESTRICT mTris16;
|
||||
const PxVec3* PX_RESTRICT mVerts;
|
||||
|
||||
BV4_ALIGN16(PxVec3p mCenterOrMinCoeff_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mExtentsOrMaxCoeff_PaddedAligned);
|
||||
|
||||
BV4_ALIGN16(PxVec3 mCenter_PaddedAligned); float mRadius2;
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
BV4_ALIGN16(PxVec3 mCenter_PaddedAligned2); float mRadius22;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
// PT: TODO: refactor with bucket pruner code (TA34704)
|
||||
static PX_FORCE_INLINE PxIntBool BV4_SphereAABBOverlap(const PxVec3& center, const PxVec3& extents, const SphereParams* PX_RESTRICT params)
|
||||
{
|
||||
const Vec4V mCenter = V4LoadA_Safe(¶ms->mCenter_PaddedAligned.x);
|
||||
const FloatV mRadius2 = FLoad(params->mRadius2);
|
||||
|
||||
const Vec4V boxCenter = V4LoadU(¢er.x);
|
||||
const Vec4V boxExtents = V4LoadU(&extents.x);
|
||||
|
||||
const Vec4V offset = V4Sub(mCenter, boxCenter);
|
||||
const Vec4V closest = V4Clamp(offset, V4Neg(boxExtents), boxExtents);
|
||||
const Vec4V d = V4Sub(offset, closest);
|
||||
|
||||
const PxU32 test = (PxU32)_mm_movemask_ps(FIsGrtrOrEq(mRadius2, V4Dot3(d, d)));
|
||||
return (test & 0x7) == 0x7;
|
||||
}
|
||||
#endif
|
||||
|
||||
static PX_FORCE_INLINE PxIntBool SphereTriangle(const SphereParams* PX_RESTRICT params, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2)
|
||||
{
|
||||
{
|
||||
const float sqrDist = (p0 - params->mCenter_PaddedAligned).magnitudeSquared();
|
||||
if(sqrDist <= params->mRadius2)
|
||||
return 1;
|
||||
}
|
||||
|
||||
const PxVec3 edge10 = p1 - p0;
|
||||
const PxVec3 edge20 = p2 - p0;
|
||||
const PxVec3 cp = closestPtPointTriangle2(params->mCenter_PaddedAligned, p0, p1, p2, edge10, edge20);
|
||||
const float sqrDist = (cp - params->mCenter_PaddedAligned).magnitudeSquared();
|
||||
return sqrDist <= params->mRadius2;
|
||||
}
|
||||
|
||||
// PT: TODO: evaluate if SIMD distance function would be faster here (TA34704)
|
||||
// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
|
||||
static /*PX_FORCE_INLINE*/ PxIntBool /*__fastcall*/ SphereTriangle(const SphereParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
return SphereTriangle(params, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2]);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_SphereOverlapAny
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const SphereParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(SphereTriangle(params, primIndex))
|
||||
return 1;
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
static PX_FORCE_INLINE void setupSphereParams(ParamsT* PX_RESTRICT params, const Sphere& sphere, const BV4Tree* PX_RESTRICT tree, const PxMat44* PX_RESTRICT worldm_Aligned, const SourceMesh* PX_RESTRICT mesh)
|
||||
{
|
||||
computeLocalSphere(params->mRadius2, params->mCenter_PaddedAligned, sphere, worldm_Aligned);
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
params->mCenter_PaddedAligned2 = params->mCenter_PaddedAligned*2.0f;
|
||||
params->mRadius22 = params->mRadius2*4.0f;
|
||||
#endif
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
|
||||
static PX_FORCE_INLINE PxIntBool BV4_SphereAABBOverlap(const Vec4V boxCenter, const Vec4V boxExtents, const SphereParams* PX_RESTRICT params)
|
||||
{
|
||||
const Vec4V mCenter = V4LoadA_Safe(¶ms->mCenter_PaddedAligned2.x);
|
||||
const FloatV mRadius2 = FLoad(params->mRadius22);
|
||||
|
||||
const Vec4V offset = V4Sub(mCenter, boxCenter);
|
||||
const Vec4V closest = V4Clamp(offset, V4Neg(boxExtents), boxExtents);
|
||||
const Vec4V d = V4Sub(offset, closest);
|
||||
|
||||
const PxU32 test = BGetBitMask(FIsGrtrOrEq(mRadius2, V4Dot3(d, d)));
|
||||
return (test & 0x7) == 0x7;
|
||||
}
|
||||
#else
|
||||
#ifdef GU_BV4_QUANTIZED_TREE
|
||||
static PX_FORCE_INLINE PxIntBool BV4_SphereAABBOverlap(const BVDataPacked* PX_RESTRICT node, const SphereParams* PX_RESTRICT params)
|
||||
{
|
||||
const VecI32V testV = I4LoadA((const PxI32*)&node->mAABB.mData[0]);
|
||||
const VecI32V qextentsV = VecI32V_And(testV, I4LoadXYZW(0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff));
|
||||
const VecI32V qcenterV = VecI32V_RightShift(testV, 16);
|
||||
const Vec4V boxCenter = V4Mul(Vec4V_From_VecI32V(qcenterV), V4LoadA_Safe(¶ms->mCenterOrMinCoeff_PaddedAligned.x));
|
||||
const Vec4V boxExtents = V4Mul(Vec4V_From_VecI32V(qextentsV), V4LoadA_Safe(¶ms->mExtentsOrMaxCoeff_PaddedAligned.x));
|
||||
|
||||
const Vec4V mCenter = V4LoadA_Safe(¶ms->mCenter_PaddedAligned.x);
|
||||
const FloatV mRadius2 = FLoad(params->mRadius2);
|
||||
|
||||
const Vec4V offset = V4Sub(mCenter, boxCenter);
|
||||
const Vec4V closest = V4Clamp(offset, V4Neg(boxExtents), boxExtents);
|
||||
const Vec4V d = V4Sub(offset, closest);
|
||||
|
||||
const PxU32 test = BGetBitMask(FIsGrtrOrEq(mRadius2, V4Dot3(d, d)));
|
||||
return (test & 0x7) == 0x7;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "GuBV4_ProcessStreamNoOrder_SphereAABB.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_SwizzledNoOrder.h"
|
||||
#endif
|
||||
|
||||
#define GU_BV4_PROCESS_STREAM_NO_ORDER
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
PxIntBool BV4_OverlapSphereAny(const Sphere& sphere, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
SphereParams Params;
|
||||
setupSphereParams(&Params, sphere, &tree, worldm_Aligned, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
return processStreamNoOrder<LeafFunction_SphereOverlapAny>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbPrimitives();
|
||||
PX_ASSERT(nbTris<16);
|
||||
return LeafFunction_SphereOverlapAny::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
// Sphere overlap all
|
||||
|
||||
struct SphereParamsAll : SphereParams
|
||||
{
|
||||
PxU32 mNbHits;
|
||||
PxU32 mMaxNbHits;
|
||||
PxU32* mHits;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_SphereOverlapAll
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(SphereParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(SphereTriangle(params, primIndex))
|
||||
{
|
||||
SphereParamsAll* ParamsAll = static_cast<SphereParamsAll*>(params);
|
||||
if(ParamsAll->mNbHits==ParamsAll->mMaxNbHits)
|
||||
return 1;
|
||||
ParamsAll->mHits[ParamsAll->mNbHits] = primIndex;
|
||||
ParamsAll->mNbHits++;
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
PxU32 BV4_OverlapSphereAll(const Sphere& sphere, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxU32* results, PxU32 size, bool& overflow)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
SphereParamsAll Params;
|
||||
Params.mNbHits = 0;
|
||||
Params.mMaxNbHits = size;
|
||||
Params.mHits = results;
|
||||
|
||||
setupSphereParams(&Params, sphere, &tree, worldm_Aligned, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
overflow = processStreamNoOrder<LeafFunction_SphereOverlapAll>(tree, &Params)!=0;
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbPrimitives();
|
||||
PX_ASSERT(nbTris<16);
|
||||
overflow = LeafFunction_SphereOverlapAll::doLeafTest(&Params, nbTris)!=0;
|
||||
}
|
||||
return Params.mNbHits;
|
||||
}
|
||||
|
||||
|
||||
// Sphere overlap - callback version
|
||||
|
||||
struct SphereParamsCB : SphereParams
|
||||
{
|
||||
MeshOverlapCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_SphereOverlapCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(const SphereParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
if(SphereTriangle(params, p0, p1, p2))
|
||||
{
|
||||
const PxU32 vrefs[3] = { VRef0, VRef1, VRef2 };
|
||||
if((params->mCallback)(params->mUserData, p0, p1, p2, primIndex, vrefs))
|
||||
return 1;
|
||||
}
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PT: this one is currently not used
|
||||
void BV4_OverlapSphereCB(const Sphere& sphere, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, MeshOverlapCallback callback, void* userData)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
SphereParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
setupSphereParams(&Params, sphere, &tree, worldm_Aligned, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
processStreamNoOrder<LeafFunction_SphereOverlapCB>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
LeafFunction_SphereOverlapCB::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Point distance query
|
||||
// Implemented here as a variation on the sphere-overlap codepath
|
||||
|
||||
// TODO:
|
||||
// * visit closest nodes first
|
||||
// - revisit inlining
|
||||
// - lazy-compute final results
|
||||
// - SIMD
|
||||
// - return uvs
|
||||
// - maxDist input param
|
||||
|
||||
struct PointDistanceParams : SphereParams
|
||||
{
|
||||
PxVec3 mClosestPt;
|
||||
PxU32 mIndex;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_PointDistance
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(SphereParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
const PxVec3 edge10 = p1 - p0;
|
||||
const PxVec3 edge20 = p2 - p0;
|
||||
const PxVec3 cp = closestPtPointTriangle2(params->mCenter_PaddedAligned, p0, p1, p2, edge10, edge20);
|
||||
const float sqrDist = (cp - params->mCenter_PaddedAligned).magnitudeSquared();
|
||||
if(sqrDist <= params->mRadius2)
|
||||
{
|
||||
PointDistanceParams* Params = static_cast<PointDistanceParams*>(params);
|
||||
Params->mClosestPt = cp;
|
||||
Params->mIndex = primIndex;
|
||||
Params->mRadius2 = sqrDist;
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
Params->mRadius22 = sqrDist*4.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static PX_FORCE_INLINE PxIntBool BV4_SphereAABBOverlap2(const Vec4V boxCenter, const Vec4V boxExtents, const SphereParams* PX_RESTRICT params, float* PX_RESTRICT _d)
|
||||
{
|
||||
const Vec4V mCenter = V4LoadA_Safe(¶ms->mCenter_PaddedAligned2.x);
|
||||
const FloatV mRadius2 = FLoad(params->mRadius22);
|
||||
|
||||
const Vec4V offset = V4Sub(mCenter, boxCenter);
|
||||
const Vec4V closest = V4Clamp(offset, V4Neg(boxExtents), boxExtents);
|
||||
const Vec4V d = V4Sub(offset, closest);
|
||||
|
||||
const FloatV dot = V4Dot3(d, d);
|
||||
FStore(dot, _d);
|
||||
|
||||
const PxU32 test = BGetBitMask(FIsGrtrOrEq(mRadius2, dot));
|
||||
return (test & 0x7) == 0x7;
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeNoOrder_SwizzledQ2(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzledQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params, float* PX_RESTRICT _d)
|
||||
{
|
||||
OPC_SLABS_GET_CE2Q(i)
|
||||
|
||||
if(BV4_SphereAABBOverlap2(centerV, extentsV, params, _d))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
LeafTestT::doLeafTest(params, node->getPrimitive(i));
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
}
|
||||
|
||||
template<class LeafTestT, int i, class ParamsT>
|
||||
PX_FORCE_INLINE void BV4_ProcessNodeNoOrder_SwizzledNQ2(PxU32* PX_RESTRICT Stack, PxU32& Nb, const BVDataSwizzledNQ* PX_RESTRICT node, ParamsT* PX_RESTRICT params, float* PX_RESTRICT _d)
|
||||
{
|
||||
OPC_SLABS_GET_CE2NQ(i)
|
||||
|
||||
if(BV4_SphereAABBOverlap2(centerV, extentsV, params, _d))
|
||||
{
|
||||
if(node->isLeaf(i))
|
||||
{
|
||||
LeafTestT::doLeafTest(params, node->getPrimitive(i));
|
||||
}
|
||||
else
|
||||
Stack[Nb++] = node->getChildData(i);
|
||||
}
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE void sort(PxU32* next, float* di, PxU32 i, PxU32 j)
|
||||
{
|
||||
if(di[i]<di[j]) // PT: "wrong" side on purpose, it's a LIFO stack
|
||||
{
|
||||
PxSwap(next[i], next[j]);
|
||||
PxSwap(di[i], di[j]);
|
||||
}
|
||||
}
|
||||
|
||||
static PX_FORCE_INLINE void sortCandidates(PxU32 nbMore, PxU32* next, float* di, PxU32* stack, PxU32& nb)
|
||||
{
|
||||
// PT: this is not elegant and it looks slow, but for distance queries the time spent here is well worth it.
|
||||
if(0)
|
||||
{
|
||||
while(nbMore)
|
||||
{
|
||||
float minDist = di[0];
|
||||
PxU32 minIndex = 0;
|
||||
for(PxU32 i=1;i<nbMore;i++)
|
||||
{
|
||||
if(di[i]>minDist) // PT: "wrong" side on purpose, it's a LIFO stack
|
||||
{
|
||||
minDist = di[i];
|
||||
minIndex = i;
|
||||
}
|
||||
}
|
||||
stack[nb++] = next[minIndex];
|
||||
nbMore--;
|
||||
PxSwap(next[minIndex], next[nbMore]);
|
||||
PxSwap(di[minIndex], di[nbMore]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(nbMore)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
stack[nb++] = next[0];
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
sort(next, di, 0, 1);
|
||||
PX_ASSERT(di[0]>=di[1]);
|
||||
stack[nb++] = next[0];
|
||||
stack[nb++] = next[1];
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
sort(next, di, 0, 1);
|
||||
sort(next, di, 1, 2);
|
||||
sort(next, di, 0, 1);
|
||||
PX_ASSERT(di[0]>=di[1]);
|
||||
PX_ASSERT(di[1]>=di[2]);
|
||||
stack[nb++] = next[0];
|
||||
stack[nb++] = next[1];
|
||||
stack[nb++] = next[2];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
sort(next, di, 0, 1);
|
||||
sort(next, di, 2, 3);
|
||||
sort(next, di, 0, 2);
|
||||
sort(next, di, 1, 3);
|
||||
sort(next, di, 1, 2);
|
||||
PX_ASSERT(di[0]>=di[1]);
|
||||
PX_ASSERT(di[1]>=di[2]);
|
||||
PX_ASSERT(di[2]>=di[3]);
|
||||
stack[nb++] = next[0];
|
||||
stack[nb++] = next[1];
|
||||
stack[nb++] = next[2];
|
||||
stack[nb++] = next[3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BV4_PointDistance(const PxVec3& point, const BV4Tree& tree, float maxDist, PxU32& index, float& dist, PxVec3& cp/*, const PxMat44* PX_RESTRICT worldm_Aligned*/)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
const float limit = sqrtf(sqrtf(PX_MAX_F32));
|
||||
if(maxDist>limit)
|
||||
maxDist = limit;
|
||||
|
||||
PointDistanceParams Params;
|
||||
setupSphereParams(&Params, Sphere(point, maxDist), &tree, NULL/*worldm_Aligned*/, mesh);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(0)
|
||||
{
|
||||
// PT: unfortunately distance queries don't map nicely to the current BV4 framework
|
||||
// This works but it doesn't visit closest nodes first so it's suboptimal. We also
|
||||
// cannot use the ordered traversal since it's based on PNS, i.e. a fixed ray direction.
|
||||
processStreamNoOrder<LeafFunction_PointDistance>(tree, &Params);
|
||||
}
|
||||
|
||||
PxU32 initData = tree.mInitData;
|
||||
PointDistanceParams* PX_RESTRICT params = &Params;
|
||||
|
||||
if(tree.mQuantized)
|
||||
{
|
||||
const BVDataPackedQ* PX_RESTRICT nodes = reinterpret_cast<const BVDataPackedQ*>(tree.mNodes);
|
||||
|
||||
const BVDataPackedQ* root = nodes;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
nodes = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledQ* tn = reinterpret_cast<const BVDataSwizzledQ*>(nodes);
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
PxU32 nbMore=0;
|
||||
PxU32 next[4];
|
||||
float di[4];
|
||||
|
||||
if(nodeType>1)
|
||||
BV4_ProcessNodeNoOrder_SwizzledQ2<LeafFunction_PointDistance, 3>(next, nbMore, tn, params, &di[nbMore]);
|
||||
if(nodeType>0)
|
||||
BV4_ProcessNodeNoOrder_SwizzledQ2<LeafFunction_PointDistance, 2>(next, nbMore, tn, params, &di[nbMore]);
|
||||
BV4_ProcessNodeNoOrder_SwizzledQ2<LeafFunction_PointDistance, 1>(next, nbMore, tn, params, &di[nbMore]);
|
||||
BV4_ProcessNodeNoOrder_SwizzledQ2<LeafFunction_PointDistance, 0>(next, nbMore, tn, params, &di[nbMore]);
|
||||
|
||||
sortCandidates(nbMore, next, di, stack, nb);
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
else
|
||||
{
|
||||
const BVDataPackedNQ* PX_RESTRICT nodes = reinterpret_cast<const BVDataPackedNQ*>(tree.mNodes);
|
||||
|
||||
const BVDataPackedNQ* root = nodes;
|
||||
|
||||
PxU32 nb=1;
|
||||
PxU32 stack[GU_BV4_STACK_SIZE];
|
||||
stack[0] = initData;
|
||||
|
||||
do
|
||||
{
|
||||
const PxU32 childData = stack[--nb];
|
||||
nodes = root + getChildOffset(childData);
|
||||
|
||||
const BVDataSwizzledNQ* tn = reinterpret_cast<const BVDataSwizzledNQ*>(nodes);
|
||||
|
||||
const PxU32 nodeType = getChildType(childData);
|
||||
|
||||
PxU32 nbMore=0;
|
||||
PxU32 next[4];
|
||||
float di[4];
|
||||
|
||||
if(nodeType>1)
|
||||
BV4_ProcessNodeNoOrder_SwizzledNQ2<LeafFunction_PointDistance, 3>(next, nbMore, tn, params, &di[nbMore]);
|
||||
if(nodeType>0)
|
||||
BV4_ProcessNodeNoOrder_SwizzledNQ2<LeafFunction_PointDistance, 2>(next, nbMore, tn, params, &di[nbMore]);
|
||||
BV4_ProcessNodeNoOrder_SwizzledNQ2<LeafFunction_PointDistance, 1>(next, nbMore, tn, params, &di[nbMore]);
|
||||
BV4_ProcessNodeNoOrder_SwizzledNQ2<LeafFunction_PointDistance, 0>(next, nbMore, tn, params, &di[nbMore]);
|
||||
|
||||
sortCandidates(nbMore, next, di, stack, nb);
|
||||
|
||||
}while(nb);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
LeafFunction_PointDistance::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
|
||||
index = Params.mIndex;
|
||||
dist = sqrtf(Params.mRadius2);
|
||||
cp = Params.mClosestPt;
|
||||
}
|
||||
|
||||
391
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_SphereSweep.cpp
vendored
Normal file
391
engine/third_party/physx/source/geomutils/src/mesh/GuBV4_SphereSweep.cpp
vendored
Normal file
@@ -0,0 +1,391 @@
|
||||
// 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/PxSimpleTypes.h"
|
||||
#include "foundation/PxMat44.h"
|
||||
#include "GuBV4.h"
|
||||
#include "GuBox.h"
|
||||
#include "GuSphere.h"
|
||||
#include "GuSweepSphereTriangle.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
using namespace aos;
|
||||
|
||||
#include "GuBV4_Common.h"
|
||||
|
||||
// PT: for sphere-sweeps we use method 3 in %SDKRoot%\InternalDocumentation\GU\Sweep strategies.ppt
|
||||
|
||||
namespace
|
||||
{
|
||||
// PT: TODO: refactor structure (TA34704)
|
||||
struct RayParams
|
||||
{
|
||||
BV4_ALIGN16(PxVec3p mCenterOrMinCoeff_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mExtentsOrMaxCoeff_PaddedAligned);
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
BV4_ALIGN16(PxVec3p mData2_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mFDir_PaddedAligned);
|
||||
BV4_ALIGN16(PxVec3p mData_PaddedAligned);
|
||||
#endif
|
||||
BV4_ALIGN16(PxVec3p mLocalDir_Padded); // PT: TODO: this one could be switched to PaddedAligned & V4LoadA (TA34704)
|
||||
BV4_ALIGN16(PxVec3p mOrigin_Padded); // PT: TODO: this one could be switched to PaddedAligned & V4LoadA (TA34704)
|
||||
};
|
||||
|
||||
struct SphereSweepParams : RayParams
|
||||
{
|
||||
const IndTri32* PX_RESTRICT mTris32;
|
||||
const IndTri16* PX_RESTRICT mTris16;
|
||||
const PxVec3* PX_RESTRICT mVerts;
|
||||
|
||||
PxVec3 mOriginalExtents_Padded;
|
||||
|
||||
RaycastHitInternal mStabbedFace;
|
||||
PxU32 mBackfaceCulling;
|
||||
PxU32 mEarlyExit;
|
||||
|
||||
PxVec3 mP0, mP1, mP2;
|
||||
PxVec3 mBestTriNormal;
|
||||
float mBestAlignmentValue;
|
||||
float mBestDistance;
|
||||
float mMaxDist;
|
||||
|
||||
// PX_FORCE_INLINE float getReportDistance() const { return mStabbedFace.mDistance; }
|
||||
PX_FORCE_INLINE float getReportDistance() const { return mBestDistance; }
|
||||
};
|
||||
}
|
||||
|
||||
#include "GuBV4_AABBAABBSweepTest.h"
|
||||
|
||||
// PT: TODO: __fastcall removed to make it compile everywhere. Revisit.
|
||||
static bool /*__fastcall*/ triSphereSweep(SphereSweepParams* PX_RESTRICT params, PxU32 primIndex, bool nodeSorting=true)
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
const PxVec3& p0 = params->mVerts[VRef0];
|
||||
const PxVec3& p1 = params->mVerts[VRef1];
|
||||
const PxVec3& p2 = params->mVerts[VRef2];
|
||||
|
||||
PxVec3 normal = (p1 - p0).cross(p2 - p0);
|
||||
|
||||
// Backface culling
|
||||
const bool culled = params->mBackfaceCulling && normal.dot(params->mLocalDir_Padded) > 0.0f;
|
||||
if(culled)
|
||||
return false;
|
||||
|
||||
const PxTriangle T(p0, p1, p2); // PT: TODO: check potential bad ctor/dtor here (TA34704) <= or avoid creating the tri, not needed anymore
|
||||
|
||||
normal.normalize();
|
||||
|
||||
// PT: TODO: we lost some perf when switching to PhysX version. Revisit/investigate. (TA34704)
|
||||
float dist;
|
||||
bool directHit;
|
||||
if(!sweepSphereVSTri(T.verts, normal, params->mOrigin_Padded, params->mOriginalExtents_Padded.x, params->mLocalDir_Padded, dist, directHit, true))
|
||||
return false;
|
||||
|
||||
const PxReal alignmentValue = computeAlignmentValue(normal, params->mLocalDir_Padded);
|
||||
if(keepTriangle(dist, alignmentValue, params->mBestDistance, params->mBestAlignmentValue, params->mMaxDist))
|
||||
{
|
||||
params->mStabbedFace.mDistance = dist;
|
||||
params->mStabbedFace.mTriangleID = primIndex;
|
||||
params->mP0 = p0;
|
||||
params->mP1 = p1;
|
||||
params->mP2 = p2;
|
||||
params->mBestDistance = PxMin(params->mBestDistance, dist); // exact lower bound
|
||||
params->mBestAlignmentValue = alignmentValue;
|
||||
params->mBestTriNormal = normal;
|
||||
if(nodeSorting)
|
||||
{
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, params->mBestDistance, params->mOrigin_Padded, params->mLocalDir_Padded);
|
||||
//setupRayData(params, dist, params->mOrigin_Padded, params->mLocalDir_Padded);
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//
|
||||
else if(keepTriangleBasic(dist, params->mBestDistance, params->mMaxDist))
|
||||
{
|
||||
params->mStabbedFace.mDistance = dist;
|
||||
params->mBestDistance = PxMin(params->mBestDistance, dist); // exact lower bound
|
||||
}
|
||||
//
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class LeafFunction_SphereSweepClosest
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void doLeafTest(SphereSweepParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
triSphereSweep(params, primIndex);
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
}
|
||||
};
|
||||
|
||||
class LeafFunction_SphereSweepAny
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(SphereSweepParams* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(triSphereSweep(params, primIndex))
|
||||
return 1;
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class ImpactFunctionSphere
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void computeImpact(PxVec3& impactPos, PxVec3& impactNormal, const Sphere& sphere, const PxVec3& dir, const PxReal t, const PxTrianglePadded& triangle)
|
||||
{
|
||||
computeSphereTriImpactData(impactPos, impactNormal, sphere.center, dir, t, triangle);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template<class ParamsT>
|
||||
static PX_FORCE_INLINE void setupSphereParams(ParamsT* PX_RESTRICT params, const Sphere& sphere, const PxVec3& dir, float maxDist, const BV4Tree* PX_RESTRICT tree, const PxMat44* PX_RESTRICT worldm_Aligned, const SourceMesh* PX_RESTRICT mesh, PxU32 flags)
|
||||
{
|
||||
params->mOriginalExtents_Padded = PxVec3(sphere.radius);
|
||||
params->mStabbedFace.mTriangleID = PX_INVALID_U32;
|
||||
params->mStabbedFace.mDistance = maxDist;
|
||||
params->mBestDistance = PX_MAX_REAL;
|
||||
params->mBestAlignmentValue = 2.0f;
|
||||
params->mMaxDist = maxDist;
|
||||
setupParamsFlags(params, flags);
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(params, mesh, tree);
|
||||
|
||||
computeLocalRay(params->mLocalDir_Padded, params->mOrigin_Padded, dir, sphere.center, worldm_Aligned);
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, maxDist, params->mOrigin_Padded, params->mLocalDir_Padded);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs.h"
|
||||
#endif
|
||||
#include "GuBV4_ProcessStreamOrdered_SegmentAABB_Inflated.h"
|
||||
#include "GuBV4_ProcessStreamNoOrder_SegmentAABB_Inflated.h"
|
||||
#ifdef GU_BV4_USE_SLABS
|
||||
#include "GuBV4_Slabs_KajiyaNoOrder.h"
|
||||
#include "GuBV4_Slabs_KajiyaOrdered.h"
|
||||
#endif
|
||||
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_NO_ORDER
|
||||
#define GU_BV4_PROCESS_STREAM_RAY_ORDERED
|
||||
#include "GuBV4_Internal.h"
|
||||
|
||||
PxIntBool BV4_SphereSweepSingle(const Sphere& sphere, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepHit* PX_RESTRICT hit, PxU32 flags)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
SphereSweepParams Params;
|
||||
setupSphereParams(&Params, sphere, dir, maxDist, &tree, worldm_Aligned, mesh, flags);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(Params.mEarlyExit)
|
||||
processStreamRayNoOrder<1, LeafFunction_SphereSweepAny>(tree, &Params);
|
||||
else
|
||||
processStreamRayOrdered<1, LeafFunction_SphereSweepClosest>(tree, &Params);
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_SphereSweepAny, LeafFunction_SphereSweepClosest>(mesh->getNbTriangles(), &Params);
|
||||
|
||||
return computeImpactDataT<ImpactFunctionSphere>(sphere, dir, hit, &Params, worldm_Aligned, (flags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (flags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
}
|
||||
|
||||
// PT: sphere sweep callback version - currently not used
|
||||
|
||||
namespace
|
||||
{
|
||||
struct SphereSweepParamsCB : SphereSweepParams
|
||||
{
|
||||
// PT: these new members are only here to call computeImpactDataT during traversal :(
|
||||
// PT: TODO: most of them may not be needed if we just move sphere to local space before traversal
|
||||
Sphere mSphere; // Sphere in original space (maybe not local/mesh space)
|
||||
PxVec3 mDir; // Dir in original space (maybe not local/mesh space)
|
||||
const PxMat44* mWorldm_Aligned;
|
||||
PxU32 mFlags;
|
||||
|
||||
SweepUnlimitedCallback mCallback;
|
||||
void* mUserData;
|
||||
bool mNodeSorting;
|
||||
};
|
||||
|
||||
class LeafFunction_SphereSweepCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE PxIntBool doLeafTest(SphereSweepParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
if(triSphereSweep(params, primIndex, params->mNodeSorting))
|
||||
{
|
||||
// PT: TODO: in this version we must compute the impact data immediately,
|
||||
// which is a bad idea in general, but I'm not sure what else I can do.
|
||||
SweepHit hit;
|
||||
const bool b = computeImpactDataT<ImpactFunctionSphere>(params->mSphere, params->mDir, &hit, params, params->mWorldm_Aligned, (params->mFlags & QUERY_MODIFIER_DOUBLE_SIDED)!=0, (params->mFlags & QUERY_MODIFIER_MESH_BOTH_SIDES)!=0);
|
||||
PX_ASSERT(b);
|
||||
PX_UNUSED(b);
|
||||
|
||||
reportUnlimitedCallbackHit(params, hit);
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PT: for design decisions in this function, refer to the comments of BV4_GenericSweepCB().
|
||||
void BV4_SphereSweepCB(const Sphere& sphere, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags, bool nodeSorting)
|
||||
{
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
SphereSweepParamsCB Params;
|
||||
Params.mSphere = sphere;
|
||||
Params.mDir = dir;
|
||||
Params.mWorldm_Aligned = worldm_Aligned;
|
||||
Params.mFlags = flags;
|
||||
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
Params.mMaxDist = maxDist;
|
||||
Params.mNodeSorting = nodeSorting;
|
||||
setupSphereParams(&Params, sphere, dir, maxDist, &tree, worldm_Aligned, mesh, flags);
|
||||
|
||||
PX_ASSERT(!Params.mEarlyExit);
|
||||
|
||||
if(tree.mNodes)
|
||||
{
|
||||
if(nodeSorting)
|
||||
processStreamRayOrdered<1, LeafFunction_SphereSweepCB>(tree, &Params);
|
||||
else
|
||||
processStreamRayNoOrder<1, LeafFunction_SphereSweepCB>(tree, &Params);
|
||||
}
|
||||
else
|
||||
doBruteForceTests<LeafFunction_SphereSweepCB, LeafFunction_SphereSweepCB>(mesh->getNbTriangles(), &Params);
|
||||
}
|
||||
|
||||
|
||||
// Old box sweep callback version, using sphere code
|
||||
|
||||
namespace
|
||||
{
|
||||
struct BoxSweepParamsCB : SphereSweepParams
|
||||
{
|
||||
MeshSweepCallback mCallback;
|
||||
void* mUserData;
|
||||
};
|
||||
|
||||
class ExLeafTestSweepCB
|
||||
{
|
||||
public:
|
||||
static PX_FORCE_INLINE void doLeafTest(BoxSweepParamsCB* PX_RESTRICT params, PxU32 primIndex)
|
||||
{
|
||||
PxU32 nbToGo = getNbPrimitives(primIndex);
|
||||
do
|
||||
{
|
||||
PxU32 VRef0, VRef1, VRef2;
|
||||
getVertexReferences(VRef0, VRef1, VRef2, primIndex, params->mTris32, params->mTris16);
|
||||
|
||||
{
|
||||
// const PxU32 vrefs[3] = { VRef0, VRef1, VRef2 };
|
||||
float dist = params->mStabbedFace.mDistance;
|
||||
if((params->mCallback)(params->mUserData, params->mVerts[VRef0], params->mVerts[VRef1], params->mVerts[VRef2], primIndex, /*vrefs,*/ dist))
|
||||
return;
|
||||
|
||||
if(dist<params->mStabbedFace.mDistance)
|
||||
{
|
||||
params->mStabbedFace.mDistance = dist;
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(params, dist, params->mOrigin_Padded, params->mLocalDir_Padded);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
primIndex++;
|
||||
}while(nbToGo--);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void BV4_GenericSweepCB_Old(const PxVec3& origin, const PxVec3& extents, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, MeshSweepCallback callback, void* userData)
|
||||
{
|
||||
BoxSweepParamsCB Params;
|
||||
Params.mCallback = callback;
|
||||
Params.mUserData = userData;
|
||||
Params.mOriginalExtents_Padded = extents;
|
||||
|
||||
Params.mStabbedFace.mTriangleID = PX_INVALID_U32;
|
||||
Params.mStabbedFace.mDistance = maxDist;
|
||||
|
||||
computeLocalRay(Params.mLocalDir_Padded, Params.mOrigin_Padded, dir, origin, worldm_Aligned);
|
||||
|
||||
#ifndef GU_BV4_USE_SLABS
|
||||
setupRayData(&Params, maxDist, Params.mOrigin_Padded, Params.mLocalDir_Padded);
|
||||
#endif
|
||||
|
||||
const SourceMesh* PX_RESTRICT mesh = static_cast<const SourceMesh*>(tree.mMeshInterface);
|
||||
|
||||
setupMeshPointersAndQuantizedCoeffs(&Params, mesh, &tree);
|
||||
|
||||
if(tree.mNodes)
|
||||
processStreamRayOrdered<1, ExLeafTestSweepCB>(tree, &Params);
|
||||
else
|
||||
{
|
||||
const PxU32 nbTris = mesh->getNbTriangles();
|
||||
PX_ASSERT(nbTris<16);
|
||||
ExLeafTestSweepCB::doLeafTest(&Params, nbTris);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
43
engine/third_party/physx/source/geomutils/src/mesh/GuBVConstants.h
vendored
Normal file
43
engine/third_party/physx/source/geomutils/src/mesh/GuBVConstants.h
vendored
Normal 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.
|
||||
|
||||
#ifndef GU_BV_CONSTANTS_H
|
||||
#define GU_BV_CONSTANTS_H
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
const physx::aos::VecU32V signMask = physx::aos::U4LoadXYZW((physx::PxU32(1)<<31), (physx::PxU32(1)<<31), (physx::PxU32(1)<<31), (physx::PxU32(1)<<31));
|
||||
const physx::aos::Vec4V epsFloat4 = physx::aos::V4Load(1e-9f);
|
||||
const physx::aos::Vec4V zeroes = physx::aos::V4Zero();
|
||||
const physx::aos::Vec4V twos = physx::aos::V4Load(2.0f);
|
||||
const physx::aos::Vec4V epsInflateFloat4 = physx::aos::V4Load(1e-7f);
|
||||
}
|
||||
|
||||
#endif // GU_BV_CONSTANTS_H
|
||||
649
engine/third_party/physx/source/geomutils/src/mesh/GuMeshData.h
vendored
Normal file
649
engine/third_party/physx/source/geomutils/src/mesh/GuMeshData.h
vendored
Normal file
@@ -0,0 +1,649 @@
|
||||
// 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_MESH_DATA_H
|
||||
#define GU_MESH_DATA_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "foundation/PxVec4.h"
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "geometry/PxTriangleMesh.h"
|
||||
#include "geometry/PxTetrahedronMesh.h"
|
||||
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "foundation/PxAllocator.h"
|
||||
#include "GuRTree.h"
|
||||
#include "GuBV4.h"
|
||||
#include "GuBV32.h"
|
||||
#include "GuSDF.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu {
|
||||
|
||||
// 1: support stackless collision trees for non-recursive collision queries
|
||||
// 2: height field functionality not supported anymore
|
||||
// 3: mass struct removed
|
||||
// 4: bounding sphere removed
|
||||
// 5: RTree added, opcode tree still in the binary image, physx 3.0
|
||||
// 6: opcode tree removed from binary image
|
||||
// 7: convex decomposition is out
|
||||
// 8: adjacency information added
|
||||
// 9: removed leaf triangles and most of opcode data, changed rtree layout
|
||||
// 10: float rtrees
|
||||
// 11: new build, isLeaf added to page
|
||||
// 12: isLeaf is now the lowest bit in ptrs
|
||||
// 13: TA30159 removed deprecated convexEdgeThreshold and bumped version
|
||||
// 14: added midphase ID
|
||||
// 15: GPU data simplification
|
||||
// 16: vertex2Face mapping enabled by default if using GPU
|
||||
|
||||
#define PX_MESH_VERSION 16
|
||||
#define PX_TET_MESH_VERSION 1
|
||||
#define PX_DEFORMABLE_VOLUME_MESH_VERSION 3 // 3: parallel GS + new linear corotated model.
|
||||
|
||||
// these flags are used to indicate/validate the contents of a cooked mesh file
|
||||
enum InternalMeshSerialFlag
|
||||
{
|
||||
IMSF_MATERIALS = (1<<0), //!< if set, the cooked mesh file contains per-triangle material indices
|
||||
IMSF_FACE_REMAP = (1<<1), //!< if set, the cooked mesh file contains a remap table
|
||||
IMSF_8BIT_INDICES = (1<<2), //!< if set, the cooked mesh file contains 8bit indices (topology)
|
||||
IMSF_16BIT_INDICES = (1<<3), //!< if set, the cooked mesh file contains 16bit indices (topology)
|
||||
IMSF_ADJACENCIES = (1<<4), //!< if set, the cooked mesh file contains adjacency structures
|
||||
IMSF_GRB_DATA = (1<<5), //!< if set, the cooked mesh file contains GRB data structures
|
||||
IMSF_SDF = (1<<6), //!< if set, the cooked mesh file contains SDF data structures
|
||||
IMSF_VERT_MAPPING = (1<<7), //!< if set, the cooked mesh file contains vertex mapping information
|
||||
IMSF_GRB_INV_REMAP = (1<<8), //!< if set, the cooked mesh file contains vertex inv mapping information. Required for deformable surfaces
|
||||
IMSF_INERTIA = (1<<9) //!< if set, the cooked mesh file contains inertia tensor for the mesh
|
||||
};
|
||||
|
||||
#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 MeshDataBase : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
PxMeshMidPhase::Enum mType;
|
||||
PxU8 mFlags;
|
||||
PxU32 mNbVertices;
|
||||
PxVec3* mVertices;
|
||||
|
||||
PxReal mMass; //this is mass assuming a unit density that can be scaled by instances!
|
||||
PxMat33 mInertia; //in local space of mesh!
|
||||
PxVec3 mLocalCenterOfMass; //local space com
|
||||
|
||||
PxBounds3 mAABB;
|
||||
PxReal mGeomEpsilon;
|
||||
|
||||
PxU32* mFaceRemap;
|
||||
|
||||
// GRB data -------------------------
|
||||
void* mGRB_primIndices; //!< GRB: GPU-friendly primitive indices(either triangle or tetrahedron)
|
||||
PxU32* mGRB_faceRemap; //!< GRB: this remap the GPU triangle indices to CPU triangle indices
|
||||
PxU32* mGRB_faceRemapInverse; //
|
||||
// End of GRB data ------------------
|
||||
|
||||
// SDF data
|
||||
SDF mSdfData;
|
||||
|
||||
// Deformable surface data : each vert has a list of associated triangles in the mesh, this is for attachement constraints to enable default filtering
|
||||
PxU32* mAccumulatedTrianglesRef;//runsum
|
||||
PxU32* mTrianglesReferences;
|
||||
PxU32 mNbTrianglesReferences;
|
||||
|
||||
MeshDataBase() :
|
||||
mFlags (0),
|
||||
mNbVertices (0),
|
||||
mVertices (NULL),
|
||||
mMass (0.f),
|
||||
mInertia (PxZero),
|
||||
mLocalCenterOfMass (0.f),
|
||||
mAABB (PxBounds3::empty()),
|
||||
mGeomEpsilon (0.0f),
|
||||
mFaceRemap (NULL),
|
||||
mGRB_primIndices (NULL),
|
||||
mGRB_faceRemap (NULL),
|
||||
mGRB_faceRemapInverse (NULL),
|
||||
mSdfData (PxZero),
|
||||
mAccumulatedTrianglesRef(NULL),
|
||||
mTrianglesReferences (NULL),
|
||||
mNbTrianglesReferences (0)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MeshDataBase()
|
||||
{
|
||||
PX_FREE(mVertices);
|
||||
PX_FREE(mFaceRemap);
|
||||
PX_FREE(mGRB_primIndices);
|
||||
PX_FREE(mGRB_faceRemap);
|
||||
PX_FREE(mGRB_faceRemapInverse);
|
||||
|
||||
PX_FREE(mAccumulatedTrianglesRef);
|
||||
|
||||
PX_FREE(mTrianglesReferences);
|
||||
}
|
||||
|
||||
PX_NOINLINE PxVec3* allocateVertices(PxU32 nbVertices)
|
||||
{
|
||||
PX_ASSERT(!mVertices);
|
||||
// PT: we allocate one more vertex to make sure it's safe to V4Load the last one
|
||||
const PxU32 nbAllocatedVerts = nbVertices + 1;
|
||||
mVertices = PX_ALLOCATE(PxVec3, nbAllocatedVerts, "PxVec3");
|
||||
mNbVertices = nbVertices;
|
||||
return mVertices;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool has16BitIndices() const
|
||||
{
|
||||
return (mFlags & PxTriangleMeshFlag::e16_BIT_INDICES) ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
class TriangleMeshData : public MeshDataBase
|
||||
{
|
||||
public:
|
||||
|
||||
PxU32 mNbTriangles;
|
||||
void* mTriangles;
|
||||
|
||||
PxU32* mAdjacencies;
|
||||
PxU8* mExtraTrigData;
|
||||
PxU16* mMaterialIndices;
|
||||
|
||||
// GRB data -------------------------
|
||||
void* mGRB_primAdjacencies; //!< GRB: adjacency data, with BOUNDARY and NONCONVEX flags (flags replace adj indices where applicable) [uin4]
|
||||
Gu::BV32Tree* mGRB_BV32Tree;
|
||||
// End of GRB data ------------------
|
||||
|
||||
TriangleMeshData() :
|
||||
mNbTriangles (0),
|
||||
mTriangles (NULL),
|
||||
mAdjacencies (NULL),
|
||||
mExtraTrigData (NULL),
|
||||
mMaterialIndices (NULL),
|
||||
mGRB_primAdjacencies (NULL),
|
||||
mGRB_BV32Tree (NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TriangleMeshData()
|
||||
{
|
||||
PX_FREE(mTriangles);
|
||||
PX_FREE(mAdjacencies);
|
||||
PX_FREE(mMaterialIndices);
|
||||
PX_FREE(mExtraTrigData);
|
||||
PX_FREE(mGRB_primAdjacencies);
|
||||
PX_DELETE(mGRB_BV32Tree);
|
||||
}
|
||||
|
||||
PX_NOINLINE PxU32* allocateAdjacencies()
|
||||
{
|
||||
PX_ASSERT(mNbTriangles);
|
||||
PX_ASSERT(!mAdjacencies);
|
||||
mAdjacencies = PX_ALLOCATE(PxU32, mNbTriangles * 3, "mAdjacencies");
|
||||
mFlags |= PxTriangleMeshFlag::eADJACENCY_INFO;
|
||||
return mAdjacencies;
|
||||
}
|
||||
|
||||
PX_NOINLINE PxU32* allocateFaceRemap()
|
||||
{
|
||||
PX_ASSERT(mNbTriangles);
|
||||
PX_ASSERT(!mFaceRemap);
|
||||
mFaceRemap = PX_ALLOCATE(PxU32, mNbTriangles, "mFaceRemap");
|
||||
return mFaceRemap;
|
||||
}
|
||||
|
||||
PX_NOINLINE void* allocateTriangles(PxU32 nbTriangles, bool force32Bit, PxU32 allocateGPUData = 0)
|
||||
{
|
||||
PX_ASSERT(mNbVertices);
|
||||
PX_ASSERT(!mTriangles);
|
||||
|
||||
bool index16 = mNbVertices <= 0xffff && !force32Bit;
|
||||
if(index16)
|
||||
mFlags |= PxTriangleMeshFlag::e16_BIT_INDICES;
|
||||
|
||||
mTriangles = PX_ALLOC(nbTriangles * (index16 ? sizeof(PxU16) : sizeof(PxU32)) * 3, "mTriangles");
|
||||
if (allocateGPUData)
|
||||
mGRB_primIndices = PX_ALLOC(nbTriangles * (index16 ? sizeof(PxU16) : sizeof(PxU32)) * 3, "mGRB_triIndices");
|
||||
mNbTriangles = nbTriangles;
|
||||
return mTriangles;
|
||||
}
|
||||
|
||||
PX_NOINLINE PxU16* allocateMaterials()
|
||||
{
|
||||
PX_ASSERT(mNbTriangles);
|
||||
PX_ASSERT(!mMaterialIndices);
|
||||
mMaterialIndices = PX_ALLOCATE(PxU16, mNbTriangles, "mMaterialIndices");
|
||||
return mMaterialIndices;
|
||||
}
|
||||
|
||||
PX_NOINLINE PxU8* allocateExtraTrigData()
|
||||
{
|
||||
PX_ASSERT(mNbTriangles);
|
||||
PX_ASSERT(!mExtraTrigData);
|
||||
mExtraTrigData = PX_ALLOCATE(PxU8, mNbTriangles, "mExtraTrigData");
|
||||
return mExtraTrigData;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void setTriangleAdjacency(PxU32 triangleIndex, PxU32 adjacency, PxU32 offset)
|
||||
{
|
||||
PX_ASSERT(mAdjacencies);
|
||||
mAdjacencies[triangleIndex*3 + offset] = adjacency;
|
||||
}
|
||||
};
|
||||
|
||||
class RTreeTriangleData : public TriangleMeshData
|
||||
{
|
||||
public:
|
||||
RTreeTriangleData() { mType = PxMeshMidPhase::eBVH33; }
|
||||
virtual ~RTreeTriangleData() {}
|
||||
|
||||
Gu::RTree mRTree;
|
||||
};
|
||||
|
||||
class BV4TriangleData : public TriangleMeshData
|
||||
{
|
||||
public:
|
||||
BV4TriangleData() { mType = PxMeshMidPhase::eBVH34; }
|
||||
virtual ~BV4TriangleData() {}
|
||||
|
||||
Gu::SourceMesh mMeshInterface;
|
||||
Gu::BV4Tree mBV4Tree;
|
||||
};
|
||||
|
||||
// PT: TODO: the following classes should probably be in their own specific files (e.g. GuTetrahedronMeshData.h, GuDeformableVolumeMeshData.h)
|
||||
|
||||
class TetrahedronMeshData : public PxTetrahedronMeshData
|
||||
{
|
||||
public:
|
||||
PxU32 mNbVertices;
|
||||
PxVec3* mVertices;
|
||||
PxU16* mMaterialIndices; //each tetrahedron should have a material index
|
||||
|
||||
PxU32 mNbTetrahedrons;
|
||||
void* mTetrahedrons; //IndTetrahedron32
|
||||
|
||||
PxU8 mFlags;
|
||||
|
||||
PxReal mGeomEpsilon;
|
||||
PxBounds3 mAABB;
|
||||
|
||||
TetrahedronMeshData() :
|
||||
mNbVertices(0),
|
||||
mVertices(NULL),
|
||||
mMaterialIndices(NULL),
|
||||
mNbTetrahedrons(0),
|
||||
mTetrahedrons(NULL),
|
||||
mFlags(0),
|
||||
mGeomEpsilon(0.0f),
|
||||
mAABB(PxBounds3::empty())
|
||||
{}
|
||||
|
||||
TetrahedronMeshData(PxVec3* vertices, PxU32 nbVertices, void* tetrahedrons, PxU32 nbTetrahedrons, PxU8 flags, PxReal geomEpsilon, PxBounds3 aabb) :
|
||||
mNbVertices(nbVertices),
|
||||
mVertices(vertices),
|
||||
mNbTetrahedrons(nbTetrahedrons),
|
||||
mTetrahedrons(tetrahedrons),
|
||||
mFlags(flags),
|
||||
mGeomEpsilon(geomEpsilon),
|
||||
mAABB(aabb)
|
||||
{}
|
||||
|
||||
void allocateTetrahedrons(const PxU32 nbGridTetrahedrons, const PxU32 allocateGPUData = 0)
|
||||
{
|
||||
if (allocateGPUData)
|
||||
{
|
||||
mTetrahedrons = PX_ALLOC(nbGridTetrahedrons * sizeof(PxU32) * 4, "mGridModelTetrahedrons");
|
||||
}
|
||||
|
||||
mNbTetrahedrons = nbGridTetrahedrons;
|
||||
}
|
||||
|
||||
PxVec3* allocateVertices(PxU32 nbVertices, const PxU32 allocateGPUData = 1)
|
||||
{
|
||||
PX_ASSERT(!mVertices);
|
||||
// PT: we allocate one more vertex to make sure it's safe to V4Load the last one
|
||||
if (allocateGPUData)
|
||||
{
|
||||
const PxU32 nbAllocatedVerts = nbVertices + 1;
|
||||
mVertices = PX_ALLOCATE(PxVec3, nbAllocatedVerts, "PxVec3");
|
||||
}
|
||||
mNbVertices = nbVertices;
|
||||
return mVertices;
|
||||
}
|
||||
|
||||
PxU16* allocateMaterials()
|
||||
{
|
||||
PX_ASSERT(mNbTetrahedrons);
|
||||
PX_ASSERT(!mMaterialIndices);
|
||||
mMaterialIndices = PX_ALLOCATE(PxU16, mNbTetrahedrons, "mMaterialIndices");
|
||||
return mMaterialIndices;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool has16BitIndices() const
|
||||
{
|
||||
return (mFlags & PxTriangleMeshFlag::e16_BIT_INDICES) ? true : false;
|
||||
}
|
||||
|
||||
~TetrahedronMeshData()
|
||||
{
|
||||
PX_FREE(mTetrahedrons);
|
||||
PX_FREE(mVertices);
|
||||
PX_FREE(mMaterialIndices)
|
||||
}
|
||||
};
|
||||
|
||||
class DeformableVolumeCollisionData : public PxDeformableVolumeCollisionData
|
||||
{
|
||||
public:
|
||||
PxU32* mFaceRemap;
|
||||
|
||||
// GRB data -------------------------
|
||||
void * mGRB_primIndices; //!< GRB: GPU-friendly primitive indices(either triangle or tetrahedron)
|
||||
PxU32* mGRB_faceRemap; //!< GRB: this remap the GPU triangle indices to CPU triangle indices
|
||||
PxU32* mGRB_faceRemapInverse;
|
||||
Gu::BV32Tree* mGRB_BV32Tree;
|
||||
PxU8* mGRB_tetraSurfaceHint;
|
||||
|
||||
|
||||
// End of GRB data ------------------
|
||||
Gu::TetrahedronSourceMesh mMeshInterface;
|
||||
Gu::BV4Tree mBV4Tree;
|
||||
|
||||
PxMat33* mTetraRestPoses;
|
||||
|
||||
|
||||
DeformableVolumeCollisionData() :
|
||||
mFaceRemap(NULL),
|
||||
mGRB_primIndices(NULL),
|
||||
mGRB_faceRemap(NULL),
|
||||
mGRB_faceRemapInverse(NULL),
|
||||
mGRB_BV32Tree(NULL),
|
||||
mGRB_tetraSurfaceHint(NULL),
|
||||
mTetraRestPoses(NULL)
|
||||
{}
|
||||
|
||||
virtual ~DeformableVolumeCollisionData()
|
||||
{
|
||||
PX_FREE(mGRB_tetraSurfaceHint);
|
||||
PX_DELETE(mGRB_BV32Tree);
|
||||
PX_FREE(mFaceRemap);
|
||||
PX_FREE(mGRB_primIndices);
|
||||
PX_FREE(mGRB_faceRemap);
|
||||
PX_FREE(mGRB_faceRemapInverse);
|
||||
PX_FREE(mTetraRestPoses);
|
||||
}
|
||||
|
||||
PxU32* allocateFaceRemap(PxU32 nbTetrahedrons)
|
||||
{
|
||||
PX_ASSERT(nbTetrahedrons);
|
||||
PX_ASSERT(!mFaceRemap);
|
||||
mFaceRemap = PX_ALLOCATE(PxU32, nbTetrahedrons, "mFaceRemap");
|
||||
return mFaceRemap;
|
||||
}
|
||||
|
||||
void allocateCollisionData(PxU32 nbTetrahedrons)
|
||||
{
|
||||
mGRB_primIndices = PX_ALLOC(nbTetrahedrons * 4 * sizeof(PxU32), "mGRB_primIndices");
|
||||
mGRB_tetraSurfaceHint = PX_ALLOCATE(PxU8, nbTetrahedrons, "mGRB_tetraSurfaceHint");
|
||||
|
||||
mTetraRestPoses = PX_ALLOCATE(PxMat33, nbTetrahedrons, "mTetraRestPoses");
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
class CollisionMeshMappingData : public PxCollisionMeshMappingData
|
||||
{
|
||||
public:
|
||||
PxReal* mVertsBarycentricInGridModel;
|
||||
PxU32* mVertsRemapInGridModel;
|
||||
|
||||
PxU32* mTetsRemapColToSim;
|
||||
PxU32 mTetsRemapSize;
|
||||
PxU32* mTetsAccumulatedRemapColToSim; //runsum, size of number of tetrahedrons in collision mesh
|
||||
|
||||
//in the collision model, each vert has a list of associated simulation tetrahedrons, this is for attachement constraints to enable default filtering
|
||||
PxU32* mCollisionAccumulatedTetrahedronsRef;//runsum
|
||||
PxU32* mCollisionTetrahedronsReferences;
|
||||
PxU32 mCollisionNbTetrahedronsReferences;
|
||||
|
||||
PxU32* mCollisionSurfaceVertToTetRemap;
|
||||
PxU8* mCollisionSurfaceVertsHint;
|
||||
|
||||
CollisionMeshMappingData() :
|
||||
mVertsBarycentricInGridModel(NULL),
|
||||
mVertsRemapInGridModel(NULL),
|
||||
mTetsRemapColToSim(NULL),
|
||||
mTetsRemapSize(0),
|
||||
mTetsAccumulatedRemapColToSim(NULL),
|
||||
mCollisionAccumulatedTetrahedronsRef(NULL),
|
||||
mCollisionTetrahedronsReferences(NULL),
|
||||
mCollisionNbTetrahedronsReferences(0),
|
||||
mCollisionSurfaceVertToTetRemap(NULL),
|
||||
mCollisionSurfaceVertsHint(NULL)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
virtual ~CollisionMeshMappingData()
|
||||
{
|
||||
PX_FREE(mVertsBarycentricInGridModel);
|
||||
PX_FREE(mVertsRemapInGridModel);
|
||||
PX_FREE(mTetsRemapColToSim);
|
||||
PX_FREE(mTetsAccumulatedRemapColToSim);
|
||||
PX_FREE(mCollisionAccumulatedTetrahedronsRef);
|
||||
PX_FREE(mCollisionTetrahedronsReferences);
|
||||
PX_FREE(mCollisionSurfaceVertsHint);
|
||||
PX_FREE(mCollisionSurfaceVertToTetRemap);
|
||||
}
|
||||
|
||||
void allocatemappingData(const PxU32 nbVerts, const PxU32 tetRemapSize, const PxU32 nbColTetrahedrons, const PxU32 allocateGPUData = 0)
|
||||
{
|
||||
if (allocateGPUData)
|
||||
{
|
||||
mVertsBarycentricInGridModel = reinterpret_cast<PxReal*>(PX_ALLOC(nbVerts * sizeof(PxReal) * 4, "mVertsBarycentricInGridModel"));
|
||||
mVertsRemapInGridModel = reinterpret_cast<PxU32*>(PX_ALLOC(nbVerts * sizeof(PxU32), "mVertsRemapInGridModel"));
|
||||
mTetsRemapColToSim = reinterpret_cast<PxU32*>(PX_ALLOC(tetRemapSize * sizeof(PxU32), "mTetsRemapInSimModel"));
|
||||
mTetsAccumulatedRemapColToSim = reinterpret_cast<PxU32*>(PX_ALLOC(nbColTetrahedrons * sizeof(PxU32), "mTetsAccumulatedRemapInSimModel"));
|
||||
mCollisionSurfaceVertsHint = reinterpret_cast<PxU8*>(PX_ALLOC(nbVerts * sizeof(PxU8), "mCollisionSurfaceVertsHint"));
|
||||
mCollisionSurfaceVertToTetRemap = reinterpret_cast<PxU32*>(PX_ALLOC(nbVerts * sizeof(PxU32), "mCollisionSurfaceVertToTetRemap"));
|
||||
}
|
||||
mTetsRemapSize = tetRemapSize;
|
||||
}
|
||||
|
||||
void allocateTetRefData(const PxU32 totalTetReference, const PxU32 nbCollisionVerts, const PxU32 allocateGPUData /*= 0*/)
|
||||
{
|
||||
if (allocateGPUData)
|
||||
{
|
||||
mCollisionAccumulatedTetrahedronsRef = reinterpret_cast<PxU32*>(PX_ALLOC(nbCollisionVerts * sizeof(PxU32), "mGMAccumulatedTetrahedronsRef"));
|
||||
mCollisionTetrahedronsReferences = reinterpret_cast<PxU32*>(PX_ALLOC(totalTetReference * sizeof(PxU32), "mGMTetrahedronsReferences"));
|
||||
|
||||
}
|
||||
|
||||
mCollisionNbTetrahedronsReferences = totalTetReference;
|
||||
}
|
||||
|
||||
virtual void release()
|
||||
{
|
||||
PX_DELETE_THIS;
|
||||
}
|
||||
};
|
||||
|
||||
class DeformableVolumeSimulationData : public PxDeformableVolumeSimulationData
|
||||
{
|
||||
public:
|
||||
PxReal* mGridModelInvMass;
|
||||
|
||||
PxMat33* mGridModelTetraRestPoses;
|
||||
|
||||
PxU32 mGridModelNbPartitions;
|
||||
PxU32 mGridModelMaxTetsPerPartitions;
|
||||
|
||||
PxU32* mGridModelOrderedTetrahedrons; // the corresponding tetrahedron index for the runsum
|
||||
|
||||
PxU32* mGMRemapOutputCP;
|
||||
PxU32* mGMAccumulatedPartitionsCP; //runsum for the combined partition
|
||||
PxU32* mGMAccumulatedCopiesCP; //runsum for the vert copies in combined partitions
|
||||
|
||||
PxU32 mGMRemapOutputSize;
|
||||
|
||||
PxU32* mGMPullIndices;
|
||||
|
||||
PxU32 mNumTetsPerElement;
|
||||
|
||||
DeformableVolumeSimulationData() :
|
||||
mGridModelInvMass(NULL),
|
||||
mGridModelTetraRestPoses(NULL),
|
||||
mGridModelNbPartitions(0),
|
||||
mGridModelOrderedTetrahedrons(NULL),
|
||||
mGMRemapOutputCP(NULL),
|
||||
mGMAccumulatedPartitionsCP(NULL),
|
||||
mGMAccumulatedCopiesCP(NULL),
|
||||
mGMRemapOutputSize(0),
|
||||
mGMPullIndices(NULL)
|
||||
{}
|
||||
|
||||
virtual ~DeformableVolumeSimulationData()
|
||||
{
|
||||
PX_FREE(mGridModelInvMass);
|
||||
PX_FREE(mGridModelTetraRestPoses);
|
||||
PX_FREE(mGridModelOrderedTetrahedrons);
|
||||
PX_FREE(mGMRemapOutputCP);
|
||||
PX_FREE(mGMAccumulatedPartitionsCP);
|
||||
PX_FREE(mGMAccumulatedCopiesCP);
|
||||
PX_FREE(mGMPullIndices);
|
||||
}
|
||||
|
||||
void allocateGridModelData(const PxU32 nbGridTetrahedrons, const PxU32 nbGridVerts,
|
||||
const PxU32 nbVerts, const PxU32 nbPartitions, const PxU32 remapOutputSize, const PxU32 numTetsPerElement, const PxU32 allocateGPUData = 0)
|
||||
{
|
||||
PX_UNUSED(nbVerts);
|
||||
|
||||
if (allocateGPUData)
|
||||
{
|
||||
const PxU32 numElements = nbGridTetrahedrons / numTetsPerElement;
|
||||
const PxU32 numVertsPerElement = (numTetsPerElement == 6 || numTetsPerElement == 5) ? 8 : 4;
|
||||
|
||||
mGridModelInvMass = reinterpret_cast<float*>(PX_ALLOC(nbGridVerts * sizeof(float), "mGridModelInvMass"));
|
||||
mGridModelTetraRestPoses = reinterpret_cast<PxMat33*>(PX_ALLOC(nbGridTetrahedrons * sizeof(PxMat33), "mGridModelTetraRestPoses"));
|
||||
|
||||
mGridModelOrderedTetrahedrons = reinterpret_cast<PxU32*>(PX_ALLOC(numElements * sizeof(PxU32), "mGridModelOrderedTetrahedrons"));
|
||||
|
||||
if (remapOutputSize) // tet mesh only (or old hex mesh)
|
||||
{
|
||||
mGMRemapOutputCP = reinterpret_cast<PxU32*>(PX_ALLOC(numElements * numVertsPerElement * sizeof(PxU32), "mGMRemapOutputCP"));
|
||||
mGMAccumulatedCopiesCP = reinterpret_cast<PxU32*>(PX_ALLOC(nbGridVerts * sizeof(PxU32), "mGMAccumulatedCopiesCP"));
|
||||
}
|
||||
|
||||
mGMAccumulatedPartitionsCP = reinterpret_cast<PxU32*>(PX_ALLOC(nbPartitions * sizeof(PxU32), "mGMAccumulatedPartitionsCP"));
|
||||
mGMPullIndices = reinterpret_cast<PxU32*>(PX_ALLOC(numElements * numVertsPerElement * sizeof(PxU32) , "mGMPullIndices"));
|
||||
}
|
||||
|
||||
mGridModelNbPartitions = nbPartitions;
|
||||
mGMRemapOutputSize = remapOutputSize;
|
||||
}
|
||||
};
|
||||
|
||||
class CollisionTetrahedronMeshData : public PxCollisionTetrahedronMeshData
|
||||
{
|
||||
public:
|
||||
TetrahedronMeshData* mMesh;
|
||||
DeformableVolumeCollisionData* mCollisionData;
|
||||
|
||||
virtual PxTetrahedronMeshData* getMesh() { return mMesh; }
|
||||
virtual const PxTetrahedronMeshData* getMesh() const { return mMesh; }
|
||||
virtual PxDeformableVolumeCollisionData* getData() { return mCollisionData; }
|
||||
virtual const PxDeformableVolumeCollisionData* getData() const { return mCollisionData; }
|
||||
|
||||
virtual ~CollisionTetrahedronMeshData()
|
||||
{
|
||||
PX_FREE(mMesh);
|
||||
PX_FREE(mCollisionData);
|
||||
}
|
||||
|
||||
virtual void release()
|
||||
{
|
||||
PX_DELETE_THIS;
|
||||
}
|
||||
};
|
||||
|
||||
class SimulationTetrahedronMeshData : public PxSimulationTetrahedronMeshData
|
||||
{
|
||||
public:
|
||||
TetrahedronMeshData* mMesh;
|
||||
DeformableVolumeSimulationData* mSimulationData;
|
||||
|
||||
virtual PxTetrahedronMeshData* getMesh() { return mMesh; }
|
||||
virtual PxDeformableVolumeSimulationData* getData() { return mSimulationData; }
|
||||
|
||||
virtual ~SimulationTetrahedronMeshData()
|
||||
{
|
||||
PX_FREE(mMesh);
|
||||
PX_FREE(mSimulationData);
|
||||
}
|
||||
|
||||
virtual void release()
|
||||
{
|
||||
PX_DELETE_THIS;
|
||||
}
|
||||
};
|
||||
|
||||
class DeformableVolumeMeshData : public PxUserAllocated
|
||||
{
|
||||
PX_NOCOPY(DeformableVolumeMeshData)
|
||||
public:
|
||||
TetrahedronMeshData& mSimulationMesh;
|
||||
DeformableVolumeSimulationData& mSimulationData;
|
||||
TetrahedronMeshData& mCollisionMesh;
|
||||
DeformableVolumeCollisionData& mCollisionData;
|
||||
CollisionMeshMappingData& mMappingData;
|
||||
|
||||
DeformableVolumeMeshData(TetrahedronMeshData& simulationMesh, DeformableVolumeSimulationData& simulationData,
|
||||
TetrahedronMeshData& collisionMesh, DeformableVolumeCollisionData& collisionData, CollisionMeshMappingData& mappingData) :
|
||||
mSimulationMesh(simulationMesh),
|
||||
mSimulationData(simulationData),
|
||||
mCollisionMesh(collisionMesh),
|
||||
mCollisionData(collisionData),
|
||||
mMappingData(mappingData)
|
||||
{ }
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
}
|
||||
|
||||
#endif // #ifdef GU_MESH_DATA_H
|
||||
331
engine/third_party/physx/source/geomutils/src/mesh/GuMeshQuery.cpp
vendored
Normal file
331
engine/third_party/physx/source/geomutils/src/mesh/GuMeshQuery.cpp
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "common/PxProfileZone.h"
|
||||
#include "geometry/PxMeshQuery.h"
|
||||
#include "geometry/PxSphereGeometry.h"
|
||||
#include "geometry/PxGeometryQuery.h"
|
||||
|
||||
#include "GuInternal.h"
|
||||
#include "GuEntityReport.h"
|
||||
#include "GuHeightFieldUtil.h"
|
||||
#include "GuBoxConversion.h"
|
||||
#include "GuIntersectionTriangleBox.h"
|
||||
#include "CmScaling.h"
|
||||
#include "GuSweepTests.h"
|
||||
#include "GuMidphaseInterface.h"
|
||||
#include "foundation/PxFPU.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
namespace {
|
||||
|
||||
class HfTrianglesEntityReport2 : public OverlapReport, public LimitedResults
|
||||
{
|
||||
public:
|
||||
HfTrianglesEntityReport2(
|
||||
PxU32* results, PxU32 maxResults, PxU32 startIndex,
|
||||
HeightFieldUtil& hfUtil,
|
||||
const PxVec3& boxCenter, const PxVec3& boxExtents, const PxQuat& boxRot,
|
||||
bool aabbOverlap) :
|
||||
LimitedResults (results, maxResults, startIndex),
|
||||
mHfUtil (hfUtil),
|
||||
mAABBOverlap (aabbOverlap)
|
||||
{
|
||||
buildFrom(mBox2Hf, boxCenter, boxExtents, boxRot);
|
||||
}
|
||||
|
||||
virtual bool reportTouchedTris(PxU32 nbEntities, const PxU32* entities)
|
||||
{
|
||||
if(mAABBOverlap)
|
||||
{
|
||||
while(nbEntities--)
|
||||
if(!add(*entities++))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxTransform idt(PxIdentity);
|
||||
for(PxU32 i=0; i<nbEntities; i++)
|
||||
{
|
||||
PxTrianglePadded tri;
|
||||
mHfUtil.getTriangle(idt, tri, NULL, NULL, entities[i], false, false); // First parameter not needed if local space triangle is enough
|
||||
|
||||
// PT: this one is safe because triangle class is padded
|
||||
if(intersectTriangleBox(mBox2Hf, tri.verts[0], tri.verts[1], tri.verts[2]))
|
||||
{
|
||||
if(!add(entities[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
HeightFieldUtil& mHfUtil;
|
||||
BoxPadded mBox2Hf;
|
||||
bool mAABBOverlap;
|
||||
|
||||
private:
|
||||
HfTrianglesEntityReport2& operator=(const HfTrianglesEntityReport2&);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void physx::PxMeshQuery::getTriangle(const PxTriangleMeshGeometry& triGeom, const PxTransform& globalPose, PxTriangleID triangleIndex, PxTriangle& triangle, PxU32* vertexIndices, PxU32* adjacencyIndices)
|
||||
{
|
||||
const TriangleMesh* tm = static_cast<const TriangleMesh*>(triGeom.triangleMesh);
|
||||
|
||||
PX_CHECK_AND_RETURN(triangleIndex<tm->getNbTriangles(), "PxMeshQuery::getTriangle: triangle index is out of bounds");
|
||||
|
||||
if(adjacencyIndices && !tm->getAdjacencies())
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "Adjacency information not created. Set buildTriangleAdjacencies on Cooking params.");
|
||||
|
||||
const PxMat34 vertex2worldSkew = globalPose * triGeom.scale;
|
||||
tm->computeWorldTriangle(triangle, triangleIndex, vertex2worldSkew, triGeom.scale.hasNegativeDeterminant(), vertexIndices, adjacencyIndices);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void physx::PxMeshQuery::getTriangle(const PxHeightFieldGeometry& hfGeom, const PxTransform& globalPose, PxTriangleID triangleIndex, PxTriangle& triangle, PxU32* vertexIndices, PxU32* adjacencyIndices)
|
||||
{
|
||||
HeightFieldUtil hfUtil(hfGeom);
|
||||
|
||||
hfUtil.getTriangle(globalPose, triangle, vertexIndices, adjacencyIndices, triangleIndex, true, true);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxU32 physx::PxMeshQuery::findOverlapTriangleMesh(
|
||||
const PxGeometry& geom, const PxTransform& geomPose,
|
||||
const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshPose,
|
||||
PxU32* results, PxU32 maxResults, PxU32 startIndex, bool& overflow, PxGeometryQueryFlags queryFlags)
|
||||
{
|
||||
PX_SIMD_GUARD_CNDT(queryFlags & PxGeometryQueryFlag::eSIMD_GUARD)
|
||||
|
||||
LimitedResults limitedResults(results, maxResults, startIndex);
|
||||
|
||||
const TriangleMesh* tm = static_cast<const TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
switch(geom.getType())
|
||||
{
|
||||
case PxGeometryType::eBOX:
|
||||
{
|
||||
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom);
|
||||
|
||||
Box box;
|
||||
buildFrom(box, geomPose.p, boxGeom.halfExtents, geomPose.q);
|
||||
|
||||
Midphase::intersectBoxVsMesh(box, *tm, meshPose, meshGeom.scale, &limitedResults);
|
||||
break;
|
||||
}
|
||||
|
||||
case PxGeometryType::eCAPSULE:
|
||||
{
|
||||
const PxCapsuleGeometry& capsGeom = static_cast<const PxCapsuleGeometry&>(geom);
|
||||
|
||||
Capsule capsule;
|
||||
getCapsule(capsule, capsGeom, geomPose);
|
||||
|
||||
Midphase::intersectCapsuleVsMesh(capsule, *tm, meshPose, meshGeom.scale, &limitedResults);
|
||||
break;
|
||||
}
|
||||
|
||||
case PxGeometryType::eSPHERE:
|
||||
{
|
||||
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom);
|
||||
Midphase::intersectSphereVsMesh(Sphere(geomPose.p, sphereGeom.radius), *tm, meshPose, meshGeom.scale, &limitedResults);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
PX_CHECK_MSG(false, "findOverlapTriangleMesh: Only box, capsule and sphere geometries are supported.");
|
||||
}
|
||||
}
|
||||
|
||||
overflow = limitedResults.mOverflow;
|
||||
return limitedResults.mNbResults;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool physx::PxMeshQuery::findOverlapTriangleMesh( PxReportCallback<PxGeomIndexPair>& callback,
|
||||
const PxTriangleMeshGeometry& meshGeom0, const PxTransform& meshPose0,
|
||||
const PxTriangleMeshGeometry& meshGeom1, const PxTransform& meshPose1,
|
||||
PxGeometryQueryFlags queryFlags, PxMeshMeshQueryFlags meshMeshFlags, float tolerance)
|
||||
{
|
||||
PX_SIMD_GUARD_CNDT(queryFlags & PxGeometryQueryFlag::eSIMD_GUARD)
|
||||
|
||||
const TriangleMesh* tm0 = static_cast<const TriangleMesh*>(meshGeom0.triangleMesh);
|
||||
const TriangleMesh* tm1 = static_cast<const TriangleMesh*>(meshGeom1.triangleMesh);
|
||||
|
||||
// PT: only implemented for BV4
|
||||
if(!tm0 || !tm1 || tm0->getConcreteType()!=PxConcreteType::eTRIANGLE_MESH_BVH34 || tm1->getConcreteType()!=PxConcreteType::eTRIANGLE_MESH_BVH34)
|
||||
return PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxMeshQuery::findOverlapTriangleMesh(): only available between two BVH34 triangles meshes.");
|
||||
|
||||
// PT: ...so we don't need a table like for the other ops, just go straight to BV4
|
||||
return intersectMeshVsMesh_BV4(callback, *tm0, meshPose0, meshGeom0.scale, *tm1, meshPose1, meshGeom1.scale, meshMeshFlags, tolerance);
|
||||
}
|
||||
|
||||
bool physx::PxMeshQuery::findOverlapTriangleMesh( PxReportCallback<PxGeomIndexClosePair>& callback,
|
||||
const PxTriangleMeshGeometry& meshGeom0, const PxTransform& meshPose0,
|
||||
const PxTriangleMeshGeometry& meshGeom1, const PxTransform& meshPose1,
|
||||
PxGeometryQueryFlags queryFlags, PxMeshMeshQueryFlags meshMeshFlags, float tolerance)
|
||||
{
|
||||
PX_SIMD_GUARD_CNDT(queryFlags & PxGeometryQueryFlag::eSIMD_GUARD)
|
||||
|
||||
const TriangleMesh* tm0 = static_cast<const TriangleMesh*>(meshGeom0.triangleMesh);
|
||||
const TriangleMesh* tm1 = static_cast<const TriangleMesh*>(meshGeom1.triangleMesh);
|
||||
|
||||
// PT: only implemented for BV4
|
||||
if(!tm0 || !tm1 || tm0->getConcreteType()!=PxConcreteType::eTRIANGLE_MESH_BVH34 || tm1->getConcreteType()!=PxConcreteType::eTRIANGLE_MESH_BVH34)
|
||||
return PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxMeshQuery::findOverlapTriangleMesh(): only available between two BVH34 triangles meshes.");
|
||||
|
||||
// PT: ...so we don't need a table like for the other ops, just go straight to BV4
|
||||
return distanceMeshVsMesh_BV4(callback, *tm0, meshPose0, meshGeom0.scale, *tm1, meshPose1, meshGeom1.scale, meshMeshFlags, tolerance);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PxU32 physx::PxMeshQuery::findOverlapHeightField( const PxGeometry& geom, const PxTransform& geomPose,
|
||||
const PxHeightFieldGeometry& hfGeom, const PxTransform& hfPose,
|
||||
PxU32* results, PxU32 maxResults, PxU32 startIndex, bool& overflow, PxGeometryQueryFlags queryFlags)
|
||||
{
|
||||
PX_SIMD_GUARD_CNDT(queryFlags & PxGeometryQueryFlag::eSIMD_GUARD)
|
||||
|
||||
const PxTransform localPose0 = hfPose.transformInv(geomPose);
|
||||
PxBoxGeometry boxGeom;
|
||||
|
||||
switch(geom.getType())
|
||||
{
|
||||
case PxGeometryType::eCAPSULE:
|
||||
{
|
||||
const PxCapsuleGeometry& cap = static_cast<const PxCapsuleGeometry&>(geom);
|
||||
boxGeom.halfExtents = PxVec3(cap.halfHeight+cap.radius, cap.radius, cap.radius);
|
||||
// PT: TODO: improve these bounds - see computeCapsuleBounds
|
||||
}
|
||||
break;
|
||||
case PxGeometryType::eSPHERE:
|
||||
{
|
||||
const PxSphereGeometry& sph = static_cast<const PxSphereGeometry&>(geom);
|
||||
boxGeom.halfExtents = PxVec3(sph.radius);
|
||||
|
||||
// PT: TODO: could this codepath be improved using the following?
|
||||
//PxBounds3 localBounds;
|
||||
//const PxVec3 localSphereCenter = getLocalSphereData(localBounds, pose0, pose1, sphereGeom.radius);
|
||||
}
|
||||
break;
|
||||
case PxGeometryType::eBOX:
|
||||
boxGeom = static_cast<const PxBoxGeometry&>(geom);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
overflow = false;
|
||||
PX_CHECK_AND_RETURN_VAL(false, "findOverlapHeightField: Only box, sphere and capsule queries are supported.", false);
|
||||
}
|
||||
}
|
||||
|
||||
const bool isAABB = ((localPose0.q.x == 0.0f) && (localPose0.q.y == 0.0f) && (localPose0.q.z == 0.0f));
|
||||
|
||||
PxBounds3 bounds;
|
||||
if (isAABB)
|
||||
bounds = PxBounds3::centerExtents(localPose0.p, boxGeom.halfExtents);
|
||||
else
|
||||
bounds = PxBounds3::poseExtent(localPose0, boxGeom.halfExtents); // box.halfExtents is really extent
|
||||
|
||||
HeightFieldUtil hfUtil(hfGeom);
|
||||
HfTrianglesEntityReport2 entityReport(results, maxResults, startIndex, hfUtil, localPose0.p, boxGeom.halfExtents, localPose0.q, isAABB);
|
||||
|
||||
hfUtil.overlapAABBTriangles(bounds, entityReport);
|
||||
overflow = entityReport.mOverflow;
|
||||
return entityReport.mNbResults;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool physx::PxMeshQuery::sweep( const PxVec3& unitDir, const PxReal maxDistance,
|
||||
const PxGeometry& geom, const PxTransform& pose,
|
||||
PxU32 triangleCount, const PxTriangle* triangles,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags,
|
||||
const PxU32* cachedIndex, const PxReal inflation, bool doubleSided, PxGeometryQueryFlags queryFlags)
|
||||
{
|
||||
PX_SIMD_GUARD_CNDT(queryFlags & PxGeometryQueryFlag::eSIMD_GUARD)
|
||||
PX_CHECK_AND_RETURN_VAL(pose.isValid(), "PxMeshQuery::sweep(): pose is not valid.", false);
|
||||
PX_CHECK_AND_RETURN_VAL(unitDir.isFinite(), "PxMeshQuery::sweep(): unitDir is not valid.", false);
|
||||
PX_CHECK_AND_RETURN_VAL(PxIsFinite(maxDistance), "PxMeshQuery::sweep(): distance is not valid.", false);
|
||||
PX_CHECK_AND_RETURN_VAL(maxDistance > 0, "PxMeshQuery::sweep(): sweep distance must be greater than 0.", false);
|
||||
|
||||
PX_PROFILE_ZONE("MeshQuery.sweep", 0);
|
||||
|
||||
const PxReal distance = PxMin(maxDistance, PX_MAX_SWEEP_DISTANCE);
|
||||
|
||||
switch(geom.getType())
|
||||
{
|
||||
case PxGeometryType::eSPHERE:
|
||||
{
|
||||
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom);
|
||||
|
||||
const PxCapsuleGeometry capsuleGeom(sphereGeom.radius, 0.0f);
|
||||
|
||||
return sweepCapsuleTriangles( triangleCount, triangles, doubleSided, capsuleGeom, pose, unitDir, distance,
|
||||
sweepHit, cachedIndex, inflation, hitFlags);
|
||||
}
|
||||
|
||||
case PxGeometryType::eCAPSULE:
|
||||
{
|
||||
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom);
|
||||
|
||||
return sweepCapsuleTriangles( triangleCount, triangles, doubleSided, capsuleGeom, pose, unitDir, distance,
|
||||
sweepHit, cachedIndex, inflation, hitFlags);
|
||||
}
|
||||
|
||||
case PxGeometryType::eBOX:
|
||||
{
|
||||
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom);
|
||||
|
||||
if(hitFlags & PxHitFlag::ePRECISE_SWEEP)
|
||||
{
|
||||
return sweepBoxTriangles_Precise( triangleCount, triangles, doubleSided, boxGeom, pose, unitDir, distance, sweepHit, cachedIndex,
|
||||
inflation, hitFlags);
|
||||
}
|
||||
else
|
||||
{
|
||||
return sweepBoxTriangles( triangleCount, triangles, doubleSided, boxGeom, pose, unitDir, distance, sweepHit, cachedIndex,
|
||||
inflation, hitFlags);
|
||||
}
|
||||
}
|
||||
default:
|
||||
PX_CHECK_MSG(false, "PxMeshQuery::sweep(): geometry object parameter must be sphere, capsule or box geometry.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
1110
engine/third_party/physx/source/geomutils/src/mesh/GuMidphaseBV4.cpp
vendored
Normal file
1110
engine/third_party/physx/source/geomutils/src/mesh/GuMidphaseBV4.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
384
engine/third_party/physx/source/geomutils/src/mesh/GuMidphaseInterface.h
vendored
Normal file
384
engine/third_party/physx/source/geomutils/src/mesh/GuMidphaseInterface.h
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
// 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_MIDPHASE_INTERFACE_H
|
||||
#define GU_MIDPHASE_INTERFACE_H
|
||||
|
||||
#include "GuOverlapTests.h"
|
||||
#include "GuRaycastTests.h"
|
||||
#include "GuTriangleMesh.h"
|
||||
#include "GuTetrahedronMesh.h"
|
||||
#include "foundation/PxVecMath.h"
|
||||
#include "PxQueryReport.h"
|
||||
#include "geometry/PxMeshQuery.h" // PT: TODO: revisit this include
|
||||
|
||||
// PT: this file contains the common interface for all midphase implementations. Specifically the Midphase namespace contains the
|
||||
// midphase-related entry points, dispatching calls to the proper implementations depending on the triangle mesh's type. The rest of it
|
||||
// is simply classes & structs shared by all implementations.
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxMeshScale;
|
||||
class PxTriangleMeshGeometry;
|
||||
namespace Cm
|
||||
{
|
||||
class FastVertex2ShapeScaling;
|
||||
}
|
||||
|
||||
namespace Gu
|
||||
{
|
||||
struct ConvexHullData;
|
||||
|
||||
struct CallbackMode { enum Enum { eANY, eCLOSEST, eMULTIPLE }; };
|
||||
|
||||
template<typename HitType>
|
||||
struct MeshHitCallback
|
||||
{
|
||||
CallbackMode::Enum mode;
|
||||
|
||||
MeshHitCallback(CallbackMode::Enum aMode) : mode(aMode) {}
|
||||
|
||||
PX_FORCE_INLINE bool inAnyMode() const { return mode == CallbackMode::eANY; }
|
||||
PX_FORCE_INLINE bool inClosestMode() const { return mode == CallbackMode::eCLOSEST; }
|
||||
PX_FORCE_INLINE bool inMultipleMode() const { return mode == CallbackMode::eMULTIPLE; }
|
||||
|
||||
virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
|
||||
const HitType& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal& shrunkMaxT, const PxU32* vIndices) = 0;
|
||||
|
||||
virtual ~MeshHitCallback() {}
|
||||
};
|
||||
|
||||
template<typename HitType>
|
||||
struct TetMeshHitCallback
|
||||
{
|
||||
CallbackMode::Enum mode;
|
||||
|
||||
TetMeshHitCallback(CallbackMode::Enum aMode) : mode(aMode) {}
|
||||
|
||||
PX_FORCE_INLINE bool inAnyMode() const { return mode == CallbackMode::eANY; }
|
||||
PX_FORCE_INLINE bool inClosestMode() const { return mode == CallbackMode::eCLOSEST; }
|
||||
PX_FORCE_INLINE bool inMultipleMode() const { return mode == CallbackMode::eMULTIPLE; }
|
||||
|
||||
virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
|
||||
const HitType& hit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, const PxVec3& v3, PxReal& shrunkMaxT, const PxU32* vIndices) = 0;
|
||||
|
||||
virtual ~TetMeshHitCallback() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct SweepConvexMeshHitCallback;
|
||||
|
||||
struct LimitedResults
|
||||
{
|
||||
PxU32* mResults;
|
||||
PxU32 mNbResults;
|
||||
PxU32 mMaxResults;
|
||||
PxU32 mStartIndex;
|
||||
PxU32 mNbSkipped;
|
||||
bool mOverflow;
|
||||
|
||||
PX_FORCE_INLINE LimitedResults(PxU32* results, PxU32 maxResults, PxU32 startIndex)
|
||||
: mResults(results), mMaxResults(maxResults), mStartIndex(startIndex)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void reset()
|
||||
{
|
||||
mNbResults = 0;
|
||||
mNbSkipped = 0;
|
||||
mOverflow = false;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool add(PxU32 index)
|
||||
{
|
||||
if(mNbResults>=mMaxResults)
|
||||
{
|
||||
mOverflow = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(mNbSkipped>=mStartIndex)
|
||||
mResults[mNbResults++] = index;
|
||||
else
|
||||
mNbSkipped++;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// RTree forward declarations
|
||||
PX_PHYSX_COMMON_API PxU32 raycast_triangleMesh_RTREE(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose,
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir, PxReal maxDist,
|
||||
PxHitFlags hitFlags, PxU32 maxHits, PxGeomRaycastHit* PX_RESTRICT hits, PxU32 stride);
|
||||
PX_PHYSX_COMMON_API bool intersectSphereVsMesh_RTREE(const Sphere& sphere, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
PX_PHYSX_COMMON_API bool intersectBoxVsMesh_RTREE (const Box& box, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
PX_PHYSX_COMMON_API bool intersectCapsuleVsMesh_RTREE(const Capsule& capsule, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
PX_PHYSX_COMMON_API void intersectOBB_RTREE(const TriangleMesh* mesh, const Box& obb, MeshHitCallback<PxGeomRaycastHit>& callback, bool bothTriangleSidesCollide, bool checkObbIsAligned);
|
||||
PX_PHYSX_COMMON_API bool sweepCapsule_MeshGeom_RTREE( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Gu::Capsule& lss, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation);
|
||||
PX_PHYSX_COMMON_API bool sweepBox_MeshGeom_RTREE( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Gu::Box& box, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation);
|
||||
PX_PHYSX_COMMON_API void sweepConvex_MeshGeom_RTREE(const TriangleMesh* mesh, const Gu::Box& hullBox, const PxVec3& localDir, PxReal distance, SweepConvexMeshHitCallback& callback, bool anyHit);
|
||||
PX_PHYSX_COMMON_API void pointMeshDistance_RTREE(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose, const PxVec3& point, float maxDist, PxU32& index, float& dist, PxVec3& closestPt);
|
||||
|
||||
// BV4 forward declarations
|
||||
PX_PHYSX_COMMON_API PxU32 raycast_triangleMesh_BV4( const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose,
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir, PxReal maxDist,
|
||||
PxHitFlags hitFlags, PxU32 maxHits, PxGeomRaycastHit* PX_RESTRICT hits, PxU32 stride);
|
||||
PX_PHYSX_COMMON_API bool intersectSphereVsMesh_BV4 (const Sphere& sphere, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
PX_PHYSX_COMMON_API bool intersectBoxVsMesh_BV4 (const Box& box, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
PX_PHYSX_COMMON_API bool intersectCapsuleVsMesh_BV4 (const Capsule& capsule, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
PX_PHYSX_COMMON_API void intersectOBB_BV4(const TriangleMesh* mesh, const Box& obb, MeshHitCallback<PxGeomRaycastHit>& callback, bool bothTriangleSidesCollide, bool checkObbIsAligned);
|
||||
PX_PHYSX_COMMON_API void intersectOBB_BV4(const TetrahedronMesh* mesh, const Box& obb, TetMeshHitCallback<PxGeomRaycastHit>& callback);
|
||||
PX_PHYSX_COMMON_API bool sweepCapsule_MeshGeom_BV4( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Gu::Capsule& lss, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation);
|
||||
PX_PHYSX_COMMON_API bool sweepBox_MeshGeom_BV4( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Gu::Box& box, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation);
|
||||
PX_PHYSX_COMMON_API void sweepConvex_MeshGeom_BV4(const TriangleMesh* mesh, const Gu::Box& hullBox, const PxVec3& localDir, PxReal distance, SweepConvexMeshHitCallback& callback, bool anyHit);
|
||||
PX_PHYSX_COMMON_API void pointMeshDistance_BV4(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose, const PxVec3& point, float maxDist, PxU32& index, float& dist, PxVec3& closestPt);
|
||||
PX_PHYSX_COMMON_API bool intersectMeshVsMesh_BV4( PxReportCallback<PxGeomIndexPair>& callback,
|
||||
const TriangleMesh& triMesh0, const PxTransform& meshPose0, const PxMeshScale& meshScale0,
|
||||
const TriangleMesh& triMesh1, const PxTransform& meshPose1, const PxMeshScale& meshScale1,
|
||||
PxMeshMeshQueryFlags meshMeshFlags, float tolerance);
|
||||
PX_PHYSX_COMMON_API bool distanceMeshVsMesh_BV4( PxReportCallback<PxGeomIndexClosePair>& callback,
|
||||
const TriangleMesh& triMesh0, const PxTransform& meshPose0, const PxMeshScale& meshScale0,
|
||||
const TriangleMesh& triMesh1, const PxTransform& meshPose1, const PxMeshScale& meshScale1,
|
||||
PxMeshMeshQueryFlags meshMeshFlags, float tolerance);
|
||||
|
||||
typedef PxU32 (*MidphaseRaycastFunction)( const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose,
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir, PxReal maxDist,
|
||||
PxHitFlags hitFlags, PxU32 maxHits, PxGeomRaycastHit* PX_RESTRICT hits, PxU32 stride);
|
||||
|
||||
typedef bool (*MidphaseSphereOverlapFunction) (const Sphere& sphere, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
typedef bool (*MidphaseBoxOverlapFunction) (const Box& box, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
typedef bool (*MidphaseCapsuleOverlapFunction) (const Capsule& capsule, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results);
|
||||
typedef void (*MidphaseBoxCBOverlapFunction) (const TriangleMesh* mesh, const Box& obb, MeshHitCallback<PxGeomRaycastHit>& callback, bool bothTriangleSidesCollide, bool checkObbIsAligned);
|
||||
|
||||
typedef bool (*MidphaseCapsuleSweepFunction)( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Gu::Capsule& lss, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation);
|
||||
typedef bool (*MidphaseBoxSweepFunction)( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Gu::Box& box, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation);
|
||||
typedef void (*MidphaseConvexSweepFunction)( const TriangleMesh* mesh, const Gu::Box& hullBox, const PxVec3& localDir, PxReal distance, SweepConvexMeshHitCallback& callback, bool anyHit);
|
||||
typedef void (*MidphasePointMeshFunction)(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose, const PxVec3& point, float maxDist, PxU32& index, float& dist, PxVec3& closestPt);
|
||||
|
||||
static const MidphaseRaycastFunction gMidphaseRaycastTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
raycast_triangleMesh_RTREE,
|
||||
raycast_triangleMesh_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseSphereOverlapFunction gMidphaseSphereOverlapTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
intersectSphereVsMesh_RTREE,
|
||||
intersectSphereVsMesh_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseBoxOverlapFunction gMidphaseBoxOverlapTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
intersectBoxVsMesh_RTREE,
|
||||
intersectBoxVsMesh_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseCapsuleOverlapFunction gMidphaseCapsuleOverlapTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
intersectCapsuleVsMesh_RTREE,
|
||||
intersectCapsuleVsMesh_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseBoxCBOverlapFunction gMidphaseBoxCBOverlapTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
intersectOBB_RTREE,
|
||||
intersectOBB_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseBoxSweepFunction gMidphaseBoxSweepTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
sweepBox_MeshGeom_RTREE,
|
||||
sweepBox_MeshGeom_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseCapsuleSweepFunction gMidphaseCapsuleSweepTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
sweepCapsule_MeshGeom_RTREE,
|
||||
sweepCapsule_MeshGeom_BV4,
|
||||
};
|
||||
|
||||
static const MidphaseConvexSweepFunction gMidphaseConvexSweepTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
sweepConvex_MeshGeom_RTREE,
|
||||
sweepConvex_MeshGeom_BV4,
|
||||
};
|
||||
|
||||
static const MidphasePointMeshFunction gMidphasePointMeshTable[PxMeshMidPhase::eLAST] =
|
||||
{
|
||||
pointMeshDistance_RTREE,
|
||||
pointMeshDistance_BV4,
|
||||
};
|
||||
|
||||
namespace Midphase
|
||||
{
|
||||
// \param[in] mesh triangle mesh to raycast against
|
||||
// \param[in] meshGeom geometry object associated with the mesh
|
||||
// \param[in] meshTransform pose/transform of geometry object
|
||||
// \param[in] rayOrigin ray's origin
|
||||
// \param[in] rayDir ray's unit dir
|
||||
// \param[in] maxDist ray's length/max distance
|
||||
// \param[in] hitFlags query behavior flags
|
||||
// \param[in] maxHits max number of hits = size of 'hits' buffer
|
||||
// \param[out] hits result buffer where to write raycast hits
|
||||
// \return number of hits written to 'hits' result buffer
|
||||
// \note there's no mechanism to report overflow. Returned number of hits is just clamped to maxHits.
|
||||
PX_FORCE_INLINE PxU32 raycastTriangleMesh( const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshTransform,
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir, PxReal maxDist,
|
||||
PxHitFlags hitFlags, PxU32 maxHits, PxGeomRaycastHit* PX_RESTRICT hits, PxU32 stride)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh->getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
return gMidphaseRaycastTable[index](mesh, meshGeom, meshTransform, rayOrigin, rayDir, maxDist, hitFlags, maxHits, hits, stride);
|
||||
}
|
||||
|
||||
// \param[in] sphere sphere
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] meshTransform pose/transform of triangle mesh
|
||||
// \param[in] meshScale mesh scale
|
||||
// \param[out] results results object if multiple hits are needed, NULL if a simple boolean answer is enough
|
||||
// \return true if at least one overlap has been found
|
||||
PX_FORCE_INLINE bool intersectSphereVsMesh(const Sphere& sphere, const TriangleMesh& mesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh.getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
return gMidphaseSphereOverlapTable[index](sphere, mesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
// \param[in] box box
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] meshTransform pose/transform of triangle mesh
|
||||
// \param[in] meshScale mesh scale
|
||||
// \param[out] results results object if multiple hits are needed, NULL if a simple boolean answer is enough
|
||||
// \return true if at least one overlap has been found
|
||||
PX_FORCE_INLINE bool intersectBoxVsMesh(const Box& box, const TriangleMesh& mesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh.getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
return gMidphaseBoxOverlapTable[index](box, mesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
// \param[in] capsule capsule
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] meshTransform pose/transform of triangle mesh
|
||||
// \param[in] meshScale mesh scale
|
||||
// \param[out] results results object if multiple hits are needed, NULL if a simple boolean answer is enough
|
||||
// \return true if at least one overlap has been found
|
||||
PX_FORCE_INLINE bool intersectCapsuleVsMesh(const Capsule& capsule, const TriangleMesh& mesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh.getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
return gMidphaseCapsuleOverlapTable[index](capsule, mesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] box box
|
||||
// \param[in] callback callback object, called each time a hit is found
|
||||
// \param[in] bothTriangleSidesCollide true for double-sided meshes
|
||||
// \param[in] checkObbIsAligned true to use a dedicated codepath for axis-aligned boxes
|
||||
PX_FORCE_INLINE void intersectOBB(const TriangleMesh* mesh, const Box& obb, MeshHitCallback<PxGeomRaycastHit>& callback, bool bothTriangleSidesCollide, bool checkObbIsAligned = true)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh->getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
gMidphaseBoxCBOverlapTable[index](mesh, obb, callback, bothTriangleSidesCollide, checkObbIsAligned);
|
||||
}
|
||||
|
||||
// \param[in] mesh tetrahedron mesh
|
||||
// \param[in] box box
|
||||
// \param[in] callback callback object, called each time a hit is found
|
||||
PX_FORCE_INLINE void intersectOBB(const TetrahedronMesh* mesh, const Box& obb, TetMeshHitCallback<PxGeomRaycastHit>& callback)
|
||||
{
|
||||
intersectOBB_BV4(mesh, obb, callback);
|
||||
}
|
||||
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] meshGeom geometry object associated with the mesh
|
||||
// \param[in] meshTransform pose/transform of geometry object
|
||||
// \param[in] capsule swept capsule
|
||||
// \param[in] unitDir sweep's unit dir
|
||||
// \param[in] distance sweep's length/max distance
|
||||
// \param[out] sweepHit hit result
|
||||
// \param[in] hitFlags query behavior flags
|
||||
// \param[in] inflation optional inflation value for swept shape
|
||||
// \return true if a hit was found, false otherwise
|
||||
PX_FORCE_INLINE bool sweepCapsuleVsMesh(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshTransform,
|
||||
const Gu::Capsule& capsule, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh->getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
return gMidphaseCapsuleSweepTable[index](mesh, meshGeom, meshTransform, capsule, unitDir, distance, sweepHit, hitFlags, inflation);
|
||||
}
|
||||
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] meshGeom geometry object associated with the mesh
|
||||
// \param[in] meshTransform pose/transform of geometry object
|
||||
// \param[in] box swept box
|
||||
// \param[in] unitDir sweep's unit dir
|
||||
// \param[in] distance sweep's length/max distance
|
||||
// \param[out] sweepHit hit result
|
||||
// \param[in] hitFlags query behavior flags
|
||||
// \param[in] inflation optional inflation value for swept shape
|
||||
// \return true if a hit was found, false otherwise
|
||||
PX_FORCE_INLINE bool sweepBoxVsMesh(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshTransform,
|
||||
const Gu::Box& box, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh->getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
return gMidphaseBoxSweepTable[index](mesh, meshGeom, meshTransform, box, unitDir, distance, sweepHit, hitFlags, inflation);
|
||||
}
|
||||
|
||||
// \param[in] mesh triangle mesh
|
||||
// \param[in] hullBox hull's bounding box
|
||||
// \param[in] localDir sweep's unit dir, in local/mesh space
|
||||
// \param[in] distance sweep's length/max distance
|
||||
// \param[in] callback callback object, called each time a hit is found
|
||||
// \param[in] anyHit true for PxHitFlag::eANY_HIT queries
|
||||
PX_FORCE_INLINE void sweepConvexVsMesh(const TriangleMesh* mesh, const Gu::Box& hullBox, const PxVec3& localDir, PxReal distance, SweepConvexMeshHitCallback& callback, bool anyHit)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh->getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
gMidphaseConvexSweepTable[index](mesh, hullBox, localDir, distance, callback, anyHit);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void pointMeshDistance(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose, const PxVec3& point, float maxDist
|
||||
, PxU32& closestIndex, float& dist, PxVec3& closestPt)
|
||||
{
|
||||
const PxU32 index = PxU32(mesh->getConcreteType() - PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
gMidphasePointMeshTable[index](mesh, meshGeom, pose, point, maxDist, closestIndex, dist, closestPt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // GU_MIDPHASE_INTERFACE_H
|
||||
920
engine/third_party/physx/source/geomutils/src/mesh/GuMidphaseRTree.cpp
vendored
Normal file
920
engine/third_party/physx/source/geomutils/src/mesh/GuMidphaseRTree.cpp
vendored
Normal file
@@ -0,0 +1,920 @@
|
||||
// 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 "GuSweepMesh.h"
|
||||
#include "GuIntersectionRayTriangle.h"
|
||||
#include "GuIntersectionCapsuleTriangle.h"
|
||||
#include "GuIntersectionRayBox.h"
|
||||
#include "GuSphere.h"
|
||||
#include "GuBoxConversion.h"
|
||||
#include "GuConvexUtilsInternal.h"
|
||||
#include "GuVecTriangle.h"
|
||||
#include "GuIntersectionTriangleBox.h"
|
||||
#include "GuRTree.h"
|
||||
#include "GuTriangleMeshRTree.h"
|
||||
#include "GuInternal.h"
|
||||
#include "CmMatrix34.h"
|
||||
|
||||
// This file contains code specific to the RTree midphase.
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cm;
|
||||
using namespace Gu;
|
||||
using namespace aos;
|
||||
|
||||
struct MeshRayCollider
|
||||
{
|
||||
template <int tInflate, int tRayTest>
|
||||
PX_PHYSX_COMMON_API static void collide(
|
||||
const PxVec3& orig, const PxVec3& dir, // dir is not normalized (full length), both in mesh space (unless meshWorld is non-zero)
|
||||
PxReal maxT, // maxT is from [0,1], if maxT is 0.0f, AABB traversal will be used
|
||||
bool bothTriangleSidesCollide, const RTreeTriangleMesh* mesh, MeshHitCallback<PxGeomRaycastHit>& callback,
|
||||
const PxVec3* inflate = NULL);
|
||||
|
||||
PX_PHYSX_COMMON_API static void collideOBB(
|
||||
const Box& obb, bool bothTriangleSidesCollide, const RTreeTriangleMesh* mesh, MeshHitCallback<PxGeomRaycastHit>& callback,
|
||||
bool checkObbIsAligned = true); // perf hint, pass false if obb is rarely axis aligned
|
||||
};
|
||||
|
||||
class SimpleRayTriOverlap
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE SimpleRayTriOverlap(const PxVec3& origin, const PxVec3& dir, bool bothSides, PxReal geomEpsilon)
|
||||
: mOrigin(origin), mDir(dir), mBothSides(bothSides), mGeomEpsilon(geomEpsilon)
|
||||
{
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxIntBool overlap(const PxVec3& vert0, const PxVec3& vert1, const PxVec3& vert2, PxGeomRaycastHit& hit) const
|
||||
{
|
||||
if(!intersectRayTriangle(mOrigin, mDir, vert0, vert1, vert2, hit.distance, hit.u, hit.v, !mBothSides, mGeomEpsilon))
|
||||
return false;
|
||||
|
||||
if(hit.distance< 0.0f) // test if the ray intersection t is negative
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PxVec3 mOrigin;
|
||||
PxVec3 mDir;
|
||||
bool mBothSides;
|
||||
PxReal mGeomEpsilon;
|
||||
};
|
||||
|
||||
using Gu::RTree;
|
||||
|
||||
// This callback comes from RTree and decodes LeafTriangle indices stored in rtree into actual triangles
|
||||
// This callback is needed because RTree doesn't know that it stores triangles since it's a general purpose spatial index
|
||||
|
||||
#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
|
||||
|
||||
template <int tInflate, bool tRayTest>
|
||||
struct RayRTreeCallback : RTree::CallbackRaycast, RTree::Callback
|
||||
{
|
||||
MeshHitCallback<PxGeomRaycastHit>& outerCallback;
|
||||
PxI32 has16BitIndices;
|
||||
const void* mTris;
|
||||
const PxVec3* mVerts;
|
||||
const PxVec3* mInflate;
|
||||
const SimpleRayTriOverlap rayCollider;
|
||||
PxReal maxT;
|
||||
PxGeomRaycastHit closestHit; // recorded closest hit over the whole traversal (only for callback mode eCLOSEST)
|
||||
PxVec3 cv0, cv1, cv2; // PT: make sure these aren't last in the class, to safely V4Load them
|
||||
PxU32 cis[3];
|
||||
bool hadClosestHit;
|
||||
const bool closestMode;
|
||||
Vec3V inflateV, rayOriginV, rayDirV;
|
||||
|
||||
RayRTreeCallback(
|
||||
PxReal geomEpsilon, MeshHitCallback<PxGeomRaycastHit>& callback,
|
||||
PxI32 has16BitIndices_, const void* tris, const PxVec3* verts,
|
||||
const PxVec3& origin, const PxVec3& dir, PxReal maxT_, bool bothSides, const PxVec3* inflate)
|
||||
: outerCallback(callback), has16BitIndices(has16BitIndices_),
|
||||
mTris(tris), mVerts(verts), mInflate(inflate), rayCollider(origin, dir, bothSides, geomEpsilon),
|
||||
maxT(maxT_), closestMode(callback.inClosestMode())
|
||||
{
|
||||
PX_ASSERT(closestHit.distance == PX_MAX_REAL);
|
||||
hadClosestHit = false;
|
||||
if (tInflate)
|
||||
inflateV = V3LoadU(*mInflate);
|
||||
rayOriginV = V3LoadU(rayCollider.mOrigin);
|
||||
rayDirV = V3LoadU(rayCollider.mDir);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void getVertIndices(PxU32 triIndex, PxU32& i0, PxU32 &i1, PxU32 &i2)
|
||||
{
|
||||
if(has16BitIndices)
|
||||
{
|
||||
const PxU16* p = reinterpret_cast<const PxU16*>(mTris) + triIndex*3;
|
||||
i0 = p[0]; i1 = p[1]; i2 = p[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxU32* p = reinterpret_cast<const PxU32*>(mTris) + triIndex*3;
|
||||
i0 = p[0]; i1 = p[1]; i2 = p[2];
|
||||
}
|
||||
}
|
||||
|
||||
virtual PX_FORCE_INLINE bool processResults(PxU32 NumTouched, PxU32* Touched, PxF32& newMaxT)
|
||||
{
|
||||
PX_ASSERT(NumTouched > 0);
|
||||
// Loop through touched leaves
|
||||
PxGeomRaycastHit tempHit;
|
||||
for(PxU32 leaf = 0; leaf<NumTouched; leaf++)
|
||||
{
|
||||
// Each leaf box has a set of triangles
|
||||
LeafTriangles currentLeaf;
|
||||
currentLeaf.Data = Touched[leaf];
|
||||
PxU32 nbLeafTris = currentLeaf.GetNbTriangles();
|
||||
PxU32 baseLeafTriIndex = currentLeaf.GetTriangleIndex();
|
||||
|
||||
for(PxU32 i = 0; i < nbLeafTris; i++)
|
||||
{
|
||||
PxU32 i0, i1, i2;
|
||||
const PxU32 triangleIndex = baseLeafTriIndex+i;
|
||||
getVertIndices(triangleIndex, i0, i1, i2);
|
||||
|
||||
const PxVec3& v0 = mVerts[i0], &v1 = mVerts[i1], &v2 = mVerts[i2];
|
||||
const PxU32 vinds[3] = { i0, i1, i2 };
|
||||
|
||||
if (tRayTest)
|
||||
{
|
||||
PxIntBool overlap;
|
||||
if (tInflate)
|
||||
{
|
||||
// AP: mesh skew is already included here (ray is pre-transformed)
|
||||
Vec3V v0v = V3LoadU(v0), v1v = V3LoadU(v1), v2v = V3LoadU(v2);
|
||||
Vec3V minB = V3Min(V3Min(v0v, v1v), v2v), maxB = V3Max(V3Max(v0v, v1v), v2v);
|
||||
|
||||
// PT: we add an epsilon to max distance, to make sure we don't reject triangles that are just at the same
|
||||
// distance as best triangle so far. We need to keep all of these to make sure we return the one with the
|
||||
// best normal.
|
||||
const float relativeEpsilon = GU_EPSILON_SAME_DISTANCE * PxMax(1.0f, maxT);
|
||||
FloatV tNear, tFar;
|
||||
overlap = intersectRayAABB2(
|
||||
V3Sub(minB, inflateV), V3Add(maxB, inflateV), rayOriginV, rayDirV, FLoad(maxT+relativeEpsilon), tNear, tFar);
|
||||
if (overlap)
|
||||
{
|
||||
// can't clip to tFar here because hitting the AABB doesn't guarantee that we can clip
|
||||
// (since we can still miss the actual tri)
|
||||
tempHit.distance = maxT;
|
||||
tempHit.faceIndex = triangleIndex;
|
||||
tempHit.u = tempHit.v = 0.0f;
|
||||
}
|
||||
} else
|
||||
overlap = rayCollider.overlap(v0, v1, v2, tempHit) && tempHit.distance <= maxT;
|
||||
if(!overlap)
|
||||
continue;
|
||||
}
|
||||
tempHit.faceIndex = triangleIndex;
|
||||
tempHit.flags = PxHitFlag::ePOSITION;
|
||||
// Intersection point is valid if dist < segment's length
|
||||
// We know dist>0 so we can use integers
|
||||
if (closestMode)
|
||||
{
|
||||
if(tempHit.distance < closestHit.distance)
|
||||
{
|
||||
closestHit = tempHit;
|
||||
newMaxT = PxMin(tempHit.distance, newMaxT);
|
||||
cv0 = v0; cv1 = v1; cv2 = v2;
|
||||
cis[0] = vinds[0]; cis[1] = vinds[1]; cis[2] = vinds[2];
|
||||
hadClosestHit = true;
|
||||
}
|
||||
} else
|
||||
{
|
||||
PxReal shrunkMaxT = newMaxT;
|
||||
PxAgain again = outerCallback.processHit(tempHit, v0, v1, v2, shrunkMaxT, vinds);
|
||||
if (!again)
|
||||
return false;
|
||||
if (shrunkMaxT < newMaxT)
|
||||
{
|
||||
newMaxT = shrunkMaxT;
|
||||
maxT = shrunkMaxT;
|
||||
}
|
||||
}
|
||||
|
||||
if (outerCallback.inAnyMode()) // early out if in ANY mode
|
||||
return false;
|
||||
}
|
||||
|
||||
} // for(PxU32 leaf = 0; leaf<NumTouched; leaf++)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool processResults(PxU32 numTouched, PxU32* touched)
|
||||
{
|
||||
PxF32 dummy;
|
||||
return RayRTreeCallback::processResults(numTouched, touched, dummy);
|
||||
}
|
||||
|
||||
|
||||
virtual ~RayRTreeCallback()
|
||||
{
|
||||
if (hadClosestHit)
|
||||
{
|
||||
PX_ASSERT(outerCallback.inClosestMode());
|
||||
outerCallback.processHit(closestHit, cv0, cv1, cv2, maxT, cis);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RayRTreeCallback& operator=(const RayRTreeCallback&);
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
void MeshRayCollider::collideOBB(
|
||||
const Box& obb, bool bothTriangleSidesCollide, const RTreeTriangleMesh* mi, MeshHitCallback<PxGeomRaycastHit>& callback,
|
||||
bool checkObbIsAligned)
|
||||
{
|
||||
const PxU32 maxResults = RTREE_N; // maxResults=rtree page size for more efficient early out
|
||||
PxU32 buf[maxResults];
|
||||
RayRTreeCallback<false, false> rTreeCallback(
|
||||
mi->getGeomEpsilon(), callback, mi->has16BitIndices(), mi->getTrianglesFast(), mi->getVerticesFast(),
|
||||
PxVec3(0), PxVec3(0), 0.0f, bothTriangleSidesCollide, NULL);
|
||||
if (checkObbIsAligned && PxAbs(PxQuat(obb.rot).w) > 0.9999f)
|
||||
{
|
||||
PxVec3 aabbExtents = obb.computeAABBExtent();
|
||||
mi->getRTree().traverseAABB(obb.center - aabbExtents, obb.center + aabbExtents, maxResults, buf, &rTreeCallback);
|
||||
} else
|
||||
mi->getRTree().traverseOBB(obb, maxResults, buf, &rTreeCallback);
|
||||
}
|
||||
|
||||
template <int tInflate, int tRayTest>
|
||||
void MeshRayCollider::collide(
|
||||
const PxVec3& orig, const PxVec3& dir, PxReal maxT, bool bothSides,
|
||||
const RTreeTriangleMesh* mi, MeshHitCallback<PxGeomRaycastHit>& callback,
|
||||
const PxVec3* inflate)
|
||||
{
|
||||
const PxU32 maxResults = RTREE_N; // maxResults=rtree page size for more efficient early out
|
||||
PxU32 buf[maxResults];
|
||||
if (maxT == 0.0f) // AABB traversal path
|
||||
{
|
||||
RayRTreeCallback<tInflate, false> rTreeCallback(
|
||||
mi->getGeomEpsilon(), callback, mi->has16BitIndices(), mi->getTrianglesFast(), mi->getVerticesFast(),
|
||||
orig, dir, maxT, bothSides, inflate);
|
||||
PxVec3 inflate1 = tInflate ? *inflate : PxVec3(0); // both maxT and inflate can be zero, so need to check tInflate
|
||||
mi->getRTree().traverseAABB(orig-inflate1, orig+inflate1, maxResults, buf, &rTreeCallback);
|
||||
}
|
||||
else // ray traversal path
|
||||
{
|
||||
RayRTreeCallback<tInflate, tRayTest> rTreeCallback(
|
||||
mi->getGeomEpsilon(), callback, mi->has16BitIndices(), mi->getTrianglesFast(), mi->getVerticesFast(),
|
||||
orig, dir, maxT, bothSides, inflate);
|
||||
mi->getRTree().traverseRay<tInflate>(orig, dir, maxResults, buf, &rTreeCallback, inflate, maxT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define TINST(a,b) \
|
||||
template void MeshRayCollider::collide<a,b>( \
|
||||
const PxVec3& orig, const PxVec3& dir, PxReal maxT, bool bothSides, const RTreeTriangleMesh* mesh, \
|
||||
MeshHitCallback<PxGeomRaycastHit>& callback, const PxVec3* inflate);
|
||||
|
||||
TINST(0,0)
|
||||
TINST(1,0)
|
||||
TINST(0,1)
|
||||
TINST(1,1)
|
||||
|
||||
#undef TINST
|
||||
|
||||
#include "GuRaycastTests.h"
|
||||
#include "geometry/PxTriangleMeshGeometry.h"
|
||||
#include "GuTriangleMesh.h"
|
||||
#include "CmScaling.h"
|
||||
|
||||
struct RayMeshColliderCallback : public MeshHitCallback<PxGeomRaycastHit>
|
||||
{
|
||||
PxU8* mDstBase;
|
||||
PxU32 mHitNum;
|
||||
const PxU32 mMaxHits;
|
||||
const PxU32 mStride;
|
||||
const PxMeshScale* mScale;
|
||||
const PxTransform* mPose;
|
||||
const PxMat34* mWorld2vertexSkew;
|
||||
PxU32 mHitFlags;
|
||||
const PxVec3& mRayDir;
|
||||
bool mIsDoubleSided;
|
||||
float mDistCoeff;
|
||||
|
||||
RayMeshColliderCallback(
|
||||
CallbackMode::Enum mode_, PxGeomRaycastHit* hits, PxU32 maxHits, PxU32 stride, const PxMeshScale* scale, const PxTransform* pose,
|
||||
const PxMat34* world2vertexSkew, PxU32 hitFlags, const PxVec3& rayDir, bool isDoubleSided, float distCoeff) :
|
||||
MeshHitCallback<PxGeomRaycastHit> (mode_),
|
||||
mDstBase (reinterpret_cast<PxU8*>(hits)),
|
||||
mHitNum (0),
|
||||
mMaxHits (maxHits),
|
||||
mStride (stride),
|
||||
mScale (scale),
|
||||
mPose (pose),
|
||||
mWorld2vertexSkew (world2vertexSkew),
|
||||
mHitFlags (hitFlags),
|
||||
mRayDir (rayDir),
|
||||
mIsDoubleSided (isDoubleSided),
|
||||
mDistCoeff (distCoeff)
|
||||
{
|
||||
}
|
||||
|
||||
// return false for early out
|
||||
virtual bool processHit(
|
||||
const PxGeomRaycastHit& lHit, const PxVec3& lp0, const PxVec3& lp1, const PxVec3& lp2, PxReal&, const PxU32*)
|
||||
{
|
||||
if(mHitNum == mMaxHits)
|
||||
return false;
|
||||
|
||||
const PxReal u = lHit.u, v = lHit.v;
|
||||
const PxVec3 localImpact = (1.0f - u - v)*lp0 + u*lp1 + v*lp2;
|
||||
|
||||
//not worth concatenating to do 1 transform: PxMat34Legacy vertex2worldSkew = scaling.getVertex2WorldSkew(absPose);
|
||||
// PT: TODO: revisit this for N hits
|
||||
PxGeomRaycastHit& hit = *reinterpret_cast<PxGeomRaycastHit*>(mDstBase);
|
||||
hit = lHit;
|
||||
|
||||
hit.position = mPose->transform(mScale->transform(localImpact));
|
||||
hit.flags = PxHitFlag::ePOSITION|PxHitFlag::eUV|PxHitFlag::eFACE_INDEX;
|
||||
hit.normal = PxVec3(0.0f);
|
||||
hit.distance *= mDistCoeff;
|
||||
|
||||
// Compute additional information if needed
|
||||
if(mHitFlags & PxHitFlag::eNORMAL)
|
||||
{
|
||||
// User requested impact normal
|
||||
const PxVec3 localNormal = (lp1 - lp0).cross(lp2 - lp0);
|
||||
|
||||
if(mWorld2vertexSkew)
|
||||
{
|
||||
hit.normal = mWorld2vertexSkew->rotateTranspose(localNormal);
|
||||
if (mScale->hasNegativeDeterminant())
|
||||
PxSwap<PxReal>(hit.u, hit.v); // have to swap the UVs though since they were computed in mesh local space
|
||||
}
|
||||
else
|
||||
hit.normal = mPose->rotate(localNormal);
|
||||
hit.normal.normalize();
|
||||
|
||||
// PT: figure out correct normal orientation (DE7458)
|
||||
// - if the mesh is single-sided the normal should be the regular triangle normal N, regardless of eMESH_BOTH_SIDES.
|
||||
// - if the mesh is double-sided the correct normal can be either N or -N. We take the one opposed to ray direction.
|
||||
if(mIsDoubleSided && hit.normal.dot(mRayDir) > 0.0f)
|
||||
hit.normal = -hit.normal;
|
||||
|
||||
hit.flags |= PxHitFlag::eNORMAL;
|
||||
}
|
||||
|
||||
mHitNum++;
|
||||
mDstBase += mStride;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
RayMeshColliderCallback& operator=(const RayMeshColliderCallback&);
|
||||
};
|
||||
|
||||
PxU32 physx::Gu::raycast_triangleMesh_RTREE(const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose,
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir, PxReal maxDist,
|
||||
PxHitFlags hitFlags, PxU32 maxHits, PxGeomRaycastHit* PX_RESTRICT hits, PxU32 stride)
|
||||
{
|
||||
PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
|
||||
const RTreeTriangleMesh* meshData = static_cast<const RTreeTriangleMesh*>(mesh);
|
||||
|
||||
//scaling: transform the ray to vertex space
|
||||
|
||||
PxVec3 orig, dir;
|
||||
PxMat34 world2vertexSkew;
|
||||
PxMat34* world2vertexSkewP = NULL;
|
||||
PxReal distCoeff = 1.0f;
|
||||
if(meshGeom.scale.isIdentity())
|
||||
{
|
||||
orig = pose.transformInv(rayOrigin);
|
||||
dir = pose.rotateInv(rayDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
world2vertexSkew = meshGeom.scale.getInverse() * pose.getInverse();
|
||||
world2vertexSkewP = &world2vertexSkew;
|
||||
orig = world2vertexSkew.transform(rayOrigin);
|
||||
dir = world2vertexSkew.rotate(rayDir);
|
||||
{
|
||||
distCoeff = dir.normalize();
|
||||
maxDist *= distCoeff;
|
||||
maxDist += 1e-3f;
|
||||
distCoeff = 1.0f / distCoeff;
|
||||
}
|
||||
}
|
||||
|
||||
const bool isDoubleSided = meshGeom.meshFlags.isSet(PxMeshGeometryFlag::eDOUBLE_SIDED);
|
||||
const bool bothSides = isDoubleSided || (hitFlags & PxHitFlag::eMESH_BOTH_SIDES);
|
||||
|
||||
const bool multipleHits = hitFlags & PxHitFlag::eMESH_MULTIPLE;
|
||||
|
||||
RayMeshColliderCallback callback(
|
||||
multipleHits ? CallbackMode::eMULTIPLE : (hitFlags & PxHitFlag::eANY_HIT ? CallbackMode::eANY : CallbackMode::eCLOSEST),
|
||||
hits, maxHits, stride, &meshGeom.scale, &pose, world2vertexSkewP, hitFlags, rayDir, isDoubleSided, distCoeff);
|
||||
|
||||
MeshRayCollider::collide<0, 1>(orig, dir, maxDist, bothSides, static_cast<const RTreeTriangleMesh*>(meshData), callback, NULL);
|
||||
return callback.mHitNum;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
\brief returns indices for the largest axis and 2 other axii
|
||||
*/
|
||||
PX_FORCE_INLINE PxU32 largestAxis(const PxVec3& v, PxU32& other1, PxU32& other2)
|
||||
{
|
||||
if (v.x >= PxMax(v.y, v.z))
|
||||
{
|
||||
other1 = 1;
|
||||
other2 = 2;
|
||||
return 0;
|
||||
}
|
||||
else if (v.y >= v.z)
|
||||
{
|
||||
other1 = 0;
|
||||
other2 = 2;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
other1 = 0;
|
||||
other2 = 1;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
static PX_INLINE void computeSweptAABBAroundOBB(
|
||||
const Box& obb, PxVec3& sweepOrigin, PxVec3& sweepExtents, PxVec3& sweepDir, PxReal& sweepLen)
|
||||
{
|
||||
PxU32 other1, other2;
|
||||
// largest axis of the OBB is the sweep direction, sum of abs of two other is the swept AABB extents
|
||||
PxU32 lai = largestAxis(obb.extents, other1, other2);
|
||||
PxVec3 longestAxis = obb.rot[lai]*obb.extents[lai];
|
||||
PxVec3 absOther1 = obb.rot[other1].abs()*obb.extents[other1];
|
||||
PxVec3 absOther2 = obb.rot[other2].abs()*obb.extents[other2];
|
||||
sweepOrigin = obb.center - longestAxis;
|
||||
sweepExtents = absOther1 + absOther2 + PxVec3(GU_MIN_AABB_EXTENT); // see comments for GU_MIN_AABB_EXTENT
|
||||
sweepLen = 2.0f; // length is already included in longestAxis
|
||||
sweepDir = longestAxis;
|
||||
}
|
||||
|
||||
enum { eSPHERE, eCAPSULE, eBOX }; // values for tSCB
|
||||
|
||||
#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.
|
||||
#pragma warning( disable : 4512 ) // assignment operator could not be generated
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
struct IntersectShapeVsMeshCallback : MeshHitCallback<PxGeomRaycastHit>
|
||||
{
|
||||
PX_NOCOPY(IntersectShapeVsMeshCallback)
|
||||
public:
|
||||
IntersectShapeVsMeshCallback(const PxMat33& vertexToShapeSkew, LimitedResults* results, bool flipNormal)
|
||||
: MeshHitCallback<PxGeomRaycastHit>(CallbackMode::eMULTIPLE),
|
||||
mVertexToShapeSkew (vertexToShapeSkew),
|
||||
mResults (results),
|
||||
mAnyHits (false),
|
||||
mFlipNormal (flipNormal)
|
||||
{
|
||||
}
|
||||
virtual ~IntersectShapeVsMeshCallback(){}
|
||||
|
||||
const PxMat33& mVertexToShapeSkew; // vertex to box without translation for boxes
|
||||
LimitedResults* mResults;
|
||||
bool mAnyHits;
|
||||
bool mFlipNormal;
|
||||
|
||||
PX_FORCE_INLINE bool recordHit(const PxGeomRaycastHit& aHit, PxIntBool hit)
|
||||
{
|
||||
if(hit)
|
||||
{
|
||||
mAnyHits = true;
|
||||
if(mResults)
|
||||
mResults->add(aHit.faceIndex);
|
||||
else
|
||||
return false; // abort traversal if we are only interested in firstContact (mResults is NULL)
|
||||
}
|
||||
return true; // if we are here, either no triangles were hit or multiple results are expected => continue traversal
|
||||
}
|
||||
};
|
||||
|
||||
template<bool tScaleIsIdentity>
|
||||
struct IntersectSphereVsMeshCallback : IntersectShapeVsMeshCallback
|
||||
{
|
||||
IntersectSphereVsMeshCallback(const PxMat33& m, LimitedResults* r, bool flipNormal) : IntersectShapeVsMeshCallback(m, r, flipNormal) {}
|
||||
virtual ~IntersectSphereVsMeshCallback(){}
|
||||
PxF32 mMinDist2;
|
||||
PxVec3 mLocalCenter; // PT: sphere center in local/mesh space
|
||||
|
||||
virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit& aHit, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2, PxReal&, const PxU32*)
|
||||
{
|
||||
const Vec3V v0 = V3LoadU(tScaleIsIdentity ? av0 : mVertexToShapeSkew * av0);
|
||||
const Vec3V v1 = V3LoadU(tScaleIsIdentity ? av1 : mVertexToShapeSkew * (mFlipNormal ? av2 : av1));
|
||||
const Vec3V v2 = V3LoadU(tScaleIsIdentity ? av2 : mVertexToShapeSkew * (mFlipNormal ? av1 : av2));
|
||||
|
||||
FloatV dummy1, dummy2;
|
||||
Vec3V closestP;
|
||||
PxReal dist2;
|
||||
FStore(distancePointTriangleSquared(V3LoadU(mLocalCenter), v0, v1, v2, dummy1, dummy2, closestP), &dist2);
|
||||
return recordHit(aHit, dist2 <= mMinDist2);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool tScaleIsIdentity>
|
||||
struct IntersectCapsuleVsMeshCallback : IntersectShapeVsMeshCallback
|
||||
{
|
||||
IntersectCapsuleVsMeshCallback(const PxMat33& m, LimitedResults* r, bool flipNormal) : IntersectShapeVsMeshCallback(m, r, flipNormal) {}
|
||||
virtual ~IntersectCapsuleVsMeshCallback(){}
|
||||
|
||||
Capsule mLocalCapsule; // PT: capsule in mesh/local space
|
||||
CapsuleTriangleOverlapData mParams;
|
||||
|
||||
virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit& aHit, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2, PxReal&, const PxU32*)
|
||||
{
|
||||
bool hit;
|
||||
if(tScaleIsIdentity)
|
||||
{
|
||||
const PxVec3 normal = (av0 - av1).cross(av0 - av2);
|
||||
hit = intersectCapsuleTriangle(normal, av0, av1, av2, mLocalCapsule, mParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxVec3 v0 = mVertexToShapeSkew * av0;
|
||||
const PxVec3 v1 = mVertexToShapeSkew * (mFlipNormal ? av2 : av1);
|
||||
const PxVec3 v2 = mVertexToShapeSkew * (mFlipNormal ? av1 : av2);
|
||||
const PxVec3 normal = (v0 - v1).cross(v0 - v2);
|
||||
hit = intersectCapsuleTriangle(normal, v0, v1, v2, mLocalCapsule, mParams);
|
||||
}
|
||||
return recordHit(aHit, hit);
|
||||
}
|
||||
};
|
||||
|
||||
template<bool tScaleIsIdentity>
|
||||
struct IntersectBoxVsMeshCallback : IntersectShapeVsMeshCallback
|
||||
{
|
||||
IntersectBoxVsMeshCallback(const PxMat33& m, LimitedResults* r, bool flipNormal) : IntersectShapeVsMeshCallback(m, r, flipNormal) {}
|
||||
virtual ~IntersectBoxVsMeshCallback(){}
|
||||
|
||||
PxMat34 mVertexToBox;
|
||||
PxVec3p mBoxExtents, mBoxCenter;
|
||||
|
||||
virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit& aHit, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2, PxReal&, const PxU32*)
|
||||
{
|
||||
PxVec3p v0, v1, v2;
|
||||
if(tScaleIsIdentity)
|
||||
{
|
||||
v0 = mVertexToShapeSkew * av0; // transform from skewed mesh vertex to box space,
|
||||
v1 = mVertexToShapeSkew * av1; // this includes inverse skew, inverse mesh shape transform and inverse box basis
|
||||
v2 = mVertexToShapeSkew * av2;
|
||||
}
|
||||
else
|
||||
{
|
||||
v0 = mVertexToBox.transform(av0);
|
||||
v1 = mVertexToBox.transform(mFlipNormal ? av2 : av1);
|
||||
v2 = mVertexToBox.transform(mFlipNormal ? av1 : av2);
|
||||
}
|
||||
|
||||
// PT: this one is safe because we're using PxVec3p for all parameters
|
||||
const PxIntBool hit = intersectTriangleBox_Unsafe(mBoxCenter, mBoxExtents, v0, v1, v2);
|
||||
return recordHit(aHit, hit);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template<int tSCB, bool idtMeshScale>
|
||||
static bool intersectAnyVsMeshT(
|
||||
const Sphere* worldSphere, const Capsule* worldCapsule, const Box* worldOBB,
|
||||
const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale,
|
||||
LimitedResults* results)
|
||||
{
|
||||
const bool flipNormal = meshScale.hasNegativeDeterminant();
|
||||
PxMat33 shapeToVertexSkew, vertexToShapeSkew;
|
||||
if (!idtMeshScale && tSCB != eBOX)
|
||||
{
|
||||
vertexToShapeSkew = toMat33(meshScale);
|
||||
shapeToVertexSkew = vertexToShapeSkew.getInverse();
|
||||
}
|
||||
|
||||
if (tSCB == eSPHERE)
|
||||
{
|
||||
IntersectSphereVsMeshCallback<idtMeshScale> callback(vertexToShapeSkew, results, flipNormal);
|
||||
// transform sphere center from world to mesh shape space
|
||||
const PxVec3 center = meshTransform.transformInv(worldSphere->center);
|
||||
|
||||
// callback will transform verts
|
||||
callback.mLocalCenter = center;
|
||||
callback.mMinDist2 = worldSphere->radius*worldSphere->radius;
|
||||
|
||||
PxVec3 sweepOrigin, sweepDir, sweepExtents;
|
||||
PxReal sweepLen;
|
||||
if (!idtMeshScale)
|
||||
{
|
||||
// AP: compute a swept AABB around an OBB around a skewed sphere
|
||||
// TODO: we could do better than an AABB around OBB actually because we can slice off the corners..
|
||||
const Box worldOBB_(worldSphere->center, PxVec3(worldSphere->radius), PxMat33(PxIdentity));
|
||||
Box vertexOBB;
|
||||
computeVertexSpaceOBB(vertexOBB, worldOBB_, meshTransform, meshScale);
|
||||
computeSweptAABBAroundOBB(vertexOBB, sweepOrigin, sweepExtents, sweepDir, sweepLen);
|
||||
} else
|
||||
{
|
||||
sweepOrigin = center;
|
||||
sweepDir = PxVec3(1.0f,0,0);
|
||||
sweepLen = 0.0f;
|
||||
sweepExtents = PxVec3(PxMax(worldSphere->radius, GU_MIN_AABB_EXTENT));
|
||||
}
|
||||
|
||||
MeshRayCollider::collide<1, 1>(sweepOrigin, sweepDir, sweepLen, true, static_cast<const RTreeTriangleMesh*>(&triMesh), callback, &sweepExtents);
|
||||
|
||||
return callback.mAnyHits;
|
||||
}
|
||||
else if (tSCB == eCAPSULE)
|
||||
{
|
||||
IntersectCapsuleVsMeshCallback<idtMeshScale> callback(vertexToShapeSkew, results, flipNormal);
|
||||
const PxF32 radius = worldCapsule->radius;
|
||||
|
||||
// transform world capsule to mesh shape space
|
||||
callback.mLocalCapsule.p0 = meshTransform.transformInv(worldCapsule->p0);
|
||||
callback.mLocalCapsule.p1 = meshTransform.transformInv(worldCapsule->p1);
|
||||
callback.mLocalCapsule.radius = radius;
|
||||
callback.mParams.init(callback.mLocalCapsule);
|
||||
|
||||
if (idtMeshScale)
|
||||
{
|
||||
// traverse a sweptAABB around the capsule
|
||||
const PxVec3 radius3(radius);
|
||||
MeshRayCollider::collide<1, 0>(callback.mLocalCapsule.p0, callback.mLocalCapsule.p1-callback.mLocalCapsule.p0, 1.0f, true, static_cast<const RTreeTriangleMesh*>(&triMesh), callback, &radius3);
|
||||
}
|
||||
else
|
||||
{
|
||||
// make vertex space OBB
|
||||
Box vertexOBB;
|
||||
Box worldOBB_;
|
||||
worldOBB_.create(*worldCapsule); // AP: potential optimization (meshTransform.inverse is already in callback.mCapsule)
|
||||
computeVertexSpaceOBB(vertexOBB, worldOBB_, meshTransform, meshScale);
|
||||
|
||||
MeshRayCollider::collideOBB(vertexOBB, true, static_cast<const RTreeTriangleMesh*>(&triMesh), callback);
|
||||
}
|
||||
return callback.mAnyHits;
|
||||
}
|
||||
else if (tSCB == eBOX)
|
||||
{
|
||||
Box vertexOBB; // query box in vertex space
|
||||
if (idtMeshScale)
|
||||
{
|
||||
// mesh scale is identity - just inverse transform the box without optimization
|
||||
vertexOBB = transformBoxOrthonormal(*worldOBB, meshTransform.getInverse());
|
||||
// mesh vertices will be transformed from skewed vertex space directly to box AABB space
|
||||
// box inverse rotation is baked into the vertexToShapeSkew transform
|
||||
// if meshScale is not identity, vertexOBB already effectively includes meshScale transform
|
||||
PxVec3 boxCenter;
|
||||
getInverse(vertexToShapeSkew, boxCenter, vertexOBB.rot, vertexOBB.center);
|
||||
IntersectBoxVsMeshCallback<idtMeshScale> callback(vertexToShapeSkew, results, flipNormal);
|
||||
|
||||
callback.mBoxCenter = -boxCenter;
|
||||
callback.mBoxExtents = worldOBB->extents; // extents do not change
|
||||
|
||||
MeshRayCollider::collideOBB(vertexOBB, true, static_cast<const RTreeTriangleMesh*>(&triMesh), callback);
|
||||
|
||||
return callback.mAnyHits;
|
||||
} else
|
||||
{
|
||||
computeVertexSpaceOBB(vertexOBB, *worldOBB, meshTransform, meshScale);
|
||||
|
||||
// mesh scale needs to be included - inverse transform and optimize the box
|
||||
const PxMat33 vertexToWorldSkew_Rot = PxMat33Padded(meshTransform.q) * toMat33(meshScale);
|
||||
const PxVec3& vertexToWorldSkew_Trans = meshTransform.p;
|
||||
|
||||
PxMat34 tmp;
|
||||
buildMatrixFromBox(tmp, *worldOBB);
|
||||
const PxMat34 inv = tmp.getInverseRT();
|
||||
const PxMat34 _vertexToWorldSkew(vertexToWorldSkew_Rot, vertexToWorldSkew_Trans);
|
||||
|
||||
IntersectBoxVsMeshCallback<idtMeshScale> callback(vertexToShapeSkew, results, flipNormal);
|
||||
callback.mVertexToBox = inv * _vertexToWorldSkew;
|
||||
callback.mBoxCenter = PxVec3(0.0f);
|
||||
callback.mBoxExtents = worldOBB->extents; // extents do not change
|
||||
|
||||
MeshRayCollider::collideOBB(vertexOBB, true, static_cast<const RTreeTriangleMesh*>(&triMesh), callback);
|
||||
|
||||
return callback.mAnyHits;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PX_ASSERT(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<int tSCB>
|
||||
static bool intersectAnyVsMesh(
|
||||
const Sphere* worldSphere, const Capsule* worldCapsule, const Box* worldOBB,
|
||||
const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale,
|
||||
LimitedResults* results)
|
||||
{
|
||||
PX_ASSERT(triMesh.getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
if (meshScale.isIdentity())
|
||||
return intersectAnyVsMeshT<tSCB, true>(worldSphere, worldCapsule, worldOBB, triMesh, meshTransform, meshScale, results);
|
||||
else
|
||||
return intersectAnyVsMeshT<tSCB, false>(worldSphere, worldCapsule, worldOBB, triMesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
bool physx::Gu::intersectSphereVsMesh_RTREE(const Sphere& sphere, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results)
|
||||
{
|
||||
return intersectAnyVsMesh<eSPHERE>(&sphere, NULL, NULL, triMesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
bool physx::Gu::intersectBoxVsMesh_RTREE(const Box& box, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results)
|
||||
{
|
||||
return intersectAnyVsMesh<eBOX>(NULL, NULL, &box, triMesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
bool physx::Gu::intersectCapsuleVsMesh_RTREE(const Capsule& capsule, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results)
|
||||
{
|
||||
return intersectAnyVsMesh<eCAPSULE>(NULL, &capsule, NULL, triMesh, meshTransform, meshScale, results);
|
||||
}
|
||||
|
||||
void physx::Gu::intersectOBB_RTREE(const TriangleMesh* mesh, const Box& obb, MeshHitCallback<PxGeomRaycastHit>& callback, bool bothTriangleSidesCollide, bool checkObbIsAligned)
|
||||
{
|
||||
MeshRayCollider::collideOBB(obb, bothTriangleSidesCollide, static_cast<const RTreeTriangleMesh*>(mesh), callback, checkObbIsAligned);
|
||||
}
|
||||
|
||||
// PT: TODO: refactor/share bits of this
|
||||
bool physx::Gu::sweepCapsule_MeshGeom_RTREE(const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Capsule& lss, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation)
|
||||
{
|
||||
PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
const RTreeTriangleMesh* meshData = static_cast<const RTreeTriangleMesh*>(mesh);
|
||||
|
||||
const Capsule inflatedCapsule(lss.p0, lss.p1, lss.radius + inflation);
|
||||
|
||||
const bool isIdentity = triMeshGeom.scale.isIdentity();
|
||||
bool isDoubleSided = (triMeshGeom.meshFlags & PxMeshGeometryFlag::eDOUBLE_SIDED);
|
||||
const PxU32 meshBothSides = hitFlags & PxHitFlag::eMESH_BOTH_SIDES;
|
||||
|
||||
// compute sweptAABB
|
||||
const PxVec3 localP0 = pose.transformInv(inflatedCapsule.p0);
|
||||
const PxVec3 localP1 = pose.transformInv(inflatedCapsule.p1);
|
||||
PxVec3 sweepOrigin = (localP0+localP1)*0.5f;
|
||||
PxVec3 sweepDir = pose.rotateInv(unitDir);
|
||||
PxVec3 sweepExtents = PxVec3(inflatedCapsule.radius) + (localP0-localP1).abs()*0.5f;
|
||||
PxReal distance1 = distance;
|
||||
PxReal distCoeff = 1.0f;
|
||||
PxMat34 poseWithScale;
|
||||
if(!isIdentity)
|
||||
{
|
||||
poseWithScale = pose * triMeshGeom.scale;
|
||||
distance1 = computeSweepData(triMeshGeom, sweepOrigin, sweepExtents, sweepDir, distance);
|
||||
distCoeff = distance1 / distance;
|
||||
} else
|
||||
poseWithScale = Matrix34FromTransform(pose);
|
||||
|
||||
SweepCapsuleMeshHitCallback callback(sweepHit, poseWithScale, distance, isDoubleSided, inflatedCapsule, unitDir, hitFlags, triMeshGeom.scale.hasNegativeDeterminant(), distCoeff);
|
||||
|
||||
MeshRayCollider::collide<1, 1>(sweepOrigin, sweepDir, distance1, true, meshData, callback, &sweepExtents);
|
||||
|
||||
if(meshBothSides)
|
||||
isDoubleSided = true;
|
||||
|
||||
return callback.finalizeHit(sweepHit, inflatedCapsule, triMeshGeom, pose, isDoubleSided);
|
||||
}
|
||||
|
||||
#include "GuSweepSharedTests.h"
|
||||
|
||||
// PT: TODO: refactor/share bits of this
|
||||
bool physx::Gu::sweepBox_MeshGeom_RTREE(const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const Box& box, const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& sweepHit, PxHitFlags hitFlags, PxReal inflation)
|
||||
{
|
||||
PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
const RTreeTriangleMesh* meshData = static_cast<const RTreeTriangleMesh*>(mesh);
|
||||
|
||||
const bool isIdentity = triMeshGeom.scale.isIdentity();
|
||||
|
||||
const bool meshBothSides = hitFlags & PxHitFlag::eMESH_BOTH_SIDES;
|
||||
const bool isDoubleSided = triMeshGeom.meshFlags & PxMeshGeometryFlag::eDOUBLE_SIDED;
|
||||
|
||||
PxMat34 meshToWorldSkew;
|
||||
PxVec3 sweptAABBMeshSpaceExtents, meshSpaceOrigin, meshSpaceDir;
|
||||
|
||||
// Input sweep params: geom, pose, box, unitDir, distance
|
||||
// We convert the origin from world space to mesh local space
|
||||
// and convert the box+pose to mesh space AABB
|
||||
if(isIdentity)
|
||||
{
|
||||
meshToWorldSkew = Matrix34FromTransform(pose);
|
||||
const PxMat33Padded worldToMeshRot(pose.q.getConjugate()); // extract rotation matrix from pose.q
|
||||
meshSpaceOrigin = worldToMeshRot.transform(box.center - pose.p);
|
||||
meshSpaceDir = worldToMeshRot.transform(unitDir) * distance;
|
||||
const PxMat33 boxToMeshRot = worldToMeshRot * box.rot;
|
||||
sweptAABBMeshSpaceExtents = boxToMeshRot.column0.abs() * box.extents.x +
|
||||
boxToMeshRot.column1.abs() * box.extents.y +
|
||||
boxToMeshRot.column2.abs() * box.extents.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
meshToWorldSkew = pose * triMeshGeom.scale;
|
||||
const PxMat33 meshToWorldSkew_Rot = PxMat33Padded(pose.q) * toMat33(triMeshGeom.scale);
|
||||
const PxVec3& meshToWorldSkew_Trans = pose.p;
|
||||
|
||||
PxMat33 worldToVertexSkew_Rot;
|
||||
PxVec3 worldToVertexSkew_Trans;
|
||||
getInverse(worldToVertexSkew_Rot, worldToVertexSkew_Trans, meshToWorldSkew_Rot, meshToWorldSkew_Trans);
|
||||
|
||||
//make vertex space OBB
|
||||
Box vertexSpaceBox1;
|
||||
const PxMat34 worldToVertexSkew(worldToVertexSkew_Rot, worldToVertexSkew_Trans);
|
||||
vertexSpaceBox1 = transform(worldToVertexSkew, box);
|
||||
// compute swept aabb
|
||||
sweptAABBMeshSpaceExtents = vertexSpaceBox1.computeAABBExtent();
|
||||
|
||||
meshSpaceOrigin = worldToVertexSkew.transform(box.center);
|
||||
meshSpaceDir = worldToVertexSkew.rotate(unitDir*distance); // also applies scale to direction/length
|
||||
}
|
||||
|
||||
sweptAABBMeshSpaceExtents += PxVec3(inflation); // inflate the bounds with additive inflation
|
||||
sweptAABBMeshSpaceExtents *= 1.01f; // fatten the bounds to account for numerical discrepancies
|
||||
|
||||
PxReal dirLen = PxMax(meshSpaceDir.magnitude(), 1e-5f);
|
||||
PxReal distCoeff = 1.0f;
|
||||
if (!isIdentity)
|
||||
distCoeff = dirLen / distance;
|
||||
|
||||
// Move to AABB space
|
||||
PxMat34 worldToBox;
|
||||
computeWorldToBoxMatrix(worldToBox, box);
|
||||
|
||||
const bool bothTriangleSidesCollide = isDoubleSided || meshBothSides;
|
||||
|
||||
const PxMat34Padded meshToBox = worldToBox*meshToWorldSkew;
|
||||
const PxTransform boxTransform = box.getTransform();
|
||||
|
||||
const PxVec3 localDir = worldToBox.rotate(unitDir);
|
||||
const PxVec3 localDirDist = localDir*distance;
|
||||
SweepBoxMeshHitCallback callback( // using eMULTIPLE with shrinkMaxT
|
||||
CallbackMode::eMULTIPLE, meshToBox, distance, bothTriangleSidesCollide, box, localDirDist, localDir, unitDir, hitFlags, inflation, triMeshGeom.scale.hasNegativeDeterminant(), distCoeff);
|
||||
|
||||
MeshRayCollider::collide<1, 1>(meshSpaceOrigin, meshSpaceDir/dirLen, dirLen, bothTriangleSidesCollide, meshData, callback, &sweptAABBMeshSpaceExtents);
|
||||
|
||||
return callback.finalizeHit(sweepHit, triMeshGeom, pose, boxTransform, localDir, meshBothSides, isDoubleSided);
|
||||
}
|
||||
|
||||
#include "GuInternal.h"
|
||||
void physx::Gu::sweepConvex_MeshGeom_RTREE(const TriangleMesh* mesh, const Box& hullBox, const PxVec3& localDir, PxReal distance, SweepConvexMeshHitCallback& callback, bool)
|
||||
{
|
||||
PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH33);
|
||||
const RTreeTriangleMesh* meshData = static_cast<const RTreeTriangleMesh*>(mesh);
|
||||
|
||||
// create temporal bounds
|
||||
Box querySweptBox;
|
||||
computeSweptBox(querySweptBox, hullBox.extents, hullBox.center, hullBox.rot, localDir, distance);
|
||||
|
||||
MeshRayCollider::collideOBB(querySweptBox, true, meshData, callback);
|
||||
}
|
||||
|
||||
void physx::Gu::pointMeshDistance_RTREE(const TriangleMesh*, const PxTriangleMeshGeometry&, const PxTransform&, const PxVec3&, float, PxU32&, float&, PxVec3&)
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "Point-mesh distance query not supported for BVH33. Please use a BVH34 mesh.\n");
|
||||
}
|
||||
354
engine/third_party/physx/source/geomutils/src/mesh/GuOverlapTestsMesh.cpp
vendored
Normal file
354
engine/third_party/physx/source/geomutils/src/mesh/GuOverlapTestsMesh.cpp
vendored
Normal file
@@ -0,0 +1,354 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "geometry/PxSphereGeometry.h"
|
||||
#include "geometry/PxConvexCoreGeometry.h"
|
||||
#include "GuMidphaseInterface.h"
|
||||
#include "CmScaling.h"
|
||||
#include "GuSphere.h"
|
||||
#include "GuInternal.h"
|
||||
#include "GuConvexUtilsInternal.h"
|
||||
#include "GuVecTriangle.h"
|
||||
#include "GuVecConvexHull.h"
|
||||
#include "GuConvexMesh.h"
|
||||
#include "GuGJK.h"
|
||||
#include "GuSweepSharedTests.h"
|
||||
#include "CmMatrix34.h"
|
||||
#include "GuBounds.h"
|
||||
#include "GuConvexSupport.h"
|
||||
#include "GuConvexGeometry.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Cm;
|
||||
using namespace Gu;
|
||||
using namespace aos;
|
||||
|
||||
bool GeomOverlapCallback_SphereMesh(GU_OVERLAP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
|
||||
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(cache);
|
||||
PX_UNUSED(threadContext);
|
||||
|
||||
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
|
||||
|
||||
const Sphere worldSphere(pose0.p, sphereGeom.radius);
|
||||
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
return Midphase::intersectSphereVsMesh(worldSphere, *meshData, pose1, meshGeom.scale, NULL);
|
||||
}
|
||||
|
||||
bool GeomOverlapCallback_CapsuleMesh(GU_OVERLAP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom0.getType()==PxGeometryType::eCAPSULE);
|
||||
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(cache);
|
||||
PX_UNUSED(threadContext);
|
||||
|
||||
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom0);
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
|
||||
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
Capsule capsule;
|
||||
getCapsule(capsule, capsuleGeom, pose0);
|
||||
return Midphase::intersectCapsuleVsMesh(capsule, *meshData, pose1, meshGeom.scale, NULL);
|
||||
}
|
||||
|
||||
bool GeomOverlapCallback_BoxMesh(GU_OVERLAP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom0.getType()==PxGeometryType::eBOX);
|
||||
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(cache);
|
||||
PX_UNUSED(threadContext);
|
||||
|
||||
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom0);
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
|
||||
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
Box box;
|
||||
buildFrom(box, pose0.p, boxGeom.halfExtents, pose0.q);
|
||||
return Midphase::intersectBoxVsMesh(box, *meshData, pose1, meshGeom.scale, NULL);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace
|
||||
{
|
||||
struct ConvexVsMeshOverlapCallback : MeshHitCallback<PxGeomRaycastHit>
|
||||
{
|
||||
PxMatTransformV MeshToBoxV;
|
||||
Vec3V boxExtents;
|
||||
|
||||
ConvexVsMeshOverlapCallback(
|
||||
const ConvexMesh& cm, const PxMeshScale& convexScale, const FastVertex2ShapeScaling& meshScale,
|
||||
const PxTransform& tr0, const PxTransform& tr1, bool identityScale, const Box& meshSpaceOBB)
|
||||
:
|
||||
MeshHitCallback<PxGeomRaycastHit>(CallbackMode::eMULTIPLE),
|
||||
mAnyHit (false),
|
||||
mIdentityScale (identityScale)
|
||||
{
|
||||
if (!identityScale) // not done in initializer list for performance
|
||||
mMeshScale = aos::Mat33V(
|
||||
V3LoadU(meshScale.getVertex2ShapeSkew().column0),
|
||||
V3LoadU(meshScale.getVertex2ShapeSkew().column1),
|
||||
V3LoadU(meshScale.getVertex2ShapeSkew().column2) );
|
||||
using namespace aos;
|
||||
|
||||
const ConvexHullData* hullData = &cm.getHull();
|
||||
|
||||
const Vec3V vScale0 = V3LoadU_SafeReadW(convexScale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
|
||||
const QuatV vQuat0 = QuatVLoadU(&convexScale.rotation.x);
|
||||
|
||||
mConvex = ConvexHullV(hullData, V3Zero(), vScale0, vQuat0, convexScale.isIdentity());
|
||||
aToB = PxMatTransformV(tr0.transformInv(tr1));
|
||||
|
||||
{
|
||||
// Move to AABB space
|
||||
PxMat34 MeshToBox;
|
||||
computeWorldToBoxMatrix(MeshToBox, meshSpaceOBB);
|
||||
|
||||
const Vec3V base0 = V3LoadU(MeshToBox.m.column0);
|
||||
const Vec3V base1 = V3LoadU(MeshToBox.m.column1);
|
||||
const Vec3V base2 = V3LoadU(MeshToBox.m.column2);
|
||||
const Mat33V matV(base0, base1, base2);
|
||||
const Vec3V p = V3LoadU(MeshToBox.p);
|
||||
MeshToBoxV = PxMatTransformV(p, matV);
|
||||
boxExtents = V3LoadU(meshSpaceOBB.extents+PxVec3(0.001f));
|
||||
}
|
||||
}
|
||||
virtual ~ConvexVsMeshOverlapCallback() {}
|
||||
|
||||
virtual PxAgain processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit&, const PxVec3& v0a, const PxVec3& v1a, const PxVec3& v2a, PxReal&, const PxU32*)
|
||||
{
|
||||
using namespace aos;
|
||||
Vec3V v0 = V3LoadU(v0a);
|
||||
Vec3V v1 = V3LoadU(v1a);
|
||||
Vec3V v2 = V3LoadU(v2a);
|
||||
|
||||
// test triangle AABB in box space vs box AABB in box local space
|
||||
{
|
||||
const Vec3V triV0 = MeshToBoxV.transform(v0); // AP: MeshToBoxV already includes mesh scale so we have to use unscaled verts here
|
||||
const Vec3V triV1 = MeshToBoxV.transform(v1);
|
||||
const Vec3V triV2 = MeshToBoxV.transform(v2);
|
||||
const Vec3V triMn = V3Min(V3Min(triV0, triV1), triV2);
|
||||
const Vec3V triMx = V3Max(V3Max(triV0, triV1), triV2);
|
||||
const Vec3V negExtents = V3Neg(boxExtents);
|
||||
const BoolV minSeparated = V3IsGrtr(triMn, boxExtents), maxSeparated = V3IsGrtr(negExtents, triMx);
|
||||
const BoolV bSeparated = BAnyTrue3(BOr(minSeparated, maxSeparated));
|
||||
if(BAllEqTTTT(bSeparated))
|
||||
return true; // continue traversal
|
||||
}
|
||||
|
||||
if(!mIdentityScale)
|
||||
{
|
||||
v0 = M33MulV3(mMeshScale, v0);
|
||||
v1 = M33MulV3(mMeshScale, v1);
|
||||
v2 = M33MulV3(mMeshScale, v2);
|
||||
}
|
||||
|
||||
TriangleV triangle(v0, v1, v2);
|
||||
Vec3V contactA, contactB, normal;
|
||||
FloatV dist;
|
||||
const RelativeConvex<TriangleV> convexA(triangle, aToB);
|
||||
const LocalConvex<ConvexHullV> convexB(mConvex);
|
||||
const GjkStatus status = gjk(convexA, convexB, aToB.p, FZero(), contactA, contactB, normal, dist);
|
||||
if(status == GJK_CONTACT || status == GJK_CLOSE)// || FAllGrtrOrEq(mSqTolerance, sqDist))
|
||||
{
|
||||
mAnyHit = true;
|
||||
return false; // abort traversal
|
||||
}
|
||||
return true; // continue traversal
|
||||
}
|
||||
|
||||
ConvexHullV mConvex;
|
||||
PxMatTransformV aToB;
|
||||
aos::Mat33V mMeshScale;
|
||||
bool mAnyHit;
|
||||
const bool mIdentityScale;
|
||||
|
||||
private:
|
||||
ConvexVsMeshOverlapCallback& operator=(const ConvexVsMeshOverlapCallback&);
|
||||
};
|
||||
}
|
||||
|
||||
// PT: TODO: refactor bits of this with convex-vs-mesh code
|
||||
bool GeomOverlapCallback_ConvexMesh(GU_OVERLAP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom0.getType()==PxGeometryType::eCONVEXMESH);
|
||||
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(cache);
|
||||
PX_UNUSED(threadContext);
|
||||
|
||||
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom0);
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
|
||||
|
||||
ConvexMesh* cm = static_cast<ConvexMesh*>(convexGeom.convexMesh);
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
const bool idtScaleConvex = convexGeom.scale.isIdentity();
|
||||
const bool idtScaleMesh = meshGeom.scale.isIdentity();
|
||||
|
||||
FastVertex2ShapeScaling convexScaling;
|
||||
if (!idtScaleConvex)
|
||||
convexScaling.init(convexGeom.scale);
|
||||
|
||||
FastVertex2ShapeScaling meshScaling;
|
||||
if (!idtScaleMesh)
|
||||
meshScaling.init(meshGeom.scale);
|
||||
|
||||
PX_ASSERT(!cm->getLocalBoundsFast().isEmpty());
|
||||
const PxBounds3 hullAABB = cm->getLocalBoundsFast().transformFast(convexScaling.getVertex2ShapeSkew());
|
||||
|
||||
Box hullOBB;
|
||||
{
|
||||
const Matrix34FromTransform world0(pose0);
|
||||
const Matrix34FromTransform world1(pose1);
|
||||
computeHullOBB(hullOBB, hullAABB, 0.0f, world0, world1, meshScaling, idtScaleMesh);
|
||||
}
|
||||
|
||||
ConvexVsMeshOverlapCallback cb(*cm, convexGeom.scale, meshScaling, pose0, pose1, idtScaleMesh, hullOBB);
|
||||
Midphase::intersectOBB(meshData, hullOBB, cb, true, false);
|
||||
|
||||
return cb.mAnyHit;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GeomOverlapCallback_MeshMesh(GU_OVERLAP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom0.getType()==PxGeometryType::eTRIANGLEMESH);
|
||||
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(cache);
|
||||
PX_UNUSED(threadContext);
|
||||
|
||||
const PxTriangleMeshGeometry& meshGeom0 = static_cast<const PxTriangleMeshGeometry&>(geom0);
|
||||
const PxTriangleMeshGeometry& meshGeom1 = static_cast<const PxTriangleMeshGeometry&>(geom1);
|
||||
|
||||
const TriangleMesh* tm0 = static_cast<const TriangleMesh*>(meshGeom0.triangleMesh);
|
||||
const TriangleMesh* tm1 = static_cast<const TriangleMesh*>(meshGeom1.triangleMesh);
|
||||
|
||||
// PT: only implemented for BV4
|
||||
if(!tm0 || !tm1 || tm0->getConcreteType()!=PxConcreteType::eTRIANGLE_MESH_BVH34 || tm1->getConcreteType()!=PxConcreteType::eTRIANGLE_MESH_BVH34)
|
||||
return PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxGeometryQuery::overlap(): only available between two BVH34 triangles meshes.");
|
||||
|
||||
class AnyHitReportCallback : public PxReportCallback<PxGeomIndexPair>
|
||||
{
|
||||
public:
|
||||
AnyHitReportCallback()
|
||||
{
|
||||
mCapacity = 1;
|
||||
}
|
||||
|
||||
virtual bool flushResults(PxU32, const PxGeomIndexPair*)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
AnyHitReportCallback callback;
|
||||
|
||||
// PT: ...so we don't need a table like for the other ops, just go straight to BV4
|
||||
return intersectMeshVsMesh_BV4(callback, *tm0, pose0, meshGeom0.scale, *tm1, pose1, meshGeom1.scale, PxMeshMeshQueryFlag::eDEFAULT, 0.0f);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool GeomOverlapCallback_ConvexCoreMesh(GU_OVERLAP_FUNC_PARAMS)
|
||||
{
|
||||
PX_UNUSED(geom0);
|
||||
PX_UNUSED(pose0);
|
||||
PX_UNUSED(geom1);
|
||||
PX_UNUSED(pose1);
|
||||
PX_UNUSED(cache);
|
||||
PX_UNUSED(threadContext);
|
||||
|
||||
struct Callback : MeshHitCallback<PxGeomRaycastHit>
|
||||
{
|
||||
Gu::ConvexShape convex;
|
||||
PxMeshScale scale;
|
||||
bool hit;
|
||||
|
||||
Callback(const PxConvexCoreGeometry& geom, const PxTransform& pose, const PxMeshScale& s)
|
||||
:
|
||||
MeshHitCallback<PxGeomRaycastHit>(CallbackMode::eMULTIPLE),
|
||||
scale(s), hit(false)
|
||||
{
|
||||
Gu::makeConvexShape(geom, pose, convex);
|
||||
}
|
||||
|
||||
virtual PxAgain processHit(const PxGeomRaycastHit& /*hit*/, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal&, const PxU32*)
|
||||
{
|
||||
const PxVec3 verts[] = { v0, v1, v2 };
|
||||
|
||||
Gu::ConvexShape tri;
|
||||
tri.coreType = Gu::ConvexCore::Type::ePOINTS;
|
||||
tri.pose = PxTransform(PxIdentity);
|
||||
Gu::ConvexCore::PointsCore& core = *reinterpret_cast<Gu::ConvexCore::PointsCore*>(tri.coreData);
|
||||
core.points = verts;
|
||||
core.numPoints = 3;
|
||||
core.stride = sizeof(PxVec3);
|
||||
core.S = scale.scale;
|
||||
core.R = scale.rotation;
|
||||
tri.margin = 0;
|
||||
|
||||
PxVec3 point0, point1, axis;
|
||||
PxReal dist = Gu::RefGjkEpa::computeGjkDistance(convex, tri, convex.pose, tri.pose, convex.margin + tri.margin, point0, point1, axis);
|
||||
hit = (dist <= convex.margin + tri.margin);
|
||||
|
||||
return !hit;
|
||||
}
|
||||
};
|
||||
|
||||
PX_ASSERT(geom0.getType() == PxGeometryType::eCONVEXCORE);
|
||||
PX_ASSERT(geom1.getType() == PxGeometryType::eTRIANGLEMESH);
|
||||
|
||||
const PxConvexCoreGeometry& shapeConvex = static_cast<const PxConvexCoreGeometry&>(geom0);
|
||||
const PxTriangleMeshGeometry& shapeMesh = static_cast<const PxTriangleMeshGeometry&>(geom1);
|
||||
const TriangleMesh* meshData = _getMeshData(shapeMesh);
|
||||
|
||||
const PxTransform pose0in1 = pose1.transformInv(pose0);
|
||||
const PxBounds3 bounds = Gu::computeBounds(geom0, PxTransform(PxIdentity));
|
||||
|
||||
Box queryBox;
|
||||
queryBox.extents = bounds.getExtents();
|
||||
queryBox.center = pose0in1.transform(bounds.getCenter());
|
||||
queryBox.rot = PxMat33(pose0in1.q);
|
||||
|
||||
const FastVertex2ShapeScaling meshScaling(shapeMesh.scale);
|
||||
meshScaling.transformQueryBounds(queryBox.center, queryBox.extents, queryBox.rot);
|
||||
|
||||
Callback callback(shapeConvex, pose0in1, shapeMesh.scale);
|
||||
|
||||
Midphase::intersectOBB(meshData, queryBox, callback, false);
|
||||
|
||||
return callback.hit;
|
||||
}
|
||||
404
engine/third_party/physx/source/geomutils/src/mesh/GuRTree.cpp
vendored
Normal file
404
engine/third_party/physx/source/geomutils/src/mesh/GuRTree.cpp
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#include "foundation/PxPreprocessor.h"
|
||||
|
||||
#define RTREE_TEXT_DUMP_ENABLE 0
|
||||
#if PX_P64_FAMILY
|
||||
#define RTREE_PAGES_PER_POOL_SLAB 16384 // preallocate all pages in first batch to make sure we stay within 32 bits for relative pointers.. this is 2 megs
|
||||
#else
|
||||
#define RTREE_PAGES_PER_POOL_SLAB 128
|
||||
#endif
|
||||
|
||||
#define INSERT_SCAN_LOOKAHEAD 1 // enable one level lookahead scan for determining which child page is best to insert a node into
|
||||
|
||||
#define RTREE_INFLATION_EPSILON 5e-4f
|
||||
|
||||
#include "GuRTree.h"
|
||||
#include "foundation/PxSort.h"
|
||||
#include "CmSerialize.h"
|
||||
#include "CmUtils.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace aos;
|
||||
using namespace Gu;
|
||||
using namespace Cm;
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu {
|
||||
|
||||
bool RTree::load(PxInputStream& stream, PxU32 meshVersion, bool mismatch_) // PT: 'meshVersion' is the PX_MESH_VERSION from cooked file
|
||||
{
|
||||
PX_UNUSED(meshVersion);
|
||||
|
||||
release();
|
||||
|
||||
PxI8 a, b, c, d;
|
||||
readChunk(a, b, c, d, stream);
|
||||
if(a!='R' || b!='T' || c!='R' || d!='E')
|
||||
return false;
|
||||
|
||||
bool mismatch;
|
||||
PxU32 fileVersion;
|
||||
if(!readBigEndianVersionNumber(stream, mismatch_, fileVersion, mismatch))
|
||||
return false;
|
||||
|
||||
readFloatBuffer(&mBoundsMin.x, 4, mismatch, stream);
|
||||
readFloatBuffer(&mBoundsMax.x, 4, mismatch, stream);
|
||||
readFloatBuffer(&mInvDiagonal.x, 4, mismatch, stream);
|
||||
readFloatBuffer(&mDiagonalScaler.x, 4, mismatch, stream);
|
||||
mPageSize = readDword(mismatch, stream);
|
||||
mNumRootPages = readDword(mismatch, stream);
|
||||
mNumLevels = readDword(mismatch, stream);
|
||||
mTotalNodes = readDword(mismatch, stream);
|
||||
mTotalPages = readDword(mismatch, stream);
|
||||
PxU32 unused = readDword(mismatch, stream); PX_UNUSED(unused); // backwards compatibility
|
||||
mPages = static_cast<RTreePage*>(PxAlignedAllocator<128>().allocate(sizeof(RTreePage)*mTotalPages, PX_FL));
|
||||
PxMarkSerializedMemory(mPages, sizeof(RTreePage)*mTotalPages);
|
||||
for(PxU32 j=0; j<mTotalPages; j++)
|
||||
{
|
||||
readFloatBuffer(mPages[j].minx, RTREE_N, mismatch, stream);
|
||||
readFloatBuffer(mPages[j].miny, RTREE_N, mismatch, stream);
|
||||
readFloatBuffer(mPages[j].minz, RTREE_N, mismatch, stream);
|
||||
readFloatBuffer(mPages[j].maxx, RTREE_N, mismatch, stream);
|
||||
readFloatBuffer(mPages[j].maxy, RTREE_N, mismatch, stream);
|
||||
readFloatBuffer(mPages[j].maxz, RTREE_N, mismatch, stream);
|
||||
ReadDwordBuffer(mPages[j].ptrs, RTREE_N, mismatch, stream);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PxU32 RTree::computeBottomLevelCount(PxU32 multiplier) const
|
||||
{
|
||||
PxU32 topCount = 0, curCount = mNumRootPages;
|
||||
const RTreePage* rightMostPage = &mPages[mNumRootPages-1];
|
||||
PX_ASSERT(rightMostPage);
|
||||
for (PxU32 level = 0; level < mNumLevels-1; level++)
|
||||
{
|
||||
topCount += curCount;
|
||||
PxU32 nc = rightMostPage->nodeCount();
|
||||
PX_ASSERT(nc > 0 && nc <= RTREE_N);
|
||||
// old version pointer, up to PX_MESH_VERSION 8
|
||||
PxU32 ptr = (rightMostPage->ptrs[nc-1]) * multiplier;
|
||||
PX_ASSERT(ptr % sizeof(RTreePage) == 0);
|
||||
const RTreePage* rightMostPageNext = mPages + (ptr / sizeof(RTreePage));
|
||||
curCount = PxU32(rightMostPageNext - rightMostPage);
|
||||
rightMostPage = rightMostPageNext;
|
||||
}
|
||||
|
||||
return mTotalPages - topCount;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
RTree::RTree(const PxEMPTY)
|
||||
{
|
||||
mFlags |= USER_ALLOCATED;
|
||||
}
|
||||
|
||||
|
||||
// PX_SERIALIZATION
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
void RTree::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
stream.alignData(128);
|
||||
stream.writeData(mPages, mTotalPages*sizeof(RTreePage));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
void RTree::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
context.alignExtraData(128);
|
||||
mPages = context.readExtraData<RTreePage>(mTotalPages);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE PxU32 RTreePage::nodeCount() const
|
||||
{
|
||||
for (int j = 0; j < RTREE_N; j ++)
|
||||
if (minx[j] == MX)
|
||||
return PxU32(j);
|
||||
|
||||
return RTREE_N;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::clearNode(PxU32 nodeIndex)
|
||||
{
|
||||
PX_ASSERT(nodeIndex < RTREE_N);
|
||||
minx[nodeIndex] = miny[nodeIndex] = minz[nodeIndex] = MX; // initialize empty node with sentinels
|
||||
maxx[nodeIndex] = maxy[nodeIndex] = maxz[nodeIndex] = MN;
|
||||
ptrs[nodeIndex] = 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::getNode(const PxU32 nodeIndex, RTreeNodeQ& r) const
|
||||
{
|
||||
PX_ASSERT(nodeIndex < RTREE_N);
|
||||
r.minx = minx[nodeIndex];
|
||||
r.miny = miny[nodeIndex];
|
||||
r.minz = minz[nodeIndex];
|
||||
r.maxx = maxx[nodeIndex];
|
||||
r.maxy = maxy[nodeIndex];
|
||||
r.maxz = maxz[nodeIndex];
|
||||
r.ptr = ptrs[nodeIndex];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::setEmpty(PxU32 startIndex)
|
||||
{
|
||||
PX_ASSERT(startIndex < RTREE_N);
|
||||
for (PxU32 j = startIndex; j < RTREE_N; j ++)
|
||||
clearNode(j);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::computeBounds(RTreeNodeQ& newBounds)
|
||||
{
|
||||
RTreeValue _minx = MX, _miny = MX, _minz = MX, _maxx = MN, _maxy = MN, _maxz = MN;
|
||||
for (PxU32 j = 0; j < RTREE_N; j++)
|
||||
{
|
||||
if (isEmpty(j))
|
||||
continue;
|
||||
_minx = PxMin(_minx, minx[j]);
|
||||
_miny = PxMin(_miny, miny[j]);
|
||||
_minz = PxMin(_minz, minz[j]);
|
||||
_maxx = PxMax(_maxx, maxx[j]);
|
||||
_maxy = PxMax(_maxy, maxy[j]);
|
||||
_maxz = PxMax(_maxz, maxz[j]);
|
||||
}
|
||||
newBounds.minx = _minx;
|
||||
newBounds.miny = _miny;
|
||||
newBounds.minz = _minz;
|
||||
newBounds.maxx = _maxx;
|
||||
newBounds.maxy = _maxy;
|
||||
newBounds.maxz = _maxz;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::adjustChildBounds(PxU32 index, const RTreeNodeQ& adjChild)
|
||||
{
|
||||
PX_ASSERT(index < RTREE_N);
|
||||
minx[index] = adjChild.minx;
|
||||
miny[index] = adjChild.miny;
|
||||
minz[index] = adjChild.minz;
|
||||
maxx[index] = adjChild.maxx;
|
||||
maxy[index] = adjChild.maxy;
|
||||
maxz[index] = adjChild.maxz;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::growChildBounds(PxU32 index, const RTreeNodeQ& child)
|
||||
{
|
||||
PX_ASSERT(index < RTREE_N);
|
||||
minx[index] = PxMin(minx[index], child.minx);
|
||||
miny[index] = PxMin(miny[index], child.miny);
|
||||
minz[index] = PxMin(minz[index], child.minz);
|
||||
maxx[index] = PxMax(maxx[index], child.maxx);
|
||||
maxy[index] = PxMax(maxy[index], child.maxy);
|
||||
maxz[index] = PxMax(maxz[index], child.maxz);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::copyNode(PxU32 targetIndex, const RTreePage& sourcePage, PxU32 sourceIndex)
|
||||
{
|
||||
PX_ASSERT(targetIndex < RTREE_N);
|
||||
PX_ASSERT(sourceIndex < RTREE_N);
|
||||
minx[targetIndex] = sourcePage.minx[sourceIndex];
|
||||
miny[targetIndex] = sourcePage.miny[sourceIndex];
|
||||
minz[targetIndex] = sourcePage.minz[sourceIndex];
|
||||
maxx[targetIndex] = sourcePage.maxx[sourceIndex];
|
||||
maxy[targetIndex] = sourcePage.maxy[sourceIndex];
|
||||
maxz[targetIndex] = sourcePage.maxz[sourceIndex];
|
||||
ptrs[targetIndex] = sourcePage.ptrs[sourceIndex];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreePage::setNode(PxU32 targetIndex, const RTreeNodeQ& sourceNode)
|
||||
{
|
||||
PX_ASSERT(targetIndex < RTREE_N);
|
||||
minx[targetIndex] = sourceNode.minx;
|
||||
miny[targetIndex] = sourceNode.miny;
|
||||
minz[targetIndex] = sourceNode.minz;
|
||||
maxx[targetIndex] = sourceNode.maxx;
|
||||
maxy[targetIndex] = sourceNode.maxy;
|
||||
maxz[targetIndex] = sourceNode.maxz;
|
||||
ptrs[targetIndex] = sourceNode.ptr;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreeNodeQ::grow(const RTreePage& page, int nodeIndex)
|
||||
{
|
||||
PX_ASSERT(nodeIndex < RTREE_N);
|
||||
minx = PxMin(minx, page.minx[nodeIndex]);
|
||||
miny = PxMin(miny, page.miny[nodeIndex]);
|
||||
minz = PxMin(minz, page.minz[nodeIndex]);
|
||||
maxx = PxMax(maxx, page.maxx[nodeIndex]);
|
||||
maxy = PxMax(maxy, page.maxy[nodeIndex]);
|
||||
maxz = PxMax(maxz, page.maxz[nodeIndex]);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreeNodeQ::grow(const RTreeNodeQ& node)
|
||||
{
|
||||
minx = PxMin(minx, node.minx); miny = PxMin(miny, node.miny); minz = PxMin(minz, node.minz);
|
||||
maxx = PxMax(maxx, node.maxx); maxy = PxMax(maxy, node.maxy); maxz = PxMax(maxz, node.maxz);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
void RTree::validateRecursive(PxU32 level, RTreeNodeQ parentBounds, RTreePage* page, CallbackRefit* cbLeaf)
|
||||
{
|
||||
PX_UNUSED(parentBounds);
|
||||
|
||||
RTreeNodeQ n;
|
||||
PxU32 pageNodeCount = page->nodeCount();
|
||||
for (PxU32 j = 0; j < pageNodeCount; j++)
|
||||
{
|
||||
page->getNode(j, n);
|
||||
if (page->isEmpty(j))
|
||||
continue;
|
||||
PX_ASSERT(n.minx >= parentBounds.minx); PX_ASSERT(n.miny >= parentBounds.miny); PX_ASSERT(n.minz >= parentBounds.minz);
|
||||
PX_ASSERT(n.maxx <= parentBounds.maxx); PX_ASSERT(n.maxy <= parentBounds.maxy); PX_ASSERT(n.maxz <= parentBounds.maxz);
|
||||
if (!n.isLeaf())
|
||||
{
|
||||
PX_ASSERT((n.ptr&1) == 0);
|
||||
RTreePage* childPage = reinterpret_cast<RTreePage*>(size_t(mPages) + n.ptr);
|
||||
validateRecursive(level+1, n, childPage, cbLeaf);
|
||||
} else if (cbLeaf)
|
||||
{
|
||||
Vec3V mnv, mxv;
|
||||
cbLeaf->recomputeBounds(page->ptrs[j] & ~1, mnv, mxv);
|
||||
PxVec3 mn3, mx3; V3StoreU(mnv, mn3); V3StoreU(mxv, mx3);
|
||||
const PxBounds3 lb(mn3, mx3);
|
||||
const PxVec3& mn = lb.minimum; const PxVec3& mx = lb.maximum; PX_UNUSED(mn); PX_UNUSED(mx);
|
||||
PX_ASSERT(mn.x >= n.minx); PX_ASSERT(mn.y >= n.miny); PX_ASSERT(mn.z >= n.minz);
|
||||
PX_ASSERT(mx.x <= n.maxx); PX_ASSERT(mx.y <= n.maxy); PX_ASSERT(mx.z <= n.maxz);
|
||||
}
|
||||
}
|
||||
RTreeNodeQ recomputedBounds;
|
||||
page->computeBounds(recomputedBounds);
|
||||
PX_ASSERT((recomputedBounds.minx - parentBounds.minx)<=RTREE_INFLATION_EPSILON);
|
||||
PX_ASSERT((recomputedBounds.miny - parentBounds.miny)<=RTREE_INFLATION_EPSILON);
|
||||
PX_ASSERT((recomputedBounds.minz - parentBounds.minz)<=RTREE_INFLATION_EPSILON);
|
||||
PX_ASSERT((recomputedBounds.maxx - parentBounds.maxx)<=RTREE_INFLATION_EPSILON);
|
||||
PX_ASSERT((recomputedBounds.maxy - parentBounds.maxy)<=RTREE_INFLATION_EPSILON);
|
||||
PX_ASSERT((recomputedBounds.maxz - parentBounds.maxz)<=RTREE_INFLATION_EPSILON);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
void RTree::validate(CallbackRefit* cbLeaf)
|
||||
{
|
||||
for (PxU32 j = 0; j < mNumRootPages; j++)
|
||||
{
|
||||
RTreeNodeQ rootBounds;
|
||||
mPages[j].computeBounds(rootBounds);
|
||||
validateRecursive(0, rootBounds, mPages+j, cbLeaf);
|
||||
}
|
||||
}
|
||||
|
||||
void RTree::refitAllStaticTree(CallbackRefit& cb, PxBounds3* retBounds)
|
||||
{
|
||||
PxU8* treeNodes8 = reinterpret_cast<PxU8*>(mPages);
|
||||
|
||||
// since pages are ordered we can scan back to front and the hierarchy will be updated
|
||||
for (PxI32 iPage = PxI32(mTotalPages)-1; iPage>=0; iPage--)
|
||||
{
|
||||
RTreePage& page = mPages[iPage];
|
||||
for (PxU32 j = 0; j < RTREE_N; j++)
|
||||
{
|
||||
if (page.isEmpty(j))
|
||||
continue;
|
||||
if (page.isLeaf(j))
|
||||
{
|
||||
Vec3V childMn, childMx;
|
||||
cb.recomputeBounds(page.ptrs[j]-1, childMn, childMx); // compute the bound around triangles
|
||||
PxVec3 mn3, mx3;
|
||||
V3StoreU(childMn, mn3);
|
||||
V3StoreU(childMx, mx3);
|
||||
page.minx[j] = mn3.x; page.miny[j] = mn3.y; page.minz[j] = mn3.z;
|
||||
page.maxx[j] = mx3.x; page.maxy[j] = mx3.y; page.maxz[j] = mx3.z;
|
||||
} else
|
||||
{
|
||||
const RTreePage* child = reinterpret_cast<const RTreePage*>(treeNodes8 + page.ptrs[j]);
|
||||
PX_COMPILE_TIME_ASSERT(RTREE_N == 4);
|
||||
bool first = true;
|
||||
for (PxU32 k = 0; k < RTREE_N; k++)
|
||||
{
|
||||
if (child->isEmpty(k))
|
||||
continue;
|
||||
if (first)
|
||||
{
|
||||
page.minx[j] = child->minx[k]; page.miny[j] = child->miny[k]; page.minz[j] = child->minz[k];
|
||||
page.maxx[j] = child->maxx[k]; page.maxy[j] = child->maxy[k]; page.maxz[j] = child->maxz[k];
|
||||
first = false;
|
||||
} else
|
||||
{
|
||||
page.minx[j] = PxMin(page.minx[j], child->minx[k]);
|
||||
page.miny[j] = PxMin(page.miny[j], child->miny[k]);
|
||||
page.minz[j] = PxMin(page.minz[j], child->minz[k]);
|
||||
page.maxx[j] = PxMax(page.maxx[j], child->maxx[k]);
|
||||
page.maxy[j] = PxMax(page.maxy[j], child->maxy[k]);
|
||||
page.maxz[j] = PxMax(page.maxz[j], child->maxz[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (retBounds)
|
||||
{
|
||||
RTreeNodeQ bound1;
|
||||
for (PxU32 ii = 0; ii<mNumRootPages; ii++)
|
||||
{
|
||||
mPages[ii].computeBounds(bound1);
|
||||
if (ii == 0)
|
||||
{
|
||||
retBounds->minimum = PxVec3(bound1.minx, bound1.miny, bound1.minz);
|
||||
retBounds->maximum = PxVec3(bound1.maxx, bound1.maxy, bound1.maxz);
|
||||
} else
|
||||
{
|
||||
retBounds->minimum = retBounds->minimum.minimum(PxVec3(bound1.minx, bound1.miny, bound1.minz));
|
||||
retBounds->maximum = retBounds->maximum.maximum(PxVec3(bound1.maxx, bound1.maxy, bound1.maxz));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if PX_CHECKED
|
||||
validate(&cb);
|
||||
#endif
|
||||
}
|
||||
|
||||
//~PX_SERIALIZATION
|
||||
const RTreeValue RTreePage::MN = -PX_MAX_F32;
|
||||
const RTreeValue RTreePage::MX = PX_MAX_F32;
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
}
|
||||
272
engine/third_party/physx/source/geomutils/src/mesh/GuRTree.h
vendored
Normal file
272
engine/third_party/physx/source/geomutils/src/mesh/GuRTree.h
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
// 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_RTREE_H
|
||||
#define GU_RTREE_H
|
||||
|
||||
#include "foundation/PxSimpleTypes.h"
|
||||
#include "foundation/PxVec4.h"
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "foundation/PxAssert.h"
|
||||
#include "foundation/PxIO.h"
|
||||
#include "common/PxSerialFramework.h"
|
||||
#include "geometry/PxTriangleMesh.h"
|
||||
|
||||
#include "foundation/PxUserAllocated.h" // for PxSerializationContext
|
||||
#include "foundation/PxAlignedMalloc.h"
|
||||
|
||||
#include "foundation/PxVecMath.h"
|
||||
|
||||
#define RTREE_N 4 // changing this number will affect the mesh format
|
||||
PX_COMPILE_TIME_ASSERT(RTREE_N == 4 || RTREE_N == 8); // using the low 5 bits for storage of index(childPtr) for dynamic rtree
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
|
||||
#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
|
||||
|
||||
namespace Gu {
|
||||
|
||||
class Box;
|
||||
struct RTreePage;
|
||||
|
||||
typedef PxF32 RTreeValue;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// quantized untransposed RTree node - used for offline build and dynamic insertion
|
||||
struct RTreeNodeQ
|
||||
{
|
||||
RTreeValue minx, miny, minz, maxx, maxy, maxz;
|
||||
PxU32 ptr; // lowest bit is leaf flag
|
||||
|
||||
PX_FORCE_INLINE void setLeaf(bool set) { if (set) ptr |= 1; else ptr &= ~1; }
|
||||
PX_FORCE_INLINE PxU32 isLeaf() const { return ptr & 1; }
|
||||
PX_FORCE_INLINE void setEmpty();
|
||||
PX_FORCE_INLINE void grow(const RTreePage& page, int nodeIndex);
|
||||
PX_FORCE_INLINE void grow(const RTreeNodeQ& node);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// RTreePage data structure, holds RTREE_N transposed nodes
|
||||
|
||||
// RTreePage data structure, holds 8 transposed nodes
|
||||
PX_ALIGN_PREFIX(16)
|
||||
struct RTreePage
|
||||
{
|
||||
static const RTreeValue MN, MX;
|
||||
|
||||
RTreeValue minx[RTREE_N]; // [min=MX, max=MN] is used as a sentinel range for empty bounds
|
||||
RTreeValue miny[RTREE_N];
|
||||
RTreeValue minz[RTREE_N];
|
||||
RTreeValue maxx[RTREE_N];
|
||||
RTreeValue maxy[RTREE_N];
|
||||
RTreeValue maxz[RTREE_N];
|
||||
PxU32 ptrs[RTREE_N]; // for static rtree this is an offset relative to the first page divided by 16, for dynamics it's an absolute pointer divided by 16
|
||||
|
||||
PX_FORCE_INLINE PxU32 nodeCount() const; // returns the number of occupied nodes in this page
|
||||
PX_FORCE_INLINE void setEmpty(PxU32 startIndex = 0);
|
||||
PX_FORCE_INLINE bool isEmpty(PxU32 index) const { return minx[index] > maxx[index]; }
|
||||
PX_FORCE_INLINE void copyNode(PxU32 targetIndex, const RTreePage& sourcePage, PxU32 sourceIndex);
|
||||
PX_FORCE_INLINE void setNode(PxU32 targetIndex, const RTreeNodeQ& node);
|
||||
PX_FORCE_INLINE void clearNode(PxU32 nodeIndex);
|
||||
PX_FORCE_INLINE void getNode(PxU32 nodeIndex, RTreeNodeQ& result) const;
|
||||
PX_FORCE_INLINE void computeBounds(RTreeNodeQ& bounds);
|
||||
PX_FORCE_INLINE void adjustChildBounds(PxU32 index, const RTreeNodeQ& adjustedChildBounds);
|
||||
PX_FORCE_INLINE void growChildBounds(PxU32 index, const RTreeNodeQ& adjustedChildBounds);
|
||||
PX_FORCE_INLINE PxU32 getNodeHandle(PxU32 index) const;
|
||||
PX_FORCE_INLINE PxU32 isLeaf(PxU32 index) const { return ptrs[index] & 1; }
|
||||
} PX_ALIGN_SUFFIX(16);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// RTree root data structure
|
||||
PX_ALIGN_PREFIX(16)
|
||||
struct RTree
|
||||
{
|
||||
// PX_SERIALIZATION
|
||||
RTree(const PxEMPTY);
|
||||
void exportExtraData(PxSerializationContext&);
|
||||
void importExtraData(PxDeserializationContext& context);
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
PX_INLINE RTree(); // offline static rtree constructor used with cooking
|
||||
|
||||
~RTree() { release(); }
|
||||
|
||||
PX_INLINE void release();
|
||||
bool load(PxInputStream& stream, PxU32 meshVersion, bool mismatch);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// QUERIES
|
||||
struct Callback
|
||||
{
|
||||
// result buffer should have room for at least RTREE_N items
|
||||
// should return true to continue traversal. If false is returned, traversal is aborted
|
||||
virtual bool processResults(PxU32 count, PxU32* buf) = 0;
|
||||
virtual void profile() {}
|
||||
virtual ~Callback() {}
|
||||
};
|
||||
|
||||
struct CallbackRaycast
|
||||
{
|
||||
// result buffer should have room for at least RTREE_N items
|
||||
// should return true to continue traversal. If false is returned, traversal is aborted
|
||||
// newMaxT serves as both input and output, as input it's the maxT so far
|
||||
// set it to a new value (which should be smaller) and it will become the new far clip t
|
||||
virtual bool processResults(PxU32 count, PxU32* buf, PxF32& newMaxT) = 0;
|
||||
virtual ~CallbackRaycast() {}
|
||||
};
|
||||
|
||||
// callback will be issued as soon as the buffer overflows maxResultsPerBlock-RTreePage:SIZE entries
|
||||
// use maxResults = RTreePage:SIZE and return false from callback for "first hit" early out
|
||||
void traverseAABB(
|
||||
const PxVec3& boxMin, const PxVec3& boxMax,
|
||||
const PxU32 maxResultsPerBlock, PxU32* resultsBlockBuf, Callback* processResultsBlockCallback) const;
|
||||
void traverseOBB(
|
||||
const Gu::Box& obb,
|
||||
const PxU32 maxResultsPerBlock, PxU32* resultsBlockBuf, Callback* processResultsBlockCallback) const;
|
||||
|
||||
template <int inflate>
|
||||
void traverseRay(
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir, // dir doesn't have to be normalized and is B-A for raySegment
|
||||
const PxU32 maxResults, PxU32* resultsPtr,
|
||||
Gu::RTree::CallbackRaycast* callback,
|
||||
const PxVec3* inflateAABBs, // inflate tree's AABBs by this amount. This function turns into AABB sweep.
|
||||
PxF32 maxT = PX_MAX_F32 // maximum ray t parameter, p(t)=origin+t*dir; use 1.0f for ray segment
|
||||
) const;
|
||||
|
||||
struct CallbackRefit
|
||||
{
|
||||
// In this callback index is the number stored in the RTree, which is a LeafTriangles object for current PhysX mesh
|
||||
virtual void recomputeBounds(PxU32 index, aos::Vec3V& mn, aos::Vec3V& mx) = 0;
|
||||
virtual ~CallbackRefit() {}
|
||||
};
|
||||
void refitAllStaticTree(CallbackRefit& cb, PxBounds3* resultMeshBounds); // faster version of refit for static RTree only
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// DEBUG HELPER FUNCTIONS
|
||||
PX_PHYSX_COMMON_API void validate(CallbackRefit* cb = NULL); // verify that all children are indeed included in parent bounds
|
||||
|
||||
void openTextDump();
|
||||
void closeTextDump();
|
||||
void textDump(const char* prefix);
|
||||
void maxscriptExport();
|
||||
PxU32 computeBottomLevelCount(PxU32 storedToMemMultiplier) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// DATA
|
||||
// remember to update save() and load() when adding or removing data
|
||||
PxVec4 mBoundsMin, mBoundsMax, mInvDiagonal, mDiagonalScaler; // 16
|
||||
PxU32 mPageSize;
|
||||
PxU32 mNumRootPages;
|
||||
PxU32 mNumLevels;
|
||||
PxU32 mTotalNodes; // 16
|
||||
PxU32 mTotalPages;
|
||||
PxU32 mFlags; enum { USER_ALLOCATED = 0x1, IS_EDGE_SET = 0x2 };
|
||||
RTreePage* mPages;
|
||||
|
||||
protected:
|
||||
typedef PxU32 NodeHandle;
|
||||
void validateRecursive(PxU32 level, RTreeNodeQ parentBounds, RTreePage* page, CallbackRefit* cb = NULL);
|
||||
|
||||
friend struct RTreePage;
|
||||
} PX_ALIGN_SUFFIX(16);
|
||||
|
||||
#if PX_SUPPORT_EXTERN_TEMPLATE
|
||||
//explicit template instantiation declaration
|
||||
extern template
|
||||
void RTree::traverseRay<0>(const PxVec3&, const PxVec3&, const PxU32, PxU32*, Gu::RTree::CallbackRaycast*, const PxVec3*, PxF32) const;
|
||||
|
||||
extern template
|
||||
void RTree::traverseRay<1>(const PxVec3&, const PxVec3&, const PxU32, PxU32*, Gu::RTree::CallbackRaycast*, const PxVec3*, PxF32) const;
|
||||
#endif
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_INLINE RTree::RTree()
|
||||
{
|
||||
mFlags = 0;
|
||||
mPages = NULL;
|
||||
mTotalNodes = 0;
|
||||
mNumLevels = 0;
|
||||
mPageSize = RTREE_N;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_INLINE void RTree::release()
|
||||
{
|
||||
if ((mFlags & USER_ALLOCATED) == 0 && mPages)
|
||||
{
|
||||
physx::PxAlignedAllocator<128>().deallocate(mPages);
|
||||
mPages = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
PX_FORCE_INLINE void RTreeNodeQ::setEmpty()
|
||||
{
|
||||
minx = miny = minz = RTreePage::MX;
|
||||
maxx = maxy = maxz = RTreePage::MN;
|
||||
}
|
||||
|
||||
|
||||
// bit 1 is always expected to be set to differentiate between leaf and non-leaf node
|
||||
PX_FORCE_INLINE PxU32 LeafGetNbTriangles(PxU32 Data) { return ((Data>>1) & 15)+1; }
|
||||
PX_FORCE_INLINE PxU32 LeafGetTriangleIndex(PxU32 Data) { return Data>>5; }
|
||||
PX_FORCE_INLINE PxU32 LeafSetData(PxU32 nb, PxU32 index)
|
||||
{
|
||||
PX_ASSERT(nb>0 && nb<=16); PX_ASSERT(index < (1<<27));
|
||||
return (index<<5)|(((nb-1)&15)<<1) | 1;
|
||||
}
|
||||
|
||||
struct LeafTriangles
|
||||
{
|
||||
PxU32 Data;
|
||||
|
||||
// Gets number of triangles in the leaf, returns the number of triangles N, with 0 < N <= 16
|
||||
PX_FORCE_INLINE PxU32 GetNbTriangles() const { return LeafGetNbTriangles(Data); }
|
||||
|
||||
// Gets triangle index for this leaf. Indexed model's array of indices retrieved with RTreeMidphase::GetIndices()
|
||||
PX_FORCE_INLINE PxU32 GetTriangleIndex() const { return LeafGetTriangleIndex(Data); }
|
||||
PX_FORCE_INLINE void SetData(PxU32 nb, PxU32 index) { Data = LeafSetData(nb, index); }
|
||||
};
|
||||
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(LeafTriangles)==4); // RTree has space for 4 bytes
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
}
|
||||
|
||||
#endif // #ifdef PX_COLLISION_RTREE
|
||||
571
engine/third_party/physx/source/geomutils/src/mesh/GuRTreeQueries.cpp
vendored
Normal file
571
engine/third_party/physx/source/geomutils/src/mesh/GuRTreeQueries.cpp
vendored
Normal file
@@ -0,0 +1,571 @@
|
||||
// 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.
|
||||
|
||||
/*
|
||||
General notes:
|
||||
|
||||
rtree depth-first traversal looks like this:
|
||||
push top level page onto stack
|
||||
|
||||
pop page from stack
|
||||
for each node in page
|
||||
if node overlaps with testrect
|
||||
push node's subpage
|
||||
|
||||
we want to efficiently keep track of current stack level to know if the current page is a leaf or not
|
||||
(since we don't store a flag with the page due to no space, we can't determine it just by looking at current page)
|
||||
since we traverse depth first, the levels for nodes on the stack look like this:
|
||||
l0 l0 l1 l2 l2 l3 l3 l3 l4
|
||||
|
||||
we can encode this as an array of 4 bits per level count into a 32-bit integer
|
||||
to simplify the code->level computation we also keep track of current level by incrementing the level whenever any subpages
|
||||
from current test page are pushed onto the stack
|
||||
when we pop a page off the stack we use this encoding to determine if we should decrement the stack level
|
||||
*/
|
||||
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "foundation/PxIntrinsics.h"
|
||||
#include "foundation/PxBitUtils.h"
|
||||
#include "GuRTree.h"
|
||||
#include "GuBox.h"
|
||||
#include "foundation/PxVecMath.h"
|
||||
#include "PxQueryReport.h" // for PxAgain
|
||||
#include "GuBVConstants.h"
|
||||
|
||||
//#define VERIFY_RTREE
|
||||
#ifdef VERIFY_RTREE
|
||||
#include "GuIntersectionRayBox.h"
|
||||
#include "GuIntersectionBoxBox.h"
|
||||
#include "stdio.h"
|
||||
#endif
|
||||
|
||||
using namespace physx;
|
||||
using namespace aos;
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu {
|
||||
|
||||
using namespace aos;
|
||||
|
||||
#define v_absm(a) V4Andc(a, signMask)
|
||||
#define V4FromF32A(x) V4LoadA(x)
|
||||
#define PxF32FV(x) FStore(x)
|
||||
#define CAST_U8(a) reinterpret_cast<PxU8*>(a)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
void RTree::traverseAABB(const PxVec3& boxMin, const PxVec3& boxMax, const PxU32 maxResults, PxU32* resultsPtr, Callback* callback) const
|
||||
{
|
||||
PX_UNUSED(resultsPtr);
|
||||
|
||||
PX_ASSERT(callback);
|
||||
PX_ASSERT(maxResults >= mPageSize);
|
||||
PX_UNUSED(maxResults);
|
||||
|
||||
const PxU32 maxStack = 128;
|
||||
PxU32 stack1[maxStack];
|
||||
PxU32* stack = stack1+1;
|
||||
|
||||
PX_ASSERT(mPages);
|
||||
PX_ASSERT((uintptr_t(mPages) & 127) == 0);
|
||||
PX_ASSERT((uintptr_t(this) & 15) == 0);
|
||||
|
||||
// conservatively quantize the input box
|
||||
Vec4V nqMin = Vec4V_From_PxVec3_WUndefined(boxMin);
|
||||
Vec4V nqMax = Vec4V_From_PxVec3_WUndefined(boxMax);
|
||||
|
||||
Vec4V nqMinx4 = V4SplatElement<0>(nqMin);
|
||||
Vec4V nqMiny4 = V4SplatElement<1>(nqMin);
|
||||
Vec4V nqMinz4 = V4SplatElement<2>(nqMin);
|
||||
Vec4V nqMaxx4 = V4SplatElement<0>(nqMax);
|
||||
Vec4V nqMaxy4 = V4SplatElement<1>(nqMax);
|
||||
Vec4V nqMaxz4 = V4SplatElement<2>(nqMax);
|
||||
|
||||
// on 64-bit platforms the dynamic rtree pointer is also relative to mPages
|
||||
PxU8* treeNodes8 = CAST_U8(mPages);
|
||||
PxU32* stackPtr = stack;
|
||||
|
||||
// AP potential perf optimization - fetch the top level right away
|
||||
PX_ASSERT(RTREE_N == 4 || RTREE_N == 8);
|
||||
PX_ASSERT(PxIsPowerOfTwo(mPageSize));
|
||||
|
||||
for (PxI32 j = PxI32(mNumRootPages-1); j >= 0; j --)
|
||||
*stackPtr++ = j*sizeof(RTreePage);
|
||||
|
||||
PxU32 cacheTopValid = true;
|
||||
PxU32 cacheTop = 0;
|
||||
|
||||
do {
|
||||
stackPtr--;
|
||||
PxU32 top;
|
||||
if (cacheTopValid) // branch is faster than lhs
|
||||
top = cacheTop;
|
||||
else
|
||||
top = stackPtr[0];
|
||||
PX_ASSERT(!cacheTopValid || stackPtr[0] == cacheTop);
|
||||
RTreePage* PX_RESTRICT tn = reinterpret_cast<RTreePage*>(treeNodes8 + top);
|
||||
const PxU32* ptrs = (reinterpret_cast<RTreePage*>(tn))->ptrs;
|
||||
|
||||
Vec4V minx4 = V4LoadA(tn->minx);
|
||||
Vec4V miny4 = V4LoadA(tn->miny);
|
||||
Vec4V minz4 = V4LoadA(tn->minz);
|
||||
Vec4V maxx4 = V4LoadA(tn->maxx);
|
||||
Vec4V maxy4 = V4LoadA(tn->maxy);
|
||||
Vec4V maxz4 = V4LoadA(tn->maxz);
|
||||
|
||||
// AABB/AABB overlap test
|
||||
BoolV res0 = V4IsGrtr(nqMinx4, maxx4); BoolV res1 = V4IsGrtr(nqMiny4, maxy4); BoolV res2 = V4IsGrtr(nqMinz4, maxz4);
|
||||
BoolV res3 = V4IsGrtr(minx4, nqMaxx4); BoolV res4 = V4IsGrtr(miny4, nqMaxy4); BoolV res5 = V4IsGrtr(minz4, nqMaxz4);
|
||||
BoolV resx = BOr(BOr(BOr(res0, res1), BOr(res2, res3)), BOr(res4, res5));
|
||||
PX_ALIGN_PREFIX(16) PxU32 resa[RTREE_N] PX_ALIGN_SUFFIX(16);
|
||||
|
||||
VecU32V res4x = VecU32V_From_BoolV(resx);
|
||||
U4StoreA(res4x, resa);
|
||||
|
||||
cacheTopValid = false;
|
||||
for (PxU32 i = 0; i < RTREE_N; i++)
|
||||
{
|
||||
PxU32 ptr = ptrs[i] & ~1; // clear the isLeaf bit
|
||||
if (resa[i])
|
||||
continue;
|
||||
if (tn->isLeaf(i))
|
||||
{
|
||||
if (!callback->processResults(1, &ptr))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(stackPtr++) = ptr;
|
||||
cacheTop = ptr;
|
||||
cacheTopValid = true;
|
||||
}
|
||||
}
|
||||
} while (stackPtr > stack);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
template <int inflate>
|
||||
void RTree::traverseRay(
|
||||
const PxVec3& rayOrigin, const PxVec3& rayDir,
|
||||
const PxU32 maxResults, PxU32* resultsPtr, Gu::RTree::CallbackRaycast* callback,
|
||||
const PxVec3* fattenAABBs, PxF32 maxT) const
|
||||
{
|
||||
// implements Kay-Kajiya 4-way SIMD test
|
||||
PX_UNUSED(resultsPtr);
|
||||
PX_UNUSED(maxResults);
|
||||
|
||||
const PxU32 maxStack = 128;
|
||||
PxU32 stack1[maxStack];
|
||||
PxU32* stack = stack1+1;
|
||||
|
||||
PX_ASSERT(mPages);
|
||||
PX_ASSERT((uintptr_t(mPages) & 127) == 0);
|
||||
PX_ASSERT((uintptr_t(this) & 15) == 0);
|
||||
|
||||
PxU8* treeNodes8 = CAST_U8(mPages);
|
||||
|
||||
Vec4V fattenAABBsX, fattenAABBsY, fattenAABBsZ;
|
||||
PX_UNUSED(fattenAABBsX); PX_UNUSED(fattenAABBsY); PX_UNUSED(fattenAABBsZ);
|
||||
if (inflate)
|
||||
{
|
||||
Vec4V fattenAABBs4 = Vec4V_From_PxVec3_WUndefined(*fattenAABBs);
|
||||
fattenAABBs4 = V4Add(fattenAABBs4, epsInflateFloat4); // US2385 - shapes are "closed" meaning exactly touching shapes should report overlap
|
||||
fattenAABBsX = V4SplatElement<0>(fattenAABBs4);
|
||||
fattenAABBsY = V4SplatElement<1>(fattenAABBs4);
|
||||
fattenAABBsZ = V4SplatElement<2>(fattenAABBs4);
|
||||
}
|
||||
|
||||
Vec4V maxT4;
|
||||
maxT4 = V4Load(maxT);
|
||||
Vec4V rayP = Vec4V_From_PxVec3_WUndefined(rayOrigin);
|
||||
Vec4V rayD = Vec4V_From_PxVec3_WUndefined(rayDir);
|
||||
VecU32V raySign = V4U32and(VecU32V_ReinterpretFrom_Vec4V(rayD), signMask);
|
||||
Vec4V rayDAbs = V4Abs(rayD); // abs value of rayD
|
||||
Vec4V rayInvD = Vec4V_ReinterpretFrom_VecU32V(V4U32or(raySign, VecU32V_ReinterpretFrom_Vec4V(V4Max(rayDAbs, epsFloat4)))); // clamp near-zero components up to epsilon
|
||||
rayD = rayInvD;
|
||||
|
||||
//rayInvD = V4Recip(rayInvD);
|
||||
// Newton-Raphson iteration for reciprocal (see wikipedia):
|
||||
// X[n+1] = X[n]*(2-original*X[n]), X[0] = V4RecipFast estimate
|
||||
//rayInvD = rayInvD*(twos-rayD*rayInvD);
|
||||
rayInvD = V4RecipFast(rayInvD); // initial estimate, not accurate enough
|
||||
rayInvD = V4Mul(rayInvD, V4NegMulSub(rayD, rayInvD, twos));
|
||||
|
||||
// P+tD=a; t=(a-P)/D
|
||||
// t=(a - p.x)*1/d.x = a/d.x +(- p.x/d.x)
|
||||
Vec4V rayPinvD = V4NegMulSub(rayInvD, rayP, zeroes);
|
||||
Vec4V rayInvDsplatX = V4SplatElement<0>(rayInvD);
|
||||
Vec4V rayInvDsplatY = V4SplatElement<1>(rayInvD);
|
||||
Vec4V rayInvDsplatZ = V4SplatElement<2>(rayInvD);
|
||||
Vec4V rayPinvDsplatX = V4SplatElement<0>(rayPinvD);
|
||||
Vec4V rayPinvDsplatY = V4SplatElement<1>(rayPinvD);
|
||||
Vec4V rayPinvDsplatZ = V4SplatElement<2>(rayPinvD);
|
||||
|
||||
PX_ASSERT(RTREE_N == 4 || RTREE_N == 8);
|
||||
PX_ASSERT(mNumRootPages > 0);
|
||||
|
||||
PxU32 stackPtr = 0;
|
||||
for (PxI32 j = PxI32(mNumRootPages-1); j >= 0; j --)
|
||||
stack[stackPtr++] = j*sizeof(RTreePage);
|
||||
|
||||
PX_ALIGN_PREFIX(16) PxU32 resa[4] PX_ALIGN_SUFFIX(16);
|
||||
|
||||
while (stackPtr)
|
||||
{
|
||||
PxU32 top = stack[--stackPtr];
|
||||
if (top&1) // isLeaf test
|
||||
{
|
||||
top--;
|
||||
PxF32 newMaxT = maxT;
|
||||
if (!callback->processResults(1, &top, newMaxT))
|
||||
return;
|
||||
/* shrink the ray if newMaxT is reduced compared to the original maxT */
|
||||
if (maxT != newMaxT)
|
||||
{
|
||||
PX_ASSERT(newMaxT < maxT);
|
||||
maxT = newMaxT;
|
||||
maxT4 = V4Load(newMaxT);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
RTreePage* PX_RESTRICT tn = reinterpret_cast<RTreePage*>(treeNodes8 + top);
|
||||
|
||||
// 6i load
|
||||
Vec4V minx4a = V4LoadA(tn->minx), miny4a = V4LoadA(tn->miny), minz4a = V4LoadA(tn->minz);
|
||||
Vec4V maxx4a = V4LoadA(tn->maxx), maxy4a = V4LoadA(tn->maxy), maxz4a = V4LoadA(tn->maxz);
|
||||
|
||||
// 1i disabled test
|
||||
// AP scaffold - optimization opportunity - can save 2 instructions here
|
||||
VecU32V ignore4a = V4IsGrtrV32u(minx4a, maxx4a); // 1 if degenerate box (empty slot in the page)
|
||||
|
||||
if (inflate)
|
||||
{
|
||||
// 6i
|
||||
maxx4a = V4Add(maxx4a, fattenAABBsX); maxy4a = V4Add(maxy4a, fattenAABBsY); maxz4a = V4Add(maxz4a, fattenAABBsZ);
|
||||
minx4a = V4Sub(minx4a, fattenAABBsX); miny4a = V4Sub(miny4a, fattenAABBsY); minz4a = V4Sub(minz4a, fattenAABBsZ);
|
||||
}
|
||||
|
||||
// P+tD=a; t=(a-P)/D
|
||||
// t=(a - p.x)*1/d.x = a/d.x +(- p.x/d.x)
|
||||
// 6i
|
||||
Vec4V tminxa0 = V4MulAdd(minx4a, rayInvDsplatX, rayPinvDsplatX);
|
||||
Vec4V tminya0 = V4MulAdd(miny4a, rayInvDsplatY, rayPinvDsplatY);
|
||||
Vec4V tminza0 = V4MulAdd(minz4a, rayInvDsplatZ, rayPinvDsplatZ);
|
||||
Vec4V tmaxxa0 = V4MulAdd(maxx4a, rayInvDsplatX, rayPinvDsplatX);
|
||||
Vec4V tmaxya0 = V4MulAdd(maxy4a, rayInvDsplatY, rayPinvDsplatY);
|
||||
Vec4V tmaxza0 = V4MulAdd(maxz4a, rayInvDsplatZ, rayPinvDsplatZ);
|
||||
|
||||
// test half-spaces
|
||||
// P+tD=dN
|
||||
// t = (d(N,D)-(P,D))/(D,D) , (D,D)=1
|
||||
|
||||
// compute 4x dot products (N,D) and (P,N) for each AABB in the page
|
||||
|
||||
// 6i
|
||||
// now compute tnear and tfar for each pair of planes for each box
|
||||
Vec4V tminxa = V4Min(tminxa0, tmaxxa0); Vec4V tmaxxa = V4Max(tminxa0, tmaxxa0);
|
||||
Vec4V tminya = V4Min(tminya0, tmaxya0); Vec4V tmaxya = V4Max(tminya0, tmaxya0);
|
||||
Vec4V tminza = V4Min(tminza0, tmaxza0); Vec4V tmaxza = V4Max(tminza0, tmaxza0);
|
||||
|
||||
// 8i
|
||||
Vec4V maxOfNeasa = V4Max(V4Max(tminxa, tminya), tminza);
|
||||
Vec4V minOfFarsa = V4Min(V4Min(tmaxxa, tmaxya), tmaxza);
|
||||
ignore4a = V4U32or(ignore4a, V4IsGrtrV32u(epsFloat4, minOfFarsa)); // if tfar is negative, ignore since its a ray, not a line
|
||||
// AP scaffold: update the build to eliminate 3 more instructions for ignore4a above
|
||||
//VecU32V ignore4a = V4IsGrtrV32u(epsFloat4, minOfFarsa); // if tfar is negative, ignore since its a ray, not a line
|
||||
ignore4a = V4U32or(ignore4a, V4IsGrtrV32u(maxOfNeasa, maxT4)); // if tnear is over maxT, ignore this result
|
||||
|
||||
// 2i
|
||||
VecU32V resa4 = V4IsGrtrV32u(maxOfNeasa, minOfFarsa); // if 1 => fail
|
||||
resa4 = V4U32or(resa4, ignore4a);
|
||||
|
||||
// 1i
|
||||
V4U32StoreAligned(resa4, reinterpret_cast<VecU32V*>(resa));
|
||||
|
||||
PxU32* ptrs = (reinterpret_cast<RTreePage*>(tn))->ptrs;
|
||||
|
||||
stack[stackPtr] = ptrs[0]; stackPtr += (1+resa[0]); // AP scaffold TODO: use VecU32add
|
||||
stack[stackPtr] = ptrs[1]; stackPtr += (1+resa[1]);
|
||||
stack[stackPtr] = ptrs[2]; stackPtr += (1+resa[2]);
|
||||
stack[stackPtr] = ptrs[3]; stackPtr += (1+resa[3]);
|
||||
}
|
||||
}
|
||||
|
||||
//explicit template instantiation
|
||||
template void RTree::traverseRay<0>(const PxVec3&, const PxVec3&, const PxU32, PxU32*, Gu::RTree::CallbackRaycast*, const PxVec3*, PxF32) const;
|
||||
|
||||
template void RTree::traverseRay<1>(const PxVec3&, const PxVec3&, const PxU32, PxU32*, Gu::RTree::CallbackRaycast*, const PxVec3*, PxF32) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
void RTree::traverseOBB(
|
||||
const Gu::Box& obb, const PxU32 maxResults, PxU32* resultsPtr, Gu::RTree::Callback* callback) const
|
||||
{
|
||||
PX_UNUSED(resultsPtr);
|
||||
PX_UNUSED(maxResults);
|
||||
|
||||
const PxU32 maxStack = 128;
|
||||
PxU32 stack[maxStack];
|
||||
|
||||
PX_ASSERT(mPages);
|
||||
PX_ASSERT((uintptr_t(mPages) & 127) == 0);
|
||||
PX_ASSERT((uintptr_t(this) & 15) == 0);
|
||||
|
||||
PxU8* treeNodes8 = CAST_U8(mPages);
|
||||
PxU32* stackPtr = stack;
|
||||
|
||||
Vec4V ones, halves, eps;
|
||||
ones = V4Load(1.0f);
|
||||
halves = V4Load(0.5f);
|
||||
eps = V4Load(1e-6f);
|
||||
|
||||
PX_UNUSED(ones);
|
||||
|
||||
Vec4V obbO = Vec4V_From_PxVec3_WUndefined(obb.center);
|
||||
Vec4V obbE = Vec4V_From_PxVec3_WUndefined(obb.extents);
|
||||
// Gu::Box::rot matrix columns are the OBB axes
|
||||
Vec4V obbX = Vec4V_From_PxVec3_WUndefined(obb.rot.column0);
|
||||
Vec4V obbY = Vec4V_From_PxVec3_WUndefined(obb.rot.column1);
|
||||
Vec4V obbZ = Vec4V_From_PxVec3_WUndefined(obb.rot.column2);
|
||||
|
||||
#if PX_WINDOWS
|
||||
// Visual Studio compiler hangs with #defines
|
||||
// On VMX platforms we use #defines in the other branch of this #ifdef to avoid register spills (LHS)
|
||||
Vec4V obbESplatX = V4SplatElement<0>(obbE);
|
||||
Vec4V obbESplatY = V4SplatElement<1>(obbE);
|
||||
Vec4V obbESplatZ = V4SplatElement<2>(obbE);
|
||||
Vec4V obbESplatNegX = V4Sub(zeroes, obbESplatX);
|
||||
Vec4V obbESplatNegY = V4Sub(zeroes, obbESplatY);
|
||||
Vec4V obbESplatNegZ = V4Sub(zeroes, obbESplatZ);
|
||||
Vec4V obbXE = V4MulAdd(obbX, obbESplatX, zeroes); // scale axii by E
|
||||
Vec4V obbYE = V4MulAdd(obbY, obbESplatY, zeroes); // scale axii by E
|
||||
Vec4V obbZE = V4MulAdd(obbZ, obbESplatZ, zeroes); // scale axii by E
|
||||
Vec4V obbOSplatX = V4SplatElement<0>(obbO);
|
||||
Vec4V obbOSplatY = V4SplatElement<1>(obbO);
|
||||
Vec4V obbOSplatZ = V4SplatElement<2>(obbO);
|
||||
Vec4V obbXSplatX = V4SplatElement<0>(obbX);
|
||||
Vec4V obbXSplatY = V4SplatElement<1>(obbX);
|
||||
Vec4V obbXSplatZ = V4SplatElement<2>(obbX);
|
||||
Vec4V obbYSplatX = V4SplatElement<0>(obbY);
|
||||
Vec4V obbYSplatY = V4SplatElement<1>(obbY);
|
||||
Vec4V obbYSplatZ = V4SplatElement<2>(obbY);
|
||||
Vec4V obbZSplatX = V4SplatElement<0>(obbZ);
|
||||
Vec4V obbZSplatY = V4SplatElement<1>(obbZ);
|
||||
Vec4V obbZSplatZ = V4SplatElement<2>(obbZ);
|
||||
Vec4V obbXESplatX = V4SplatElement<0>(obbXE);
|
||||
Vec4V obbXESplatY = V4SplatElement<1>(obbXE);
|
||||
Vec4V obbXESplatZ = V4SplatElement<2>(obbXE);
|
||||
Vec4V obbYESplatX = V4SplatElement<0>(obbYE);
|
||||
Vec4V obbYESplatY = V4SplatElement<1>(obbYE);
|
||||
Vec4V obbYESplatZ = V4SplatElement<2>(obbYE);
|
||||
Vec4V obbZESplatX = V4SplatElement<0>(obbZE);
|
||||
Vec4V obbZESplatY = V4SplatElement<1>(obbZE);
|
||||
Vec4V obbZESplatZ = V4SplatElement<2>(obbZE);
|
||||
#else
|
||||
#define obbESplatX V4SplatElement<0>(obbE)
|
||||
#define obbESplatY V4SplatElement<1>(obbE)
|
||||
#define obbESplatZ V4SplatElement<2>(obbE)
|
||||
#define obbESplatNegX V4Sub(zeroes, obbESplatX)
|
||||
#define obbESplatNegY V4Sub(zeroes, obbESplatY)
|
||||
#define obbESplatNegZ V4Sub(zeroes, obbESplatZ)
|
||||
#define obbXE V4MulAdd(obbX, obbESplatX, zeroes)
|
||||
#define obbYE V4MulAdd(obbY, obbESplatY, zeroes)
|
||||
#define obbZE V4MulAdd(obbZ, obbESplatZ, zeroes)
|
||||
#define obbOSplatX V4SplatElement<0>(obbO)
|
||||
#define obbOSplatY V4SplatElement<1>(obbO)
|
||||
#define obbOSplatZ V4SplatElement<2>(obbO)
|
||||
#define obbXSplatX V4SplatElement<0>(obbX)
|
||||
#define obbXSplatY V4SplatElement<1>(obbX)
|
||||
#define obbXSplatZ V4SplatElement<2>(obbX)
|
||||
#define obbYSplatX V4SplatElement<0>(obbY)
|
||||
#define obbYSplatY V4SplatElement<1>(obbY)
|
||||
#define obbYSplatZ V4SplatElement<2>(obbY)
|
||||
#define obbZSplatX V4SplatElement<0>(obbZ)
|
||||
#define obbZSplatY V4SplatElement<1>(obbZ)
|
||||
#define obbZSplatZ V4SplatElement<2>(obbZ)
|
||||
#define obbXESplatX V4SplatElement<0>(obbXE)
|
||||
#define obbXESplatY V4SplatElement<1>(obbXE)
|
||||
#define obbXESplatZ V4SplatElement<2>(obbXE)
|
||||
#define obbYESplatX V4SplatElement<0>(obbYE)
|
||||
#define obbYESplatY V4SplatElement<1>(obbYE)
|
||||
#define obbYESplatZ V4SplatElement<2>(obbYE)
|
||||
#define obbZESplatX V4SplatElement<0>(obbZE)
|
||||
#define obbZESplatY V4SplatElement<1>(obbZE)
|
||||
#define obbZESplatZ V4SplatElement<2>(obbZE)
|
||||
#endif
|
||||
|
||||
PX_ASSERT(mPageSize == 4 || mPageSize == 8);
|
||||
PX_ASSERT(mNumRootPages > 0);
|
||||
|
||||
for (PxI32 j = PxI32(mNumRootPages-1); j >= 0; j --)
|
||||
*stackPtr++ = j*sizeof(RTreePage);
|
||||
PxU32 cacheTopValid = true;
|
||||
PxU32 cacheTop = 0;
|
||||
|
||||
PX_ALIGN_PREFIX(16) PxU32 resa_[4] PX_ALIGN_SUFFIX(16);
|
||||
|
||||
do {
|
||||
stackPtr--;
|
||||
|
||||
PxU32 top;
|
||||
if (cacheTopValid) // branch is faster than lhs
|
||||
top = cacheTop;
|
||||
else
|
||||
top = stackPtr[0];
|
||||
PX_ASSERT(!cacheTopValid || top == cacheTop);
|
||||
RTreePage* PX_RESTRICT tn = reinterpret_cast<RTreePage*>(treeNodes8 + top);
|
||||
|
||||
const PxU32 offs = 0;
|
||||
PxU32* ptrs = (reinterpret_cast<RTreePage*>(tn))->ptrs;
|
||||
|
||||
// 6i
|
||||
Vec4V minx4a = V4LoadA(tn->minx+offs);
|
||||
Vec4V miny4a = V4LoadA(tn->miny+offs);
|
||||
Vec4V minz4a = V4LoadA(tn->minz+offs);
|
||||
Vec4V maxx4a = V4LoadA(tn->maxx+offs);
|
||||
Vec4V maxy4a = V4LoadA(tn->maxy+offs);
|
||||
Vec4V maxz4a = V4LoadA(tn->maxz+offs);
|
||||
|
||||
VecU32V noOverlapa;
|
||||
VecU32V resa4u;
|
||||
{
|
||||
// PRECOMPUTE FOR A BLOCK
|
||||
// 109 instr per 4 OBB/AABB
|
||||
// ABB iteration 1, start with OBB origin as other point -- 6
|
||||
Vec4V p1ABBxa = V4Max(minx4a, V4Min(maxx4a, obbOSplatX));
|
||||
Vec4V p1ABBya = V4Max(miny4a, V4Min(maxy4a, obbOSplatY));
|
||||
Vec4V p1ABBza = V4Max(minz4a, V4Min(maxz4a, obbOSplatZ));
|
||||
|
||||
// OBB iteration 1, move to OBB space first -- 12
|
||||
Vec4V p1ABBOxa = V4Sub(p1ABBxa, obbOSplatX);
|
||||
Vec4V p1ABBOya = V4Sub(p1ABBya, obbOSplatY);
|
||||
Vec4V p1ABBOza = V4Sub(p1ABBza, obbOSplatZ);
|
||||
Vec4V obbPrjXa = V4MulAdd(p1ABBOxa, obbXSplatX, V4MulAdd(p1ABBOya, obbXSplatY, V4MulAdd(p1ABBOza, obbXSplatZ, zeroes)));
|
||||
Vec4V obbPrjYa = V4MulAdd(p1ABBOxa, obbYSplatX, V4MulAdd(p1ABBOya, obbYSplatY, V4MulAdd(p1ABBOza, obbYSplatZ, zeroes)));
|
||||
Vec4V obbPrjZa = V4MulAdd(p1ABBOxa, obbZSplatX, V4MulAdd(p1ABBOya, obbZSplatY, V4MulAdd(p1ABBOza, obbZSplatZ, zeroes)));
|
||||
// clamp AABB point in OBB space to OBB extents. Since we scaled the axii, the extents are [-1,1] -- 6
|
||||
Vec4V pOBBxa = V4Max(obbESplatNegX, V4Min(obbPrjXa, obbESplatX));
|
||||
Vec4V pOBBya = V4Max(obbESplatNegY, V4Min(obbPrjYa, obbESplatY));
|
||||
Vec4V pOBBza = V4Max(obbESplatNegZ, V4Min(obbPrjZa, obbESplatZ));
|
||||
// go back to AABB space. we have x,y,z in obb space, need to multiply by axii -- 9
|
||||
Vec4V p1OBBxa = V4MulAdd(pOBBxa, obbXSplatX, V4MulAdd(pOBBya, obbYSplatX, V4MulAdd(pOBBza, obbZSplatX, obbOSplatX)));
|
||||
Vec4V p1OBBya = V4MulAdd(pOBBxa, obbXSplatY, V4MulAdd(pOBBya, obbYSplatY, V4MulAdd(pOBBza, obbZSplatY, obbOSplatY)));
|
||||
Vec4V p1OBBza = V4MulAdd(pOBBxa, obbXSplatZ, V4MulAdd(pOBBya, obbYSplatZ, V4MulAdd(pOBBza, obbZSplatZ, obbOSplatZ)));
|
||||
|
||||
// ABB iteration 2 -- 6 instructions
|
||||
Vec4V p2ABBxa = V4Max(minx4a, V4Min(maxx4a, p1OBBxa));
|
||||
Vec4V p2ABBya = V4Max(miny4a, V4Min(maxy4a, p1OBBya));
|
||||
Vec4V p2ABBza = V4Max(minz4a, V4Min(maxz4a, p1OBBza));
|
||||
// above blocks add up to 12+12+15=39 instr
|
||||
// END PRECOMPUTE FOR A BLOCK
|
||||
|
||||
// for AABBs precompute extents and center -- 9i
|
||||
Vec4V abbCxa = V4MulAdd(V4Add(maxx4a, minx4a), halves, zeroes);
|
||||
Vec4V abbCya = V4MulAdd(V4Add(maxy4a, miny4a), halves, zeroes);
|
||||
Vec4V abbCza = V4MulAdd(V4Add(maxz4a, minz4a), halves, zeroes);
|
||||
Vec4V abbExa = V4Sub(maxx4a, abbCxa);
|
||||
Vec4V abbEya = V4Sub(maxy4a, abbCya);
|
||||
Vec4V abbEza = V4Sub(maxz4a, abbCza);
|
||||
|
||||
// now test separating axes D1 = p1OBB-p1ABB and D2 = p1OBB-p2ABB -- 37 instructions per axis
|
||||
// D1 first -- 3 instructions
|
||||
Vec4V d1xa = V4Sub(p1OBBxa, p1ABBxa), d1ya = V4Sub(p1OBBya, p1ABBya), d1za = V4Sub(p1OBBza, p1ABBza);
|
||||
|
||||
// for AABB compute projections of extents and center -- 6
|
||||
Vec4V abbExd1Prja = V4MulAdd(d1xa, abbExa, zeroes);
|
||||
Vec4V abbEyd1Prja = V4MulAdd(d1ya, abbEya, zeroes);
|
||||
Vec4V abbEzd1Prja = V4MulAdd(d1za, abbEza, zeroes);
|
||||
Vec4V abbCd1Prja = V4MulAdd(d1xa, abbCxa, V4MulAdd(d1ya, abbCya, V4MulAdd(d1za, abbCza, zeroes)));
|
||||
|
||||
// for obb project each halfaxis and origin and add abs values of half-axis projections -- 12 instructions
|
||||
Vec4V obbXEd1Prja = V4MulAdd(d1xa, obbXESplatX, V4MulAdd(d1ya, obbXESplatY, V4MulAdd(d1za, obbXESplatZ, zeroes)));
|
||||
Vec4V obbYEd1Prja = V4MulAdd(d1xa, obbYESplatX, V4MulAdd(d1ya, obbYESplatY, V4MulAdd(d1za, obbYESplatZ, zeroes)));
|
||||
Vec4V obbZEd1Prja = V4MulAdd(d1xa, obbZESplatX, V4MulAdd(d1ya, obbZESplatY, V4MulAdd(d1za, obbZESplatZ, zeroes)));
|
||||
Vec4V obbOd1Prja = V4MulAdd(d1xa, obbOSplatX, V4MulAdd(d1ya, obbOSplatY, V4MulAdd(d1za, obbOSplatZ, zeroes)));
|
||||
|
||||
// compare lengths between projected centers with sum of projected radii -- 16i
|
||||
Vec4V originDiffd1a = v_absm(V4Sub(abbCd1Prja, obbOd1Prja));
|
||||
Vec4V absABBRd1a = V4Add(V4Add(v_absm(abbExd1Prja), v_absm(abbEyd1Prja)), v_absm(abbEzd1Prja));
|
||||
Vec4V absOBBRd1a = V4Add(V4Add(v_absm(obbXEd1Prja), v_absm(obbYEd1Prja)), v_absm(obbZEd1Prja));
|
||||
VecU32V noOverlapd1a = V4IsGrtrV32u(V4Sub(originDiffd1a, eps), V4Add(absABBRd1a, absOBBRd1a));
|
||||
VecU32V epsNoOverlapd1a = V4IsGrtrV32u(originDiffd1a, eps);
|
||||
|
||||
// D2 next (35 instr)
|
||||
// 3i
|
||||
Vec4V d2xa = V4Sub(p1OBBxa, p2ABBxa), d2ya = V4Sub(p1OBBya, p2ABBya), d2za = V4Sub(p1OBBza, p2ABBza);
|
||||
// for AABB compute projections of extents and center -- 6
|
||||
Vec4V abbExd2Prja = V4MulAdd(d2xa, abbExa, zeroes);
|
||||
Vec4V abbEyd2Prja = V4MulAdd(d2ya, abbEya, zeroes);
|
||||
Vec4V abbEzd2Prja = V4MulAdd(d2za, abbEza, zeroes);
|
||||
Vec4V abbCd2Prja = V4MulAdd(d2xa, abbCxa, V4MulAdd(d2ya, abbCya, V4MulAdd(d2za, abbCza, zeroes)));
|
||||
// for obb project each halfaxis and origin and add abs values of half-axis projections -- 12i
|
||||
Vec4V obbXEd2Prja = V4MulAdd(d2xa, obbXESplatX, V4MulAdd(d2ya, obbXESplatY, V4MulAdd(d2za, obbXESplatZ, zeroes)));
|
||||
Vec4V obbYEd2Prja = V4MulAdd(d2xa, obbYESplatX, V4MulAdd(d2ya, obbYESplatY, V4MulAdd(d2za, obbYESplatZ, zeroes)));
|
||||
Vec4V obbZEd2Prja = V4MulAdd(d2xa, obbZESplatX, V4MulAdd(d2ya, obbZESplatY, V4MulAdd(d2za, obbZESplatZ, zeroes)));
|
||||
Vec4V obbOd2Prja = V4MulAdd(d2xa, obbOSplatX, V4MulAdd(d2ya, obbOSplatY, V4MulAdd(d2za, obbOSplatZ, zeroes)));
|
||||
// compare lengths between projected centers with sum of projected radii -- 16i
|
||||
Vec4V originDiffd2a = v_absm(V4Sub(abbCd2Prja, obbOd2Prja));
|
||||
Vec4V absABBRd2a = V4Add(V4Add(v_absm(abbExd2Prja), v_absm(abbEyd2Prja)), v_absm(abbEzd2Prja));
|
||||
Vec4V absOBBRd2a = V4Add(V4Add(v_absm(obbXEd2Prja), v_absm(obbYEd2Prja)), v_absm(obbZEd2Prja));
|
||||
VecU32V noOverlapd2a = V4IsGrtrV32u(V4Sub(originDiffd2a, eps), V4Add(absABBRd2a, absOBBRd2a));
|
||||
VecU32V epsNoOverlapd2a = V4IsGrtrV32u(originDiffd2a, eps);
|
||||
|
||||
// 8i
|
||||
noOverlapa = V4U32or(V4U32and(noOverlapd1a, epsNoOverlapd1a), V4U32and(noOverlapd2a, epsNoOverlapd2a));
|
||||
VecU32V ignore4a = V4IsGrtrV32u(minx4a, maxx4a); // 1 if degenerate box (empty slot)
|
||||
noOverlapa = V4U32or(noOverlapa, ignore4a);
|
||||
resa4u = V4U32Andc(U4Load(1), noOverlapa); // 1 & ~noOverlap
|
||||
V4U32StoreAligned(resa4u, reinterpret_cast<VecU32V*>(resa_));
|
||||
///// 8+16+12+6+3+16+12+6+3+9+6+9+6+12+6+6=136i from load to result
|
||||
}
|
||||
|
||||
cacheTopValid = false;
|
||||
for (PxU32 i = 0; i < 4; i++)
|
||||
{
|
||||
PxU32 ptr = ptrs[i+offs] & ~1; // clear the isLeaf bit
|
||||
if (resa_[i])
|
||||
{
|
||||
if (tn->isLeaf(i))
|
||||
{
|
||||
if (!callback->processResults(1, &ptr))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(stackPtr++) = ptr;
|
||||
cacheTop = ptr;
|
||||
cacheTopValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (stackPtr > stack);
|
||||
}
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
}
|
||||
104
engine/third_party/physx/source/geomutils/src/mesh/GuSweepConvexTri.h
vendored
Normal file
104
engine/third_party/physx/source/geomutils/src/mesh/GuSweepConvexTri.h
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
// 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_SWEEP_CONVEX_TRI
|
||||
#define GU_SWEEP_CONVEX_TRI
|
||||
|
||||
#include "geometry/PxConvexMeshGeometry.h"
|
||||
#include "GuVecTriangle.h"
|
||||
#include "GuVecConvexHull.h"
|
||||
#include "GuConvexMesh.h"
|
||||
#include "GuGJKRaycast.h"
|
||||
|
||||
// return true if hit, false if no hit
|
||||
static PX_FORCE_INLINE bool sweepConvexVsTriangle(
|
||||
const PxVec3& v0, const PxVec3& v1, const PxVec3& v2,
|
||||
ConvexHullV& convexHull, const aos::PxMatTransformV& meshToConvex, const aos::PxTransformV& convexTransfV,
|
||||
const aos::Vec3VArg convexSpaceDir, const PxVec3& unitDir, const PxVec3& meshSpaceUnitDir,
|
||||
const aos::FloatVArg fullDistance, PxReal shrunkDistance,
|
||||
PxGeomSweepHit& hit, bool isDoubleSided, PxReal inflation, bool& initialOverlap, PxU32 faceIndex)
|
||||
{
|
||||
using namespace aos;
|
||||
if(!isDoubleSided)
|
||||
{
|
||||
// Create triangle normal
|
||||
const PxVec3 denormalizedNormal = (v1 - v0).cross(v2 - v1);
|
||||
|
||||
// Backface culling
|
||||
// PT: WARNING, the test is reversed compared to usual because we pass -unitDir to this function
|
||||
const bool culled = denormalizedNormal.dot(meshSpaceUnitDir) <= 0.0f;
|
||||
if(culled)
|
||||
return false;
|
||||
}
|
||||
|
||||
const Vec3V zeroV = V3Zero();
|
||||
const FloatV zero = FZero();
|
||||
|
||||
const Vec3V p0 = V3LoadU(v0); // in mesh local space
|
||||
const Vec3V p1 = V3LoadU(v1);
|
||||
const Vec3V p2 = V3LoadU(v2);
|
||||
|
||||
// transform triangle verts from mesh local to convex local space
|
||||
TriangleV triangleV(meshToConvex.transform(p0), meshToConvex.transform(p1), meshToConvex.transform(p2));
|
||||
|
||||
FloatV toi;
|
||||
Vec3V closestA,normal;
|
||||
|
||||
const LocalConvex<TriangleV> convexA(triangleV);
|
||||
const LocalConvex<ConvexHullV> convexB(convexHull);
|
||||
const Vec3V initialSearchDir = V3Sub(triangleV.getCenter(), convexHull.getCenter());
|
||||
// run GJK raycast
|
||||
// sweep triangle in convex local space vs convex, closestA will be the impact point in convex local space
|
||||
const bool gjkHit = gjkRaycastPenetration<LocalConvex<TriangleV>, LocalConvex<ConvexHullV> >(
|
||||
convexA, convexB, initialSearchDir, zero, zeroV, convexSpaceDir, toi, normal, closestA, inflation, false);
|
||||
if(!gjkHit)
|
||||
return false;
|
||||
|
||||
if(FAllGrtrOrEq(zero, toi))
|
||||
{
|
||||
initialOverlap = true; // PT: TODO: redundant with hit distance, consider removing
|
||||
return setInitialOverlapResults(hit, unitDir, faceIndex);
|
||||
}
|
||||
|
||||
const FloatV minDist = FLoad(shrunkDistance);
|
||||
const FloatV dist = FMul(toi, fullDistance); // scale the toi to original full sweep distance
|
||||
if(FAllGrtr(minDist, dist)) // is current dist < minDist?
|
||||
{
|
||||
hit.faceIndex = faceIndex;
|
||||
hit.flags = PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX;
|
||||
const Vec3V destWorldPointA = convexTransfV.transform(closestA);
|
||||
const Vec3V destNormal = V3Normalize(convexTransfV.rotate(normal));
|
||||
V3StoreU(destWorldPointA, hit.position);
|
||||
V3StoreU(destNormal, hit.normal);
|
||||
FStore(dist, &hit.distance);
|
||||
return true; // report a hit
|
||||
}
|
||||
return false; // report no hit
|
||||
}
|
||||
|
||||
#endif
|
||||
157
engine/third_party/physx/source/geomutils/src/mesh/GuSweepMesh.h
vendored
Normal file
157
engine/third_party/physx/source/geomutils/src/mesh/GuSweepMesh.h
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
// 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_SWEEP_MESH_H
|
||||
#define GU_SWEEP_MESH_H
|
||||
|
||||
#include "GuMidphaseInterface.h"
|
||||
#include "GuVecConvexHull.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
namespace Gu
|
||||
{
|
||||
// PT: intermediate class containing shared bits of code & members
|
||||
struct SweepShapeMeshHitCallback : MeshHitCallback<PxGeomRaycastHit>
|
||||
{
|
||||
SweepShapeMeshHitCallback(CallbackMode::Enum mode, const PxHitFlags& hitFlags, bool flipNormal, float distCoef);
|
||||
|
||||
const PxHitFlags mHitFlags;
|
||||
bool mStatus; // Default is false, set to true if a valid hit is found. Stays true once true.
|
||||
bool mInitialOverlap; // Default is false, set to true if an initial overlap hit is found. Reset for each hit.
|
||||
bool mFlipNormal; // If negative scale is used we need to flip normal
|
||||
PxReal mDistCoeff; // dist coeff from unscaled to scaled distance
|
||||
|
||||
void operator=(const SweepShapeMeshHitCallback&) {}
|
||||
};
|
||||
|
||||
struct SweepCapsuleMeshHitCallback : SweepShapeMeshHitCallback
|
||||
{
|
||||
PxGeomSweepHit& mSweepHit;
|
||||
const PxMat34& mVertexToWorldSkew;
|
||||
const PxReal mTrueSweepDistance; // max sweep distance that can be used
|
||||
PxReal mBestAlignmentValue; // best alignment value for triangle normal
|
||||
PxReal mBestDist; // best distance, not the same as sweepHit.distance, can be shorter by epsilon
|
||||
const Capsule& mCapsule;
|
||||
const PxVec3& mUnitDir;
|
||||
const bool mMeshDoubleSided; // PT: true if PxMeshGeometryFlag::eDOUBLE_SIDED
|
||||
const bool mIsSphere;
|
||||
|
||||
SweepCapsuleMeshHitCallback(PxGeomSweepHit& sweepHit, const PxMat34& worldMatrix, PxReal distance, bool meshDoubleSided,
|
||||
const Capsule& capsule, const PxVec3& unitDir, const PxHitFlags& hitFlags, bool flipNormal, float distCoef);
|
||||
|
||||
virtual PxAgain processHit(const PxGeomRaycastHit& aHit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal& shrunkMaxT, const PxU32*);
|
||||
|
||||
// PT: TODO: unify these operators
|
||||
void operator=(const SweepCapsuleMeshHitCallback&) {}
|
||||
|
||||
bool finalizeHit( PxGeomSweepHit& sweepHit, const Capsule& lss, const PxTriangleMeshGeometry& triMeshGeom,
|
||||
const PxTransform& pose, bool isDoubleSided) const;
|
||||
};
|
||||
|
||||
#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
|
||||
|
||||
struct SweepBoxMeshHitCallback : SweepShapeMeshHitCallback
|
||||
{
|
||||
const PxMat34Padded& mMeshToBox;
|
||||
PxReal mDist, mDist0;
|
||||
physx::aos::FloatV mDistV;
|
||||
const Box& mBox;
|
||||
const PxVec3& mLocalDir;
|
||||
const PxVec3& mWorldUnitDir;
|
||||
PxReal mInflation;
|
||||
PxTriangle mHitTriangle;
|
||||
physx::aos::Vec3V mMinClosestA;
|
||||
physx::aos::Vec3V mMinNormal;
|
||||
physx::aos::Vec3V mLocalMotionV;
|
||||
PxU32 mMinTriangleIndex;
|
||||
PxVec3 mOneOverDir;
|
||||
const bool mBothTriangleSidesCollide; // PT: true if PxMeshGeometryFlag::eDOUBLE_SIDED || PxHitFlag::eMESH_BOTH_SIDES
|
||||
|
||||
SweepBoxMeshHitCallback(CallbackMode::Enum mode_, const PxMat34Padded& meshToBox, PxReal distance, bool bothTriangleSidesCollide,
|
||||
const Box& box, const PxVec3& localMotion, const PxVec3& localDir, const PxVec3& unitDir,
|
||||
const PxHitFlags& hitFlags, PxReal inflation, bool flipNormal, float distCoef);
|
||||
|
||||
virtual ~SweepBoxMeshHitCallback() {}
|
||||
|
||||
virtual PxAgain processHit(const PxGeomRaycastHit& meshHit, const PxVec3& lp0, const PxVec3& lp1, const PxVec3& lp2, PxReal& shrinkMaxT, const PxU32*);
|
||||
|
||||
bool finalizeHit( PxGeomSweepHit& sweepHit, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const PxTransform& boxTransform, const PxVec3& localDir,
|
||||
bool meshBothSides, bool isDoubleSided) const;
|
||||
|
||||
private:
|
||||
SweepBoxMeshHitCallback& operator=(const SweepBoxMeshHitCallback&);
|
||||
};
|
||||
|
||||
struct SweepConvexMeshHitCallback : SweepShapeMeshHitCallback
|
||||
{
|
||||
PxTriangle mHitTriangle;
|
||||
ConvexHullV mConvexHull;
|
||||
physx::aos::PxMatTransformV mMeshToConvex;
|
||||
physx::aos::PxTransformV mConvexPoseV;
|
||||
const Cm::FastVertex2ShapeScaling& mMeshScale;
|
||||
PxGeomSweepHit mSweepHit; // stores either the closest or any hit depending on value of mAnyHit
|
||||
physx::aos::FloatV mInitialDistance;
|
||||
physx::aos::Vec3V mConvexSpaceDir; // convexPose.rotateInv(-unit*distance)
|
||||
PxVec3 mUnitDir;
|
||||
PxVec3 mMeshSpaceUnitDir;
|
||||
PxReal mInflation;
|
||||
const bool mAnyHit;
|
||||
const bool mBothTriangleSidesCollide; // PT: true if PxMeshGeometryFlag::eDOUBLE_SIDED || PxHitFlag::eMESH_BOTH_SIDES
|
||||
|
||||
SweepConvexMeshHitCallback( const ConvexHullData& hull, const PxMeshScale& convexScale, const Cm::FastVertex2ShapeScaling& meshScale,
|
||||
const PxTransform& convexPose, const PxTransform& meshPose,
|
||||
const PxVec3& unitDir, PxReal distance, PxHitFlags hitFlags, bool bothTriangleSidesCollide, PxReal inflation,
|
||||
bool anyHit, float distCoef);
|
||||
|
||||
virtual ~SweepConvexMeshHitCallback() {}
|
||||
|
||||
virtual PxAgain processHit(const PxGeomRaycastHit& hit, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2, PxReal& shrunkMaxT, const PxU32*);
|
||||
|
||||
bool finalizeHit(PxGeomSweepHit& sweepHit, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose,
|
||||
const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose,
|
||||
const PxVec3& unitDir, PxReal inflation,
|
||||
bool isMtd, bool meshBothSides, bool isDoubleSided, bool bothTriangleSidesCollide);
|
||||
|
||||
private:
|
||||
SweepConvexMeshHitCallback& operator=(const SweepConvexMeshHitCallback&);
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
613
engine/third_party/physx/source/geomutils/src/mesh/GuSweepsMesh.cpp
vendored
Normal file
613
engine/third_party/physx/source/geomutils/src/mesh/GuSweepsMesh.cpp
vendored
Normal file
@@ -0,0 +1,613 @@
|
||||
// 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 "GuSweepTests.h"
|
||||
#include "GuSweepMesh.h"
|
||||
#include "GuInternal.h"
|
||||
#include "GuConvexUtilsInternal.h"
|
||||
#include "CmScaling.h"
|
||||
#include "GuSweepMTD.h"
|
||||
#include "GuVecBox.h"
|
||||
#include "GuVecCapsule.h"
|
||||
#include "GuSweepBoxTriangle_SAT.h"
|
||||
#include "GuSweepCapsuleTriangle.h"
|
||||
#include "GuSweepSphereTriangle.h"
|
||||
#include "GuDistancePointTriangle.h"
|
||||
#include "GuCapsule.h"
|
||||
#include "CmMatrix34.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
using namespace Cm;
|
||||
using namespace aos;
|
||||
|
||||
#include "GuSweepConvexTri.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool sweepSphereTriangle(const PxTriangle& tri,
|
||||
const PxVec3& center, PxReal radius,
|
||||
const PxVec3& unitDir, PxReal distance,
|
||||
PxGeomSweepHit& hit, PxVec3& triNormalOut,
|
||||
PxHitFlags hitFlags, bool isDoubleSided)
|
||||
{
|
||||
const bool meshBothSides = hitFlags & PxHitFlag::eMESH_BOTH_SIDES;
|
||||
if(!(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP))
|
||||
{
|
||||
const bool doBackfaceCulling = !isDoubleSided && !meshBothSides;
|
||||
|
||||
// PT: test if shapes initially overlap
|
||||
// PT: add culling here for now, but could be made more efficiently...
|
||||
|
||||
// Create triangle normal
|
||||
PxVec3 denormalizedNormal;
|
||||
tri.denormalizedNormal(denormalizedNormal);
|
||||
|
||||
// Backface culling
|
||||
if(doBackfaceCulling && (denormalizedNormal.dot(unitDir) > 0.0f))
|
||||
return false;
|
||||
|
||||
float s_unused, t_unused;
|
||||
const PxVec3 cp = closestPtPointTriangle(center, tri.verts[0], tri.verts[1], tri.verts[2], s_unused, t_unused);
|
||||
const PxReal dist2 = (cp - center).magnitudeSquared();
|
||||
if(dist2<=radius*radius)
|
||||
{
|
||||
triNormalOut = denormalizedNormal.getNormalized();
|
||||
return setInitialOverlapResults(hit, unitDir, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return sweepSphereTriangles(1, &tri,
|
||||
center, radius,
|
||||
unitDir, distance,
|
||||
NULL,
|
||||
hit, triNormalOut,
|
||||
isDoubleSided, meshBothSides, false, false);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SweepShapeMeshHitCallback::SweepShapeMeshHitCallback(CallbackMode::Enum inMode, const PxHitFlags& hitFlags, bool flipNormal, float distCoef) :
|
||||
MeshHitCallback<PxGeomRaycastHit> (inMode),
|
||||
mHitFlags (hitFlags),
|
||||
mStatus (false),
|
||||
mInitialOverlap (false),
|
||||
mFlipNormal (flipNormal),
|
||||
mDistCoeff (distCoef)
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SweepCapsuleMeshHitCallback::SweepCapsuleMeshHitCallback(
|
||||
PxGeomSweepHit& sweepHit, const PxMat34& worldMatrix, PxReal distance, bool meshDoubleSided,
|
||||
const Capsule& capsule, const PxVec3& unitDir, const PxHitFlags& hitFlags, bool flipNormal, float distCoef) :
|
||||
SweepShapeMeshHitCallback (CallbackMode::eMULTIPLE, hitFlags, flipNormal, distCoef),
|
||||
mSweepHit (sweepHit),
|
||||
mVertexToWorldSkew (worldMatrix),
|
||||
mTrueSweepDistance (distance),
|
||||
mBestAlignmentValue (2.0f),
|
||||
mBestDist (distance + GU_EPSILON_SAME_DISTANCE),
|
||||
mCapsule (capsule),
|
||||
mUnitDir (unitDir),
|
||||
mMeshDoubleSided (meshDoubleSided),
|
||||
mIsSphere (capsule.p0 == capsule.p1)
|
||||
{
|
||||
mSweepHit.distance = mTrueSweepDistance;
|
||||
}
|
||||
|
||||
PxAgain SweepCapsuleMeshHitCallback::processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit& aHit, const PxVec3& v0, const PxVec3& v1, const PxVec3& v2, PxReal& shrunkMaxT, const PxU32*)
|
||||
{
|
||||
const PxTriangle tmpt( mVertexToWorldSkew.transform(v0),
|
||||
mVertexToWorldSkew.transform(mFlipNormal ? v2 : v1),
|
||||
mVertexToWorldSkew.transform(mFlipNormal ? v1 : v2));
|
||||
|
||||
PxGeomSweepHit localHit; // PT: TODO: ctor!
|
||||
PxVec3 triNormal;
|
||||
// pick a farther hit within distEpsilon that is more opposing than the previous closest hit
|
||||
// make it a relative epsilon to make sure it still works with large distances
|
||||
const PxReal distEpsilon = GU_EPSILON_SAME_DISTANCE * PxMax(1.0f, mSweepHit.distance);
|
||||
const float minD = mSweepHit.distance + distEpsilon;
|
||||
if(mIsSphere)
|
||||
{
|
||||
if(!::sweepSphereTriangle( tmpt,
|
||||
mCapsule.p0, mCapsule.radius,
|
||||
mUnitDir, minD,
|
||||
localHit, triNormal,
|
||||
mHitFlags, mMeshDoubleSided))
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// PT: this one is safe because cullbox is NULL (no need to allocate one more triangle)
|
||||
if(!sweepCapsuleTriangles_Precise( 1, &tmpt,
|
||||
mCapsule,
|
||||
mUnitDir, minD,
|
||||
NULL,
|
||||
localHit, triNormal,
|
||||
mHitFlags, mMeshDoubleSided,
|
||||
NULL))
|
||||
return true;
|
||||
}
|
||||
|
||||
const PxReal alignmentValue = computeAlignmentValue(triNormal, mUnitDir);
|
||||
if(keepTriangle(localHit.distance, alignmentValue, mBestDist, mBestAlignmentValue, mTrueSweepDistance))
|
||||
{
|
||||
mBestAlignmentValue = alignmentValue;
|
||||
|
||||
// AP: need to shrink the sweep distance passed into sweepCapsuleTriangles for correctness so that next sweep is closer
|
||||
shrunkMaxT = localHit.distance * mDistCoeff; // shrunkMaxT is scaled
|
||||
|
||||
mBestDist = PxMin(mBestDist, localHit.distance); // exact lower bound
|
||||
mSweepHit.flags = localHit.flags;
|
||||
mSweepHit.distance = localHit.distance;
|
||||
mSweepHit.normal = localHit.normal;
|
||||
mSweepHit.position = localHit.position;
|
||||
mSweepHit.faceIndex = aHit.faceIndex;
|
||||
|
||||
mStatus = true;
|
||||
//ML:this is the initial overlap condition
|
||||
if(localHit.distance == 0.0f)
|
||||
{
|
||||
mInitialOverlap = true;
|
||||
return false;
|
||||
}
|
||||
if(mHitFlags & PxHitFlag::eANY_HIT)
|
||||
return false; // abort traversal
|
||||
}
|
||||
///
|
||||
else if(keepTriangleBasic(localHit.distance, mBestDist, mTrueSweepDistance))
|
||||
{
|
||||
mSweepHit.distance = localHit.distance;
|
||||
mBestDist = PxMin(mBestDist, localHit.distance); // exact lower bound
|
||||
}
|
||||
///
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SweepCapsuleMeshHitCallback::finalizeHit( PxGeomSweepHit& sweepHit, const Capsule& lss, const PxTriangleMeshGeometry& triMeshGeom,
|
||||
const PxTransform& pose, bool isDoubleSided) const
|
||||
{
|
||||
if(!mStatus)
|
||||
return false;
|
||||
|
||||
if(mInitialOverlap)
|
||||
{
|
||||
// PT: TODO: consider using 'setInitialOverlapResults' here
|
||||
bool hasContacts = false;
|
||||
if(mHitFlags & PxHitFlag::eMTD)
|
||||
{
|
||||
const Vec3V p0 = V3LoadU(mCapsule.p0);
|
||||
const Vec3V p1 = V3LoadU(mCapsule.p1);
|
||||
const FloatV radius = FLoad(lss.radius);
|
||||
CapsuleV capsuleV;
|
||||
capsuleV.initialize(p0, p1, radius);
|
||||
|
||||
//we need to calculate the MTD
|
||||
hasContacts = computeCapsule_TriangleMeshMTD(triMeshGeom, pose, capsuleV, mCapsule.radius, isDoubleSided, sweepHit);
|
||||
}
|
||||
setupSweepHitForMTD(sweepHit, hasContacts, mUnitDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSweepHit.distance = mBestDist;
|
||||
sweepHit.flags = PxHitFlag::eNORMAL | PxHitFlag::ePOSITION | PxHitFlag::eFACE_INDEX;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool sweepCapsule_MeshGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
|
||||
{
|
||||
PX_UNUSED(threadContext);
|
||||
PX_UNUSED(capsuleGeom_);
|
||||
PX_UNUSED(capsulePose_);
|
||||
|
||||
PX_ASSERT(geom.getType() == PxGeometryType::eTRIANGLEMESH);
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom);
|
||||
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
return Midphase::sweepCapsuleVsMesh(meshData, meshGeom, pose, lss, unitDir, distance, sweepHit, hitFlags, inflation);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// same as 'mat.transform(p)' but using SIMD
|
||||
static PX_FORCE_INLINE Vec4V transformV(const Vec4V p, const PxMat34Padded& mat)
|
||||
{
|
||||
Vec4V ResV = V4Scale(V4LoadU(&mat.m.column0.x), V4GetX(p));
|
||||
ResV = V4ScaleAdd(V4LoadU(&mat.m.column1.x), V4GetY(p), ResV);
|
||||
ResV = V4ScaleAdd(V4LoadU(&mat.m.column2.x), V4GetZ(p), ResV);
|
||||
ResV = V4Add(ResV, V4LoadU(&mat.p.x)); // PT: this load is safe thanks to padding
|
||||
return ResV;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SweepBoxMeshHitCallback::SweepBoxMeshHitCallback( CallbackMode::Enum mode_, const PxMat34Padded& meshToBox, PxReal distance, bool bothTriangleSidesCollide,
|
||||
const Box& box, const PxVec3& localMotion, const PxVec3& localDir, const PxVec3& unitDir,
|
||||
const PxHitFlags& hitFlags, PxReal inflation, bool flipNormal, float distCoef) :
|
||||
SweepShapeMeshHitCallback (mode_, hitFlags, flipNormal,distCoef),
|
||||
mMeshToBox (meshToBox),
|
||||
mDist (distance),
|
||||
mBox (box),
|
||||
mLocalDir (localDir),
|
||||
mWorldUnitDir (unitDir),
|
||||
mInflation (inflation),
|
||||
mBothTriangleSidesCollide (bothTriangleSidesCollide)
|
||||
{
|
||||
mLocalMotionV = V3LoadU(localMotion);
|
||||
mDistV = FLoad(distance);
|
||||
mDist0 = distance;
|
||||
mOneOverDir = PxVec3(
|
||||
mLocalDir.x!=0.0f ? 1.0f/mLocalDir.x : 0.0f,
|
||||
mLocalDir.y!=0.0f ? 1.0f/mLocalDir.y : 0.0f,
|
||||
mLocalDir.z!=0.0f ? 1.0f/mLocalDir.z : 0.0f);
|
||||
}
|
||||
|
||||
PxAgain SweepBoxMeshHitCallback::processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit& meshHit, const PxVec3& lp0, const PxVec3& lp1, const PxVec3& lp2, PxReal& shrinkMaxT, const PxU32*)
|
||||
{
|
||||
if(mHitFlags & PxHitFlag::ePRECISE_SWEEP)
|
||||
{
|
||||
const PxTriangle currentTriangle(
|
||||
mMeshToBox.transform(lp0),
|
||||
mMeshToBox.transform(mFlipNormal ? lp2 : lp1),
|
||||
mMeshToBox.transform(mFlipNormal ? lp1 : lp2));
|
||||
|
||||
PxF32 t = PX_MAX_REAL; // PT: could be better!
|
||||
if(!triBoxSweepTestBoxSpace(currentTriangle, mBox.extents, mLocalDir, mOneOverDir, mDist, t, !mBothTriangleSidesCollide))
|
||||
return true;
|
||||
|
||||
if(t <= mDist)
|
||||
{
|
||||
// PT: test if shapes initially overlap
|
||||
mDist = t;
|
||||
shrinkMaxT = t * mDistCoeff; // shrunkMaxT is scaled
|
||||
mMinClosestA = V3LoadU(currentTriangle.verts[0]); // PT: this is arbitrary
|
||||
mMinNormal = V3LoadU(-mWorldUnitDir);
|
||||
mStatus = true;
|
||||
mMinTriangleIndex = meshHit.faceIndex;
|
||||
mHitTriangle = currentTriangle;
|
||||
if(t == 0.0f)
|
||||
{
|
||||
mInitialOverlap = true;
|
||||
return false; // abort traversal
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const FloatV zero = FZero();
|
||||
|
||||
// PT: SIMD code similar to:
|
||||
// const Vec3V triV0 = V3LoadU(mMeshToBox.transform(lp0));
|
||||
// const Vec3V triV1 = V3LoadU(mMeshToBox.transform(lp1));
|
||||
// const Vec3V triV2 = V3LoadU(mMeshToBox.transform(lp2));
|
||||
//
|
||||
// SIMD version works but we need to ensure all loads are safe.
|
||||
// For incoming vertices they should either come from the vertex array or from a binary deserialized file.
|
||||
// For the vertex array we can just allocate one more vertex. For the binary file it should be ok as soon
|
||||
// as vertices aren't the last thing serialized in the file.
|
||||
// For the matrix only the last column is a problem, and we can easily solve that with some padding in the local class.
|
||||
const Vec3V triV0 = Vec3V_From_Vec4V(transformV(V4LoadU(&lp0.x), mMeshToBox));
|
||||
const Vec3V triV1 = Vec3V_From_Vec4V(transformV(V4LoadU(mFlipNormal ? &lp2.x : &lp1.x), mMeshToBox));
|
||||
const Vec3V triV2 = Vec3V_From_Vec4V(transformV(V4LoadU(mFlipNormal ? &lp1.x : &lp2.x), mMeshToBox));
|
||||
|
||||
if(!mBothTriangleSidesCollide)
|
||||
{
|
||||
const Vec3V triNormal = V3Cross(V3Sub(triV2, triV1),V3Sub(triV0, triV1));
|
||||
if(FAllGrtrOrEq(V3Dot(triNormal, mLocalMotionV), zero))
|
||||
return true;
|
||||
}
|
||||
|
||||
const Vec3V zeroV = V3Zero();
|
||||
const Vec3V boxExtents = V3LoadU(mBox.extents);
|
||||
const BoxV boxV(zeroV, boxExtents);
|
||||
|
||||
const TriangleV triangleV(triV0, triV1, triV2);
|
||||
|
||||
FloatV lambda;
|
||||
Vec3V closestA, normal;//closestA and normal is in the local space of convex hull
|
||||
const LocalConvex<TriangleV> convexA(triangleV);
|
||||
const LocalConvex<BoxV> convexB(boxV);
|
||||
const Vec3V initialSearchDir = V3Sub(triangleV.getCenter(), boxV.getCenter());
|
||||
if(!gjkRaycastPenetration<LocalConvex<TriangleV>, LocalConvex<BoxV> >(convexA, convexB, initialSearchDir, zero, zeroV, mLocalMotionV, lambda, normal, closestA, mInflation, false))
|
||||
return true;
|
||||
|
||||
mStatus = true;
|
||||
mMinClosestA = closestA;
|
||||
mMinTriangleIndex = meshHit.faceIndex;
|
||||
if(FAllGrtrOrEq(zero, lambda)) // lambda < 0? => initial overlap
|
||||
{
|
||||
mInitialOverlap = true;
|
||||
shrinkMaxT = 0.0f;
|
||||
mDistV = zero;
|
||||
mDist = 0.0f;
|
||||
mMinNormal = V3LoadU(-mWorldUnitDir);
|
||||
return false;
|
||||
}
|
||||
|
||||
PxF32 f;
|
||||
FStore(lambda, &f);
|
||||
mDist = f*mDist; // shrink dist
|
||||
mLocalMotionV = V3Scale(mLocalMotionV, lambda); // shrink localMotion
|
||||
mDistV = FMul(mDistV, lambda); // shrink distV
|
||||
mMinNormal = normal;
|
||||
if(mDist * mDistCoeff < shrinkMaxT) // shrink shrinkMaxT
|
||||
shrinkMaxT = mDist * mDistCoeff; // shrunkMaxT is scaled
|
||||
|
||||
//mHitTriangle = currentTriangle;
|
||||
V3StoreU(triV0, mHitTriangle.verts[0]);
|
||||
V3StoreU(triV1, mHitTriangle.verts[1]);
|
||||
V3StoreU(triV2, mHitTriangle.verts[2]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SweepBoxMeshHitCallback::finalizeHit( PxGeomSweepHit& sweepHit, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose,
|
||||
const PxTransform& boxTransform, const PxVec3& localDir,
|
||||
bool meshBothSides, bool isDoubleSided) const
|
||||
{
|
||||
if(!mStatus)
|
||||
return false;
|
||||
|
||||
Vec3V minClosestA = mMinClosestA;
|
||||
Vec3V minNormal = mMinNormal;
|
||||
sweepHit.faceIndex = mMinTriangleIndex;
|
||||
|
||||
if(mInitialOverlap)
|
||||
{
|
||||
bool hasContacts = false;
|
||||
if(mHitFlags & PxHitFlag::eMTD)
|
||||
hasContacts = computeBox_TriangleMeshMTD(triMeshGeom, pose, mBox, boxTransform, mInflation, mBothTriangleSidesCollide, sweepHit);
|
||||
|
||||
setupSweepHitForMTD(sweepHit, hasContacts, mWorldUnitDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
sweepHit.distance = mDist;
|
||||
sweepHit.flags = PxHitFlag::eFACE_INDEX;
|
||||
|
||||
// PT: we need the "best triangle" normal in order to call 'shouldFlipNormal'. We stored the best
|
||||
// triangle in both GJK & precise codepaths (in box space). We use a dedicated 'shouldFlipNormal'
|
||||
// function that delays computing the triangle normal.
|
||||
// TODO: would still be more efficient to store the best normal directly, it's already computed at least
|
||||
// in the GJK codepath.
|
||||
|
||||
const Vec3V p0 = V3LoadU(&boxTransform.p.x);
|
||||
const QuatV q0 = QuatVLoadU(&boxTransform.q.x);
|
||||
const PxTransformV boxPos(p0, q0);
|
||||
|
||||
if(mHitFlags & PxHitFlag::ePRECISE_SWEEP)
|
||||
{
|
||||
computeBoxLocalImpact(sweepHit.position, sweepHit.normal, sweepHit.flags, mBox, localDir, mHitTriangle, mHitFlags, isDoubleSided, meshBothSides, mDist);
|
||||
}
|
||||
else
|
||||
{
|
||||
sweepHit.flags |= PxHitFlag::eNORMAL|PxHitFlag::ePOSITION;
|
||||
|
||||
// PT: now for the GJK path, we must first always negate the returned normal. Similar to what happens in the precise path,
|
||||
// we can't delay this anymore: our normal must be properly oriented in order to call 'shouldFlipNormal'.
|
||||
minNormal = V3Neg(minNormal);
|
||||
|
||||
// PT: this one is to ensure the normal respects the mesh-both-sides/double-sided convention
|
||||
PxVec3 tmp;
|
||||
V3StoreU(minNormal, tmp);
|
||||
|
||||
if(shouldFlipNormal(tmp, meshBothSides, isDoubleSided, mHitTriangle, localDir, NULL))
|
||||
minNormal = V3Neg(minNormal);
|
||||
|
||||
// PT: finally, this moves everything back to world space
|
||||
V3StoreU(boxPos.rotate(minNormal), sweepHit.normal);
|
||||
V3StoreU(boxPos.transform(minClosestA), sweepHit.position);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool sweepBox_MeshGeom(GU_BOX_SWEEP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom.getType() == PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(threadContext);
|
||||
PX_UNUSED(boxPose_);
|
||||
PX_UNUSED(boxGeom_);
|
||||
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom);
|
||||
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
return Midphase::sweepBoxVsMesh(meshData, meshGeom, pose, box, unitDir, distance, sweepHit, hitFlags, inflation);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SweepConvexMeshHitCallback::SweepConvexMeshHitCallback( const ConvexHullData& hull, const PxMeshScale& convexScale, const FastVertex2ShapeScaling& meshScale,
|
||||
const PxTransform& convexPose, const PxTransform& meshPose,
|
||||
const PxVec3& unitDir, PxReal distance, PxHitFlags hitFlags, bool bothTriangleSidesCollide, PxReal inflation,
|
||||
bool anyHit, float distCoef) :
|
||||
SweepShapeMeshHitCallback (CallbackMode::eMULTIPLE, hitFlags, meshScale.flipsNormal(), distCoef),
|
||||
mMeshScale (meshScale),
|
||||
mUnitDir (unitDir),
|
||||
mInflation (inflation),
|
||||
mAnyHit (anyHit),
|
||||
mBothTriangleSidesCollide (bothTriangleSidesCollide)
|
||||
{
|
||||
mSweepHit.distance = distance; // this will be shrinking progressively as we sweep and clip the sweep length
|
||||
mSweepHit.faceIndex = 0xFFFFFFFF;
|
||||
|
||||
mMeshSpaceUnitDir = meshPose.rotateInv(unitDir);
|
||||
|
||||
const Vec3V worldDir = V3LoadU(unitDir);
|
||||
const FloatV dist = FLoad(distance);
|
||||
const QuatV q0 = QuatVLoadU(&meshPose.q.x);
|
||||
const Vec3V p0 = V3LoadU(&meshPose.p.x);
|
||||
|
||||
const QuatV q1 = QuatVLoadU(&convexPose.q.x);
|
||||
const Vec3V p1 = V3LoadU(&convexPose.p.x);
|
||||
|
||||
const PxTransformV meshPoseV(p0, q0);
|
||||
const PxTransformV convexPoseV(p1, q1);
|
||||
|
||||
mMeshToConvex = convexPoseV.transformInv(meshPoseV);
|
||||
mConvexPoseV = convexPoseV;
|
||||
mConvexSpaceDir = convexPoseV.rotateInv(V3Neg(V3Scale(worldDir, dist)));
|
||||
mInitialDistance = dist;
|
||||
|
||||
const Vec3V vScale = V3LoadU_SafeReadW(convexScale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
|
||||
const QuatV vQuat = QuatVLoadU(&convexScale.rotation.x);
|
||||
mConvexHull.initialize(&hull, V3Zero(), vScale, vQuat, convexScale.isIdentity());
|
||||
}
|
||||
|
||||
PxAgain SweepConvexMeshHitCallback::processHit( // all reported coords are in mesh local space including hit.position
|
||||
const PxGeomRaycastHit& hit, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2, PxReal& shrunkMaxT, const PxU32*)
|
||||
{
|
||||
const PxVec3 v0 = mMeshScale * av0;
|
||||
const PxVec3 v1 = mMeshScale * (mFlipNormal ? av2 : av1);
|
||||
const PxVec3 v2 = mMeshScale * (mFlipNormal ? av1 : av2);
|
||||
|
||||
// mSweepHit will be updated if sweep distance is < input mSweepHit.distance
|
||||
const PxReal oldDist = mSweepHit.distance;
|
||||
if(sweepConvexVsTriangle(
|
||||
v0, v1, v2, mConvexHull, mMeshToConvex, mConvexPoseV, mConvexSpaceDir,
|
||||
mUnitDir, mMeshSpaceUnitDir, mInitialDistance, oldDist, mSweepHit, mBothTriangleSidesCollide,
|
||||
mInflation, mInitialOverlap, hit.faceIndex))
|
||||
{
|
||||
mStatus = true;
|
||||
shrunkMaxT = mSweepHit.distance * mDistCoeff; // shrunkMaxT is scaled
|
||||
|
||||
// PT: added for 'shouldFlipNormal'
|
||||
mHitTriangle.verts[0] = v0;
|
||||
mHitTriangle.verts[1] = v1;
|
||||
mHitTriangle.verts[2] = v2;
|
||||
|
||||
if(mAnyHit)
|
||||
return false; // abort traversal
|
||||
|
||||
if(mSweepHit.distance == 0.0f)
|
||||
return false;
|
||||
}
|
||||
return true; // continue traversal
|
||||
}
|
||||
|
||||
bool SweepConvexMeshHitCallback::finalizeHit( PxGeomSweepHit& sweepHit, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose,
|
||||
const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose,
|
||||
const PxVec3& unitDir, PxReal inflation,
|
||||
bool isMtd, bool meshBothSides, bool isDoubleSided, bool bothTriangleSidesCollide)
|
||||
{
|
||||
if(!mStatus)
|
||||
return false;
|
||||
|
||||
if(mInitialOverlap)
|
||||
{
|
||||
bool hasContacts = false;
|
||||
if(isMtd)
|
||||
hasContacts = computeConvex_TriangleMeshMTD(meshGeom, pose, convexGeom, convexPose, inflation, bothTriangleSidesCollide, sweepHit);
|
||||
|
||||
setupSweepHitForMTD(sweepHit, hasContacts, unitDir);
|
||||
|
||||
sweepHit.faceIndex = mSweepHit.faceIndex;
|
||||
}
|
||||
else
|
||||
{
|
||||
sweepHit = mSweepHit;
|
||||
//sweepHit.position += unitDir * sweepHit.distance;
|
||||
sweepHit.normal = -sweepHit.normal;
|
||||
sweepHit.normal.normalize();
|
||||
|
||||
// PT: this one is to ensure the normal respects the mesh-both-sides/double-sided convention
|
||||
// PT: beware, the best triangle is in mesh-space, but the impact data is in world-space already
|
||||
if(shouldFlipNormal(sweepHit.normal, meshBothSides, isDoubleSided, mHitTriangle, unitDir, &pose))
|
||||
sweepHit.normal = -sweepHit.normal;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool sweepConvex_MeshGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
|
||||
{
|
||||
PX_ASSERT(geom.getType() == PxGeometryType::eTRIANGLEMESH);
|
||||
PX_UNUSED(threadContext);
|
||||
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom);
|
||||
|
||||
ConvexMesh* convexMesh = static_cast<ConvexMesh*>(convexGeom.convexMesh);
|
||||
TriangleMesh* meshData = static_cast<TriangleMesh*>(meshGeom.triangleMesh);
|
||||
|
||||
const bool idtScaleConvex = convexGeom.scale.isIdentity();
|
||||
const bool idtScaleMesh = meshGeom.scale.isIdentity();
|
||||
|
||||
FastVertex2ShapeScaling convexScaling;
|
||||
if(!idtScaleConvex)
|
||||
convexScaling.init(convexGeom.scale);
|
||||
|
||||
FastVertex2ShapeScaling meshScaling;
|
||||
if(!idtScaleMesh)
|
||||
meshScaling.init(meshGeom.scale);
|
||||
|
||||
PX_ASSERT(!convexMesh->getLocalBoundsFast().isEmpty());
|
||||
const PxBounds3 hullAABB = convexMesh->getLocalBoundsFast().transformFast(convexScaling.getVertex2ShapeSkew());
|
||||
|
||||
Box hullOBB;
|
||||
computeHullOBB(hullOBB, hullAABB, 0.0f, Matrix34FromTransform(convexPose), Matrix34FromTransform(pose), meshScaling, idtScaleMesh);
|
||||
|
||||
hullOBB.extents.x += inflation;
|
||||
hullOBB.extents.y += inflation;
|
||||
hullOBB.extents.z += inflation;
|
||||
|
||||
const PxVec3 localDir = pose.rotateInv(unitDir);
|
||||
|
||||
// inverse transform the sweep direction and distance to mesh space
|
||||
PxVec3 meshSpaceSweepVector = meshScaling.getShape2VertexSkew().transform(localDir*distance);
|
||||
const PxReal meshSpaceSweepDist = meshSpaceSweepVector.normalize();
|
||||
|
||||
PxReal distCoeff = 1.0f;
|
||||
if (!idtScaleMesh)
|
||||
distCoeff = meshSpaceSweepDist / distance;
|
||||
|
||||
const bool meshBothSides = hitFlags & PxHitFlag::eMESH_BOTH_SIDES;
|
||||
const bool isDoubleSided = meshGeom.meshFlags & PxMeshGeometryFlag::eDOUBLE_SIDED;
|
||||
const bool bothTriangleSidesCollide = isDoubleSided || meshBothSides;
|
||||
const bool anyHit = hitFlags & PxHitFlag::eANY_HIT;
|
||||
SweepConvexMeshHitCallback callback(
|
||||
convexMesh->getHull(), convexGeom.scale, meshScaling, convexPose, pose, -unitDir, distance, hitFlags,
|
||||
bothTriangleSidesCollide, inflation, anyHit, distCoeff);
|
||||
|
||||
Midphase::sweepConvexVsMesh(meshData, hullOBB, meshSpaceSweepVector, meshSpaceSweepDist, callback, anyHit);
|
||||
|
||||
const bool isMtd = hitFlags & PxHitFlag::eMTD;
|
||||
return callback.finalizeHit(sweepHit, meshGeom, pose, convexGeom, convexPose, unitDir, inflation, isMtd, meshBothSides, isDoubleSided, bothTriangleSidesCollide);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
106
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedron.h
vendored
Normal file
106
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedron.h
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_TETRAHEDRON_H
|
||||
#define GU_TETRAHEDRON_H
|
||||
|
||||
#include "foundation/PxVec3.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
#include "GuTriangle.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
/**
|
||||
\brief Structure used to store indices for a triangles points. T is either PxU32 or PxU16
|
||||
|
||||
*/
|
||||
|
||||
template <class T>
|
||||
struct TetrahedronT
|
||||
{
|
||||
PX_INLINE TetrahedronT() {}
|
||||
PX_INLINE TetrahedronT(T a, T b, T c, T d) { v[0] = a; v[1] = b; v[2] = c; v[3] = d; }
|
||||
template <class TX>
|
||||
PX_INLINE TetrahedronT(const TetrahedronT<TX>& other) { v[0] = other[0]; v[1] = other[1]; v[2] = other[2]; }
|
||||
PX_INLINE T& operator[](T i) { return v[i]; }
|
||||
template<class TX>//any type of TriangleT<>, possibly with different T
|
||||
PX_INLINE TetrahedronT<T>& operator=(const TetrahedronT<TX>& i) { v[0] = i[0]; v[1] = i[1]; v[2] = i[2]; v[3] = i[3]; return *this; }
|
||||
PX_INLINE const T& operator[](T i) const { return v[i]; }
|
||||
|
||||
PX_INLINE PxI32 indexOf(T i) const
|
||||
{
|
||||
if (v[0] == i) return 0;
|
||||
if (v[1] == i) return 1;
|
||||
if (v[2] == i) return 2;
|
||||
if (v[3] == i) return 3;
|
||||
return -1;
|
||||
}
|
||||
|
||||
PX_INLINE bool contains(T id) const
|
||||
{
|
||||
return v[0] == id || v[1] == id || v[2] == id || v[3] == id;
|
||||
}
|
||||
|
||||
PX_INLINE void replace(T oldId, T newId)
|
||||
{
|
||||
if (v[0] == oldId) v[0] = newId;
|
||||
if (v[1] == oldId) v[1] = newId;
|
||||
if (v[2] == oldId) v[2] = newId;
|
||||
if (v[3] == oldId) v[3] = newId;
|
||||
}
|
||||
|
||||
PX_INLINE void sort()
|
||||
{
|
||||
if (v[0] > v[1]) PxSwap(v[0], v[1]);
|
||||
if (v[2] > v[3]) PxSwap(v[2], v[3]);
|
||||
if (v[0] > v[2]) PxSwap(v[0], v[2]);
|
||||
if (v[1] > v[3]) PxSwap(v[1], v[3]);
|
||||
if (v[1] > v[2]) PxSwap(v[1], v[2]);
|
||||
}
|
||||
|
||||
PX_INLINE bool containsFace(const Gu::IndexedTriangleT<T>& triangle) const
|
||||
{
|
||||
return contains(triangle[0]) && contains(triangle[1]) && contains(triangle[2]);
|
||||
}
|
||||
|
||||
PX_INLINE static bool identical(Gu::TetrahedronT<T> x, Gu::TetrahedronT<T> y)
|
||||
{
|
||||
x.sort();
|
||||
y.sort();
|
||||
return x.v[0] == y.v[0] && x.v[1] == y.v[1] && x.v[2] == y.v[2] && x.v[3] == y.v[3];
|
||||
}
|
||||
|
||||
T v[4]; //vertex indices
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
324
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMesh.cpp
vendored
Normal file
324
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMesh.cpp
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
// 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 "GuMidphaseInterface.h"
|
||||
#include "GuTetrahedronMesh.h"
|
||||
#include "GuBox.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
void TetrahedronMesh::onRefCountZero()
|
||||
{
|
||||
if (mMeshFactory)
|
||||
{
|
||||
::onRefCountZero(this, mMeshFactory, false, "PxTetrahedronMesh::release: double deletion detected!");
|
||||
}
|
||||
}
|
||||
|
||||
void DeformableVolumeMesh::onRefCountZero()
|
||||
{
|
||||
if (mMeshFactory)
|
||||
{
|
||||
::onRefCountZero(this, mMeshFactory, false, "PxDeformableVolumeMesh::release: double deletion detected!");
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DeformableVolumeAuxData::DeformableVolumeAuxData(DeformableVolumeSimulationData& d, DeformableVolumeCollisionData& c, CollisionMeshMappingData& e)
|
||||
: PxDeformableVolumeAuxData(PxType(PxConcreteType::eDEFORMABLE_VOLUME_STATE), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
||||
, mGridModelInvMass(d.mGridModelInvMass)
|
||||
, mGridModelTetraRestPoses(d.mGridModelTetraRestPoses)
|
||||
, mGridModelOrderedTetrahedrons(d.mGridModelOrderedTetrahedrons)
|
||||
, mGMNbPartitions(d.mGridModelNbPartitions)
|
||||
, mGMMaxMaxTetsPerPartitions(d.mGridModelMaxTetsPerPartitions)
|
||||
, mGMRemapOutputSize(d.mGMRemapOutputSize)
|
||||
, mGMRemapOutputCP(d.mGMRemapOutputCP)
|
||||
, mGMAccumulatedPartitionsCP(d.mGMAccumulatedPartitionsCP)
|
||||
, mGMAccumulatedCopiesCP(d.mGMAccumulatedCopiesCP)
|
||||
, mCollisionAccumulatedTetrahedronsRef(e.mCollisionAccumulatedTetrahedronsRef)
|
||||
, mCollisionTetrahedronsReferences(e.mCollisionTetrahedronsReferences)
|
||||
, mCollisionNbTetrahedronsReferences(e.mCollisionNbTetrahedronsReferences)
|
||||
, mCollisionSurfaceVertsHint(e.mCollisionSurfaceVertsHint)
|
||||
, mCollisionSurfaceVertToTetRemap(e.mCollisionSurfaceVertToTetRemap)
|
||||
, mVertsBarycentricInGridModel(e.mVertsBarycentricInGridModel)
|
||||
, mVertsRemapInGridModel(e.mVertsRemapInGridModel)
|
||||
, mTetsRemapColToSim(e.mTetsRemapColToSim)
|
||||
, mTetsRemapSize(e.mTetsRemapSize)
|
||||
, mTetsAccumulatedRemapColToSim(e.mTetsAccumulatedRemapColToSim)
|
||||
|
||||
, mGMPullIndices(d.mGMPullIndices)
|
||||
, mTetraRestPoses(c.mTetraRestPoses)
|
||||
, mNumTetsPerElement(d.mNumTetsPerElement)
|
||||
|
||||
{
|
||||
// this constructor takes ownership of memory from the data object
|
||||
d.mGridModelInvMass = 0;
|
||||
d.mGridModelTetraRestPoses = 0;
|
||||
d.mGridModelOrderedTetrahedrons = 0;
|
||||
d.mGMRemapOutputCP = 0;
|
||||
d.mGMAccumulatedPartitionsCP = 0;
|
||||
d.mGMAccumulatedCopiesCP = 0;
|
||||
e.mCollisionAccumulatedTetrahedronsRef = 0;
|
||||
e.mCollisionTetrahedronsReferences = 0;
|
||||
e.mCollisionSurfaceVertsHint = 0;
|
||||
e.mCollisionSurfaceVertToTetRemap = 0;
|
||||
d.mGMPullIndices = 0;
|
||||
|
||||
e.mVertsBarycentricInGridModel = 0;
|
||||
e.mVertsRemapInGridModel = 0;
|
||||
e.mTetsRemapColToSim = 0;
|
||||
e.mTetsAccumulatedRemapColToSim = 0;
|
||||
|
||||
c.mTetraRestPoses = 0;
|
||||
}
|
||||
|
||||
DeformableVolumeAuxData::~DeformableVolumeAuxData()
|
||||
{
|
||||
PX_FREE(mGridModelInvMass);
|
||||
|
||||
PX_FREE(mGridModelTetraRestPoses);
|
||||
PX_FREE(mGridModelOrderedTetrahedrons);
|
||||
PX_FREE(mGMRemapOutputCP);
|
||||
PX_FREE(mGMAccumulatedPartitionsCP);
|
||||
PX_FREE(mGMAccumulatedCopiesCP);
|
||||
PX_FREE(mCollisionAccumulatedTetrahedronsRef);
|
||||
PX_FREE(mCollisionTetrahedronsReferences);
|
||||
PX_FREE(mCollisionSurfaceVertsHint);
|
||||
PX_FREE(mCollisionSurfaceVertToTetRemap);
|
||||
|
||||
PX_FREE(mVertsBarycentricInGridModel);
|
||||
PX_FREE(mVertsRemapInGridModel);
|
||||
PX_FREE(mTetsRemapColToSim);
|
||||
PX_FREE(mTetsAccumulatedRemapColToSim);
|
||||
|
||||
PX_FREE(mGMPullIndices);
|
||||
PX_FREE(mTetraRestPoses);
|
||||
}
|
||||
|
||||
TetrahedronMesh::TetrahedronMesh(PxU32 nbVertices, PxVec3* vertices, PxU32 nbTetrahedrons, void* tetrahedrons, PxU8 flags, PxBounds3 aabb, PxReal geomEpsilon)
|
||||
: PxTetrahedronMesh(PxType(PxConcreteType::eTETRAHEDRON_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
||||
, mNbVertices(nbVertices)
|
||||
, mVertices(vertices)
|
||||
, mNbTetrahedrons(nbTetrahedrons)
|
||||
, mTetrahedrons(tetrahedrons)
|
||||
, mFlags(flags)
|
||||
, mMaterialIndices(NULL)
|
||||
, mAABB(aabb)
|
||||
, mGeomEpsilon(geomEpsilon)
|
||||
{
|
||||
}
|
||||
|
||||
TetrahedronMesh::TetrahedronMesh(TetrahedronMeshData& mesh)
|
||||
: PxTetrahedronMesh(PxType(PxConcreteType::eTETRAHEDRON_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
||||
, mNbVertices(mesh.mNbVertices)
|
||||
, mVertices(mesh.mVertices)
|
||||
, mNbTetrahedrons(mesh.mNbTetrahedrons)
|
||||
, mTetrahedrons(mesh.mTetrahedrons)
|
||||
, mFlags(mesh.mFlags)
|
||||
, mMaterialIndices(mesh.mMaterialIndices)
|
||||
, mAABB(mesh.mAABB)
|
||||
, mGeomEpsilon(mesh.mGeomEpsilon)
|
||||
{
|
||||
// this constructor takes ownership of memory from the data object
|
||||
mesh.mVertices = 0;
|
||||
mesh.mTetrahedrons = 0;
|
||||
mesh.mMaterialIndices = 0;
|
||||
}
|
||||
|
||||
TetrahedronMesh::TetrahedronMesh(MeshFactory* meshFactory, TetrahedronMeshData& mesh)
|
||||
: PxTetrahedronMesh(PxType(PxConcreteType::eTETRAHEDRON_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
||||
, mNbVertices(mesh.mNbVertices)
|
||||
, mVertices(mesh.mVertices)
|
||||
, mNbTetrahedrons(mesh.mNbTetrahedrons)
|
||||
, mTetrahedrons(mesh.mTetrahedrons)
|
||||
, mFlags(mesh.mFlags)
|
||||
, mMaterialIndices(mesh.mMaterialIndices)
|
||||
, mAABB(mesh.mAABB)
|
||||
, mGeomEpsilon(mesh.mGeomEpsilon)
|
||||
, mMeshFactory(meshFactory)
|
||||
{
|
||||
// this constructor takes ownership of memory from the data object
|
||||
mesh.mVertices = 0;
|
||||
mesh.mTetrahedrons = 0;
|
||||
mesh.mMaterialIndices = 0;
|
||||
}
|
||||
|
||||
TetrahedronMesh::~TetrahedronMesh()
|
||||
{
|
||||
PX_FREE(mTetrahedrons);
|
||||
PX_FREE(mVertices);
|
||||
PX_FREE(mMaterialIndices);
|
||||
}
|
||||
|
||||
BVTetrahedronMesh::BVTetrahedronMesh(TetrahedronMeshData& mesh, DeformableVolumeCollisionData& d, MeshFactory* factory) : TetrahedronMesh(mesh)
|
||||
, mFaceRemap(d.mFaceRemap)
|
||||
, mGRB_tetraIndices(d.mGRB_primIndices)
|
||||
, mGRB_tetraSurfaceHint(d.mGRB_tetraSurfaceHint)
|
||||
, mGRB_faceRemap(d.mGRB_faceRemap)
|
||||
, mGRB_faceRemapInverse(d.mGRB_faceRemapInverse)
|
||||
, mGRB_BV32Tree(d.mGRB_BV32Tree)
|
||||
{
|
||||
mMeshFactory = factory;
|
||||
|
||||
bool has16BitIndices = (mesh.mFlags & PxMeshFlag::e16_BIT_INDICES) ? true : false;
|
||||
|
||||
mMeshInterface4.mVerts = mVertices; // mesh.mVertices;
|
||||
mMeshInterface4.mNbVerts = mesh.mNbVertices;
|
||||
mMeshInterface4.mNbTetrahedrons = mesh.mNbTetrahedrons;
|
||||
mMeshInterface4.mTetrahedrons16 = has16BitIndices ? reinterpret_cast<IndTetrahedron16*>(mTetrahedrons/*mesh.mTetrahedrons*/) : NULL;
|
||||
mMeshInterface4.mTetrahedrons32 = has16BitIndices ? NULL : reinterpret_cast<IndTetrahedron32*>(mTetrahedrons/*mesh.mTetrahedrons*/);
|
||||
|
||||
mBV4Tree = d.mBV4Tree;
|
||||
mBV4Tree.mMeshInterface = &mMeshInterface4;
|
||||
|
||||
if (mGRB_BV32Tree)
|
||||
{
|
||||
mMeshInterface32.mVerts = mVertices; // mesh.mVertices;
|
||||
mMeshInterface32.mNbVerts = mesh.mNbVertices;
|
||||
mMeshInterface32.mNbTetrahedrons = mesh.mNbTetrahedrons;
|
||||
mMeshInterface32.mTetrahedrons16 = has16BitIndices ? reinterpret_cast<IndTetrahedron16*>(d.mGRB_primIndices) : NULL;
|
||||
mMeshInterface32.mTetrahedrons32 = has16BitIndices ? NULL : reinterpret_cast<IndTetrahedron32*>(d.mGRB_primIndices);
|
||||
|
||||
mGRB_BV32Tree->mMeshInterface = &mMeshInterface32;
|
||||
}
|
||||
|
||||
// this constructor takes ownership of memory from the data object
|
||||
d.mGRB_tetraSurfaceHint = NULL;
|
||||
d.mFaceRemap = NULL;
|
||||
|
||||
d.mGRB_primIndices = NULL;
|
||||
d.mGRB_faceRemap = NULL;
|
||||
d.mGRB_faceRemapInverse = NULL;
|
||||
d.mGRB_BV32Tree = NULL;
|
||||
|
||||
mesh.mVertices = NULL;
|
||||
mesh.mTetrahedrons = NULL;
|
||||
}
|
||||
|
||||
DeformableVolumeMesh::DeformableVolumeMesh(MeshFactory* factory, DeformableVolumeMeshData& d)
|
||||
: PxDeformableVolumeMesh(PxType(PxConcreteType::eDEFORMABLE_VOLUME_MESH), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE)
|
||||
, mMeshFactory(factory)
|
||||
{
|
||||
mDeformableVolumeAuxData = PX_NEW(DeformableVolumeAuxData)(d.mSimulationData, d.mCollisionData, d.mMappingData);
|
||||
mCollisionMesh = PX_NEW(BVTetrahedronMesh)(d.mCollisionMesh, d.mCollisionData, factory);
|
||||
mSimulationMesh = PX_NEW(TetrahedronMesh)(factory, d.mSimulationMesh);
|
||||
}
|
||||
|
||||
DeformableVolumeMesh::~DeformableVolumeMesh()
|
||||
{
|
||||
if (getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)
|
||||
{
|
||||
PX_DELETE(mDeformableVolumeAuxData);
|
||||
PX_DELETE(mCollisionMesh);
|
||||
PX_DELETE(mSimulationMesh);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PT: used to be automatic but making it manual saves bytes in the internal mesh
|
||||
|
||||
void DeformableVolumeMesh::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
//PX_DEFINE_DYNAMIC_ARRAY(TriangleMesh, mVertices, PxField::eVEC3, mNbVertices, Ps::PxFieldFlag::eSERIALIZE),
|
||||
if (getCollisionMeshFast()->mVertices)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(getCollisionMeshFast()->mVertices, getCollisionMeshFast()->mNbVertices * sizeof(PxVec3));
|
||||
}
|
||||
|
||||
/*if (mSurfaceTriangles)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mSurfaceTriangles, mNbTriangles * 3 * sizeof(PxU32));
|
||||
}*/
|
||||
|
||||
if (getCollisionMeshFast()->mTetrahedrons)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(getCollisionMeshFast()->mTetrahedrons, getCollisionMeshFast()->mNbTetrahedrons * 4 * sizeof(PxU32));
|
||||
}
|
||||
|
||||
/*if (mTetSurfaceHint)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mTetSurfaceHint, mNbTetrahedrons * sizeof(PxU8));
|
||||
}*/
|
||||
|
||||
if (getCollisionMeshFast()->mMaterialIndices)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(getCollisionMeshFast()->mMaterialIndices, getCollisionMeshFast()->mNbTetrahedrons * sizeof(PxU16));
|
||||
}
|
||||
|
||||
if (getCollisionMeshFast()->mFaceRemap)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(getCollisionMeshFast()->mFaceRemap, getCollisionMeshFast()->mNbTetrahedrons * sizeof(PxU32));
|
||||
}
|
||||
}
|
||||
|
||||
void DeformableVolumeMesh::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
// PT: vertices are followed by indices, so it will be safe to V4Load vertices from a deserialized binary file
|
||||
if (getCollisionMeshFast()->mVertices)
|
||||
getCollisionMeshFast()->mVertices = context.readExtraData<PxVec3, PX_SERIAL_ALIGN>(getCollisionMeshFast()->mNbVertices);
|
||||
|
||||
if (getCollisionMeshFast()->mTetrahedrons)
|
||||
getCollisionMeshFast()->mTetrahedrons = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(4 * getCollisionMeshFast()->mNbTetrahedrons);
|
||||
|
||||
if (getCollisionMeshFast()->mFaceRemap)
|
||||
getCollisionMeshFast()->mFaceRemap = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(getCollisionMeshFast()->mNbTetrahedrons);
|
||||
|
||||
getCollisionMeshFast()->mGRB_tetraIndices = NULL;
|
||||
getCollisionMeshFast()->mGRB_tetraSurfaceHint = NULL;
|
||||
getCollisionMeshFast()->mGRB_faceRemap = NULL;
|
||||
getCollisionMeshFast()->mGRB_faceRemapInverse = NULL;
|
||||
getCollisionMeshFast()->mGRB_BV32Tree = NULL;
|
||||
}
|
||||
|
||||
void DeformableVolumeMesh::release()
|
||||
{
|
||||
Cm::RefCountable_decRefCount(*this);
|
||||
}
|
||||
|
||||
//PxVec3* TetrahedronMesh::getVerticesForModification()
|
||||
//{
|
||||
// PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxDeformableVolumeMesh::getVerticesForModification() is not currently supported.");
|
||||
//
|
||||
// return NULL;
|
||||
//}
|
||||
|
||||
//PxBounds3 BVTetrahedronMesh::refitBVH()
|
||||
//{
|
||||
// PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxDeformableVolumeMesh::refitBVH() is not currently supported.");
|
||||
//
|
||||
// return PxBounds3(mAABB.getMin(), mAABB.getMax());
|
||||
//}
|
||||
293
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMesh.h
vendored
Normal file
293
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMesh.h
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
// 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_TETRAHEDRONMESH_H
|
||||
#define GU_TETRAHEDRONMESH_H
|
||||
|
||||
#include "foundation/PxIO.h"
|
||||
#include "geometry/PxTetrahedronMeshGeometry.h"
|
||||
#include "geometry/PxTetrahedronMesh.h"
|
||||
#include "geometry/PxTetrahedron.h"
|
||||
#include "geometry/PxSimpleTriangleMesh.h"
|
||||
#include "CmRefCountable.h"
|
||||
#include "common/PxRenderOutput.h"
|
||||
#include "GuMeshData.h"
|
||||
#include "GuCenterExtents.h"
|
||||
#include "GuMeshFactory.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class MeshFactory;
|
||||
#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 DeformableVolumeAuxData : public PxDeformableVolumeAuxData, public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
DeformableVolumeAuxData(DeformableVolumeSimulationData& d, DeformableVolumeCollisionData& c, CollisionMeshMappingData& e);
|
||||
|
||||
virtual ~DeformableVolumeAuxData();
|
||||
|
||||
virtual const char* getConcreteTypeName() const { return "PxDeformableVolumeAuxData"; }
|
||||
|
||||
virtual void acquireReference() { Cm::RefCountable_incRefCount(*this); }
|
||||
virtual PxU32 getReferenceCount() const { return Cm::RefCountable_getRefCount(*this); }
|
||||
virtual void release() { Cm::RefCountable_decRefCount(*this); }
|
||||
virtual void onRefCountZero() { PX_DELETE_THIS; }
|
||||
virtual PxReal* getGridModelInvMass() { return mGridModelInvMass; }
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbTetRemapSizeFast() const { return mTetsRemapSize; }
|
||||
PX_FORCE_INLINE PxReal* getGridModelInvMassFast() { return mGridModelInvMass; }
|
||||
PX_FORCE_INLINE PxU32 getNbGMPartitionFast() const { return mGMNbPartitions; }
|
||||
|
||||
PX_FORCE_INLINE PxU32 getGMRemapOutputSizeFast() const { return mGMRemapOutputSize; }
|
||||
PX_FORCE_INLINE PxU32 getGMMaxTetsPerPartitionsFast() const { return mGMMaxMaxTetsPerPartitions; }
|
||||
|
||||
|
||||
PX_FORCE_INLINE PxU32* getCollisionAccumulatedTetrahedronRefs() const { return mCollisionAccumulatedTetrahedronsRef; }
|
||||
PX_FORCE_INLINE PxU32* getCollisionTetrahedronRefs() const { return mCollisionTetrahedronsReferences; }
|
||||
PX_FORCE_INLINE PxU32 getCollisionNbTetrahedronRefs() const { return mCollisionNbTetrahedronsReferences; }
|
||||
|
||||
PX_FORCE_INLINE PxU32* getCollisionSurfaceVertToTetRemap() const { return mCollisionSurfaceVertToTetRemap; }
|
||||
PX_FORCE_INLINE PxMat33* getGridModelRestPosesFast() { return mGridModelTetraRestPoses; }
|
||||
PX_FORCE_INLINE PxMat33* getRestPosesFast() { return mTetraRestPoses; }
|
||||
|
||||
float* mGridModelInvMass;
|
||||
|
||||
PxMat33* mGridModelTetraRestPoses;
|
||||
PxU32* mGridModelOrderedTetrahedrons;
|
||||
|
||||
|
||||
PxU32 mGMNbPartitions;
|
||||
PxU32 mGMMaxMaxTetsPerPartitions;
|
||||
PxU32 mGMRemapOutputSize;
|
||||
PxU32* mGMRemapOutputCP;
|
||||
|
||||
PxU32* mGMAccumulatedPartitionsCP;
|
||||
PxU32* mGMAccumulatedCopiesCP;
|
||||
|
||||
PxU32* mCollisionAccumulatedTetrahedronsRef;
|
||||
PxU32* mCollisionTetrahedronsReferences;
|
||||
PxU32 mCollisionNbTetrahedronsReferences;
|
||||
|
||||
PxU8* mCollisionSurfaceVertsHint;
|
||||
PxU32* mCollisionSurfaceVertToTetRemap;
|
||||
|
||||
PxReal* mVertsBarycentricInGridModel;
|
||||
PxU32* mVertsRemapInGridModel;
|
||||
|
||||
|
||||
PxU32* mTetsRemapColToSim;
|
||||
PxU32 mTetsRemapSize;
|
||||
PxU32* mTetsAccumulatedRemapColToSim;
|
||||
|
||||
PxU32* mGMPullIndices;
|
||||
|
||||
PxMat33* mTetraRestPoses;
|
||||
|
||||
PxU32 mNumTetsPerElement;
|
||||
};
|
||||
|
||||
class TetrahedronMesh : public PxTetrahedronMesh, public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
TetrahedronMesh(PxU32 nbVertices, PxVec3* vertices, PxU32 nbTetrahedrons, void* tetrahedrons, PxU8 flags, PxBounds3 aabb, PxReal geomEpsilon);
|
||||
TetrahedronMesh(TetrahedronMeshData& mesh);
|
||||
TetrahedronMesh(MeshFactory* meshFactory, TetrahedronMeshData& mesh);
|
||||
virtual ~TetrahedronMesh();
|
||||
|
||||
virtual const char* getConcreteTypeName() const { return "PxTetrahedronMesh"; }
|
||||
|
||||
virtual void acquireReference() { Cm::RefCountable_incRefCount(*this); }
|
||||
virtual PxU32 getReferenceCount() const { return Cm::RefCountable_getRefCount(*this); }
|
||||
virtual void release() { Cm::RefCountable_decRefCount(*this); }
|
||||
virtual void onRefCountZero();
|
||||
|
||||
virtual PxU32 getNbVertices() const { return mNbVertices; }
|
||||
virtual const PxVec3* getVertices() const { return mVertices; }
|
||||
virtual PxU32 getNbTetrahedrons() const { return mNbTetrahedrons; }
|
||||
virtual const void* getTetrahedrons() const { return mTetrahedrons; }
|
||||
virtual PxTetrahedronMeshFlags getTetrahedronMeshFlags() const { return PxTetrahedronMeshFlags(mFlags); }
|
||||
virtual const PxU32* getTetrahedraRemap() const { return NULL; }
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbVerticesFast() const { return mNbVertices; }
|
||||
PX_FORCE_INLINE PxVec3* getVerticesFast() const { return mVertices; }
|
||||
PX_FORCE_INLINE PxU32 getNbTetrahedronsFast() const { return mNbTetrahedrons; }
|
||||
PX_FORCE_INLINE const void* getTetrahedronsFast() const { return mTetrahedrons; }
|
||||
PX_FORCE_INLINE bool has16BitIndices() const { return (mFlags & PxMeshFlag::e16_BIT_INDICES) ? true : false; }
|
||||
PX_FORCE_INLINE bool hasPerTriangleMaterials() const { return mMaterialIndices != NULL; }
|
||||
PX_FORCE_INLINE const PxU16* getMaterials() const { return mMaterialIndices; }
|
||||
|
||||
PX_FORCE_INLINE const CenterExtents& getLocalBoundsFast() const { return mAABB; }
|
||||
|
||||
PX_FORCE_INLINE const CenterExtentsPadded& getPaddedBounds() const
|
||||
{
|
||||
// PT: see compile-time assert in cpp
|
||||
return static_cast<const CenterExtentsPadded&>(mAABB);
|
||||
}
|
||||
|
||||
virtual PxBounds3 getLocalBounds() const
|
||||
{
|
||||
PX_ASSERT(mAABB.isValid());
|
||||
return PxBounds3::centerExtents(mAABB.mCenter, mAABB.mExtents);
|
||||
}
|
||||
|
||||
PxU32 mNbVertices;
|
||||
PxVec3* mVertices;
|
||||
PxU32 mNbTetrahedrons;
|
||||
void* mTetrahedrons;
|
||||
|
||||
PxU8 mFlags; //!< Flag whether indices are 16 or 32 bits wide
|
||||
|
||||
PxU16* mMaterialIndices; //!< the size of the array is mNbTetrahedrons.
|
||||
|
||||
// PT: WARNING: bounds must be followed by at least 32bits of data for safe SIMD loading
|
||||
CenterExtents mAABB;
|
||||
PxReal mGeomEpsilon;
|
||||
|
||||
MeshFactory* mMeshFactory; // PT: changed to pointer for serialization
|
||||
};
|
||||
|
||||
PX_FORCE_INLINE const Gu::TetrahedronMesh* _getTetraMeshData(const PxTetrahedronMeshGeometry& meshGeom)
|
||||
{
|
||||
return static_cast<const Gu::TetrahedronMesh*>(meshGeom.tetrahedronMesh);
|
||||
}
|
||||
|
||||
class BVTetrahedronMesh : public TetrahedronMesh
|
||||
{
|
||||
public:
|
||||
BVTetrahedronMesh(TetrahedronMeshData& mesh, DeformableVolumeCollisionData& d, MeshFactory* factory = NULL);
|
||||
|
||||
virtual ~BVTetrahedronMesh()
|
||||
{
|
||||
PX_FREE(mGRB_tetraIndices);
|
||||
PX_FREE(mGRB_tetraSurfaceHint);
|
||||
PX_FREE(mGRB_faceRemap);
|
||||
PX_FREE(mGRB_faceRemapInverse);
|
||||
PX_DELETE(mGRB_BV32Tree);
|
||||
PX_FREE(mFaceRemap);
|
||||
}
|
||||
|
||||
//virtual PxBounds3 refitBVH();
|
||||
|
||||
PX_FORCE_INLINE const Gu::BV4Tree& getBV4Tree() const { return mBV4Tree; }
|
||||
|
||||
PX_FORCE_INLINE Gu::BV4Tree& getBV4Tree() { return mBV4Tree; }
|
||||
|
||||
PX_FORCE_INLINE void* getGRBTetraFaceRemap() { return mGRB_faceRemap; }
|
||||
|
||||
PX_FORCE_INLINE void* getGRBTetraFaceRemapInverse() { return mGRB_faceRemapInverse; }
|
||||
|
||||
virtual const PxU32* getTetrahedraRemap() const { return mFaceRemap; }
|
||||
|
||||
PX_FORCE_INLINE bool isTetMeshGPUCompatible() const
|
||||
{
|
||||
return mGRB_BV32Tree != NULL;
|
||||
}
|
||||
|
||||
PxU32* mFaceRemap; //!< new faces to old faces mapping (after cleaning, etc). Usage: old = faceRemap[new]
|
||||
|
||||
// GRB data -------------------------
|
||||
void* mGRB_tetraIndices; //!< GRB: GPU-friendly tri indices [uint4]
|
||||
PxU8* mGRB_tetraSurfaceHint;
|
||||
PxU32* mGRB_faceRemap;
|
||||
PxU32* mGRB_faceRemapInverse;
|
||||
Gu::BV32Tree* mGRB_BV32Tree; //!< GRB: BV32 tree
|
||||
|
||||
private:
|
||||
Gu::TetrahedronSourceMesh mMeshInterface4;
|
||||
Gu::BV4Tree mBV4Tree;
|
||||
Gu::TetrahedronSourceMesh mMeshInterface32;
|
||||
};
|
||||
|
||||
// Possible optimization: align the whole struct to cache line
|
||||
class DeformableVolumeMesh : public PxDeformableVolumeMesh, public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
|
||||
virtual const char* getConcreteTypeName() const { return "PxDeformableVolumeMesh"; }
|
||||
|
||||
// PX_SERIALIZATION
|
||||
virtual void exportExtraData(PxSerializationContext& ctx);
|
||||
void importExtraData(PxDeserializationContext&);
|
||||
virtual void release();
|
||||
|
||||
void resolveReferences(PxDeserializationContext&) {}
|
||||
virtual void requiresObjects(PxProcessPxBaseCallback&) {}
|
||||
//~PX_SERIALIZATION
|
||||
|
||||
virtual void acquireReference() { Cm::RefCountable_incRefCount(*this); }
|
||||
virtual PxU32 getReferenceCount() const { return Cm::RefCountable_getRefCount(*this); }
|
||||
virtual void onRefCountZero();
|
||||
|
||||
//virtual PxMeshMidPhase::Enum getMidphaseID() const { return PxMeshMidPhase::eBVH34; }
|
||||
|
||||
DeformableVolumeMesh(MeshFactory* factory, DeformableVolumeMeshData& data);
|
||||
|
||||
virtual ~DeformableVolumeMesh();
|
||||
|
||||
void setMeshFactory(MeshFactory* factory) { mMeshFactory = factory; }
|
||||
|
||||
virtual const PxTetrahedronMesh* getCollisionMesh() const { return mCollisionMesh; }
|
||||
virtual PxTetrahedronMesh* getCollisionMesh() { return mCollisionMesh; }
|
||||
|
||||
PX_FORCE_INLINE const BVTetrahedronMesh* getCollisionMeshFast() const { return mCollisionMesh; }
|
||||
PX_FORCE_INLINE BVTetrahedronMesh* getCollisionMeshFast() { return mCollisionMesh; }
|
||||
|
||||
virtual const PxTetrahedronMesh* getSimulationMesh() const { return mSimulationMesh; }
|
||||
virtual PxTetrahedronMesh* getSimulationMesh() { return mSimulationMesh; }
|
||||
|
||||
PX_FORCE_INLINE const TetrahedronMesh* getSimulationMeshFast() const { return mSimulationMesh; }
|
||||
PX_FORCE_INLINE TetrahedronMesh* getSimulationMeshFast() { return mSimulationMesh; }
|
||||
|
||||
virtual const PxDeformableVolumeAuxData* getDeformableVolumeAuxData() const { return mDeformableVolumeAuxData; }
|
||||
virtual PxDeformableVolumeAuxData* getDeformableVolumeAuxData() { return mDeformableVolumeAuxData; }
|
||||
|
||||
PX_FORCE_INLINE const DeformableVolumeAuxData* getDeformableVolumeAuxDataFast() const { return mDeformableVolumeAuxData; }
|
||||
PX_FORCE_INLINE DeformableVolumeAuxData* getDeformableVolumeAuxDataFast() { return mDeformableVolumeAuxData; }
|
||||
|
||||
protected:
|
||||
TetrahedronMesh* mSimulationMesh;
|
||||
BVTetrahedronMesh* mCollisionMesh;
|
||||
DeformableVolumeAuxData* mDeformableVolumeAuxData;
|
||||
|
||||
MeshFactory* mMeshFactory; // PT: changed to pointer for serialization
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace Gu
|
||||
}
|
||||
|
||||
#endif
|
||||
134
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMeshUtils.cpp
vendored
Normal file
134
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMeshUtils.cpp
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
|
||||
#include "GuTetrahedronMeshUtils.h"
|
||||
#include "GuDistancePointTetrahedron.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
|
||||
void convertDeformableVolumeCollisionToSimMeshTets(const PxTetrahedronMesh& simMesh, const DeformableVolumeAuxData& simState, const BVTetrahedronMesh& collisionMesh,
|
||||
PxU32 inTetId, const PxVec4& inTetBarycentric, PxU32& outTetId, PxVec4& outTetBarycentric, bool bClampToClosestPoint)
|
||||
{
|
||||
if (inTetId == 0xFFFFFFFF)
|
||||
{
|
||||
outTetId = 0xFFFFFFFF;
|
||||
outTetBarycentric = PxVec4(0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Map from CPU tet ID (corresponds to the ID in the BV4 mesh) to the GPU tet ID (corresponds to the ID in
|
||||
// the BV32 mesh)
|
||||
inTetId = collisionMesh.mGRB_faceRemapInverse[inTetId];
|
||||
|
||||
const PxU32 endIdx = simState.mTetsAccumulatedRemapColToSim[inTetId];
|
||||
const PxU32 startIdx = inTetId != 0 ? simState.mTetsAccumulatedRemapColToSim[inTetId - 1] : 0;
|
||||
|
||||
const PxU32* const tetRemapColToSim = simState.mTetsRemapColToSim;
|
||||
|
||||
typedef PxVec4T<unsigned int> uint4;
|
||||
|
||||
const uint4* const collInds = reinterpret_cast<const uint4*>(collisionMesh.mGRB_tetraIndices /*collisionMesh->mTetrahedrons*/);
|
||||
const uint4* const simInds = reinterpret_cast<const uint4*>(simMesh.getTetrahedrons());
|
||||
|
||||
const PxVec3* const collVerts = collisionMesh.mVertices;
|
||||
const PxVec3* const simVerts = simMesh.getVertices();
|
||||
|
||||
const uint4 ind = collInds[inTetId];
|
||||
|
||||
const PxVec3 point = collVerts[ind.x] * inTetBarycentric.x + collVerts[ind.y] * inTetBarycentric.y +
|
||||
collVerts[ind.z] * inTetBarycentric.z + collVerts[ind.w] * inTetBarycentric.w;
|
||||
|
||||
PxReal currDist = PX_MAX_F32;
|
||||
|
||||
for (PxU32 i = startIdx; i < endIdx; ++i)
|
||||
{
|
||||
const PxU32 simTet = tetRemapColToSim[i];
|
||||
|
||||
const uint4 simInd = simInds[simTet];
|
||||
|
||||
const PxVec3 a = simVerts[simInd.x];
|
||||
const PxVec3 b = simVerts[simInd.y];
|
||||
const PxVec3 c = simVerts[simInd.z];
|
||||
const PxVec3 d = simVerts[simInd.w];
|
||||
|
||||
const PxVec3 tmpClosest = closestPtPointTetrahedronWithInsideCheck(point, a, b, c, d);
|
||||
const PxVec3 v = point - tmpClosest;
|
||||
const PxReal tmpDist = v.dot(v);
|
||||
if (tmpDist < currDist)
|
||||
{
|
||||
PxVec4 tmpBarycentric;
|
||||
if (bClampToClosestPoint)
|
||||
PxComputeBarycentric(a, b, c, d, tmpClosest, tmpBarycentric);
|
||||
else
|
||||
PxComputeBarycentric(a, b, c, d, point, tmpBarycentric);
|
||||
|
||||
currDist = tmpDist;
|
||||
outTetId = simTet;
|
||||
outTetBarycentric = tmpBarycentric;
|
||||
|
||||
if (tmpDist < 1e-6f)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PX_ASSERT(outTetId != 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
PxVec4 addAxisToSimMeshBarycentric(const PxTetrahedronMesh& simMesh, const PxU32 simTetId, const PxVec4& simBary, const PxVec3& axis)
|
||||
{
|
||||
const PxVec3* simMeshVerts = simMesh.getVertices();
|
||||
PxVec3 tetVerts[4];
|
||||
if(simMesh.getTetrahedronMeshFlags() & PxTetrahedronMeshFlag::e16_BIT_INDICES)
|
||||
{
|
||||
const PxU16* indices = reinterpret_cast<const PxU16*>(simMesh.getTetrahedrons());
|
||||
tetVerts[0] = simMeshVerts[indices[simTetId*4 + 0]];
|
||||
tetVerts[1] = simMeshVerts[indices[simTetId*4 + 1]];
|
||||
tetVerts[2] = simMeshVerts[indices[simTetId*4 + 2]];
|
||||
tetVerts[3] = simMeshVerts[indices[simTetId*4 + 3]];
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxU32* indices = reinterpret_cast<const PxU32*>(simMesh.getTetrahedrons());
|
||||
tetVerts[0] = simMeshVerts[indices[simTetId*4 + 0]];
|
||||
tetVerts[1] = simMeshVerts[indices[simTetId*4 + 1]];
|
||||
tetVerts[2] = simMeshVerts[indices[simTetId*4 + 2]];
|
||||
tetVerts[3] = simMeshVerts[indices[simTetId*4 + 3]];
|
||||
}
|
||||
|
||||
const PxVec3 simPoint = tetVerts[0]*simBary.x + tetVerts[1]*simBary.y + tetVerts[2]*simBary.z + tetVerts[3]*simBary.w;
|
||||
const PxVec3 offsetPoint = simPoint + axis;
|
||||
|
||||
PxVec4 offsetBary;
|
||||
PxComputeBarycentric(tetVerts[0], tetVerts[1], tetVerts[2], tetVerts[3], offsetPoint, offsetBary);
|
||||
return offsetBary;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
48
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMeshUtils.h
vendored
Normal file
48
engine/third_party/physx/source/geomutils/src/mesh/GuTetrahedronMeshUtils.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
|
||||
#ifndef GU_TETRAHEDRONMESHUTILS_H
|
||||
#define GU_TETRAHEDRONMESHUTILS_H
|
||||
|
||||
#include <GuTetrahedronMesh.h>
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
|
||||
PX_PHYSX_COMMON_API
|
||||
void convertDeformableVolumeCollisionToSimMeshTets(const PxTetrahedronMesh& simMesh, const DeformableVolumeAuxData& simState, const BVTetrahedronMesh& collisionMesh,
|
||||
PxU32 inTetId, const PxVec4& inTetBarycentric, PxU32& outTetId, PxVec4& outTetBarycentric, bool bClampToClosestPoint = true);
|
||||
|
||||
PX_PHYSX_COMMON_API
|
||||
PxVec4 addAxisToSimMeshBarycentric(const PxTetrahedronMesh& simMesh, const PxU32 simTetId,
|
||||
const PxVec4& simBarycentric, const PxVec3& axis);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
144
engine/third_party/physx/source/geomutils/src/mesh/GuTriangle.h
vendored
Normal file
144
engine/third_party/physx/source/geomutils/src/mesh/GuTriangle.h
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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_TRIANGLE_H
|
||||
#define GU_TRIANGLE_H
|
||||
|
||||
#include "foundation/PxVec3.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
// PT: I'm taking back control of these files and re-introducing the "ICE" naming conventions:
|
||||
// - "Triangle" is for actual triangles (like the PxTriangle class)
|
||||
// - If it contains vertex indices, it's "IndexedTriangle".
|
||||
// - "v" is too ambiguous (it could be either an actual vertex or a vertex reference) so use "ref" instead.
|
||||
// Plus we sometimes reference edges, not vertices, so "v" is too restrictive.
|
||||
|
||||
template <class T>
|
||||
struct IndexedTriangleT : public PxUserAllocated
|
||||
{
|
||||
PX_INLINE IndexedTriangleT () {}
|
||||
PX_INLINE IndexedTriangleT (T a, T b, T c) { mRef[0] = a; mRef[1] = b; mRef[2] = c; }
|
||||
template <class TX>
|
||||
PX_INLINE IndexedTriangleT (const IndexedTriangleT <TX>& other) { mRef[0] = other[0]; mRef[1] = other[1]; mRef[2] = other[2]; }
|
||||
|
||||
PX_INLINE T& operator[](T i) { return mRef[i]; }
|
||||
PX_INLINE const T& operator[](T i) const { return mRef[i]; }
|
||||
|
||||
template<class TX>//any type of IndexedTriangleT <>, possibly with different T
|
||||
PX_INLINE IndexedTriangleT <T>& operator=(const IndexedTriangleT <TX>& i) { mRef[0]=i[0]; mRef[1]=i[1]; mRef[2]=i[2]; return *this; }
|
||||
|
||||
void flip()
|
||||
{
|
||||
PxSwap(mRef[1], mRef[2]);
|
||||
}
|
||||
|
||||
PX_INLINE bool contains(T id) const
|
||||
{
|
||||
return mRef[0] == id || mRef[1] == id || mRef[2] == id;
|
||||
}
|
||||
|
||||
PX_INLINE void center(const PxVec3* verts, PxVec3& center) const
|
||||
{
|
||||
const PxVec3& p0 = verts[mRef[0]];
|
||||
const PxVec3& p1 = verts[mRef[1]];
|
||||
const PxVec3& p2 = verts[mRef[2]];
|
||||
center = (p0+p1+p2)*0.33333333333333333333f;
|
||||
}
|
||||
|
||||
float area(const PxVec3* verts) const
|
||||
{
|
||||
const PxVec3& p0 = verts[mRef[0]];
|
||||
const PxVec3& p1 = verts[mRef[1]];
|
||||
const PxVec3& p2 = verts[mRef[2]];
|
||||
return ((p0-p1).cross(p0-p2)).magnitude() * 0.5f;
|
||||
}
|
||||
|
||||
PxU8 findEdge(T vref0, T vref1) const
|
||||
{
|
||||
if(mRef[0]==vref0 && mRef[1]==vref1) return 0;
|
||||
else if(mRef[0]==vref1 && mRef[1]==vref0) return 0;
|
||||
else if(mRef[0]==vref0 && mRef[2]==vref1) return 1;
|
||||
else if(mRef[0]==vref1 && mRef[2]==vref0) return 1;
|
||||
else if(mRef[1]==vref0 && mRef[2]==vref1) return 2;
|
||||
else if(mRef[1]==vref1 && mRef[2]==vref0) return 2;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
// counter clock wise order
|
||||
PxU8 findEdgeCCW(T vref0, T vref1) const
|
||||
{
|
||||
if(mRef[0]==vref0 && mRef[1]==vref1) return 0;
|
||||
else if(mRef[0]==vref1 && mRef[1]==vref0) return 0;
|
||||
else if(mRef[0]==vref0 && mRef[2]==vref1) return 2;
|
||||
else if(mRef[0]==vref1 && mRef[2]==vref0) return 2;
|
||||
else if(mRef[1]==vref0 && mRef[2]==vref1) return 1;
|
||||
else if(mRef[1]==vref1 && mRef[2]==vref0) return 1;
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
bool replaceVertex(T oldref, T newref)
|
||||
{
|
||||
if(mRef[0]==oldref) { mRef[0] = newref; return true; }
|
||||
else if(mRef[1]==oldref) { mRef[1] = newref; return true; }
|
||||
else if(mRef[2]==oldref) { mRef[2] = newref; return true; }
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDegenerate() const
|
||||
{
|
||||
if(mRef[0]==mRef[1]) return true;
|
||||
if(mRef[1]==mRef[2]) return true;
|
||||
if(mRef[2]==mRef[0]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
PX_INLINE void denormalizedNormal(const PxVec3* verts, PxVec3& normal) const
|
||||
{
|
||||
const PxVec3& p0 = verts[mRef[0]];
|
||||
const PxVec3& p1 = verts[mRef[1]];
|
||||
const PxVec3& p2 = verts[mRef[2]];
|
||||
normal = ((p2 - p1).cross(p0 - p1));
|
||||
}
|
||||
|
||||
T mRef[3]; //vertex indices
|
||||
};
|
||||
|
||||
typedef IndexedTriangleT<PxU32> IndexedTriangle32;
|
||||
typedef IndexedTriangleT<PxU16> IndexedTriangle16;
|
||||
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(IndexedTriangle32)==12);
|
||||
PX_COMPILE_TIME_ASSERT(sizeof(IndexedTriangle16)==6);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
239
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleCache.h
vendored
Normal file
239
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleCache.h
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// 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_TRIANGLE_CACHE_H
|
||||
#define GU_TRIANGLE_CACHE_H
|
||||
#include "foundation/PxHash.h"
|
||||
#include "foundation/PxUtilities.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
struct CachedEdge
|
||||
{
|
||||
protected:
|
||||
PxU32 mId0, mId1;
|
||||
public:
|
||||
CachedEdge(PxU32 i0, PxU32 i1)
|
||||
{
|
||||
mId0 = PxMin(i0, i1);
|
||||
mId1 = PxMax(i0, i1);
|
||||
}
|
||||
|
||||
CachedEdge()
|
||||
{
|
||||
}
|
||||
|
||||
PxU32 getId0() const { return mId0; }
|
||||
PxU32 getId1() const { return mId1; }
|
||||
|
||||
bool operator == (const CachedEdge& other) const
|
||||
{
|
||||
return mId0 == other.mId0 && mId1 == other.mId1;
|
||||
}
|
||||
|
||||
PxU32 getHashCode() const
|
||||
{
|
||||
return PxComputeHash(mId0 << 16 | mId1);
|
||||
}
|
||||
};
|
||||
|
||||
struct CachedVertex
|
||||
{
|
||||
private:
|
||||
PxU32 mId;
|
||||
public:
|
||||
CachedVertex(PxU32 id)
|
||||
{
|
||||
mId = id;
|
||||
}
|
||||
|
||||
CachedVertex()
|
||||
{
|
||||
}
|
||||
|
||||
PxU32 getId() const { return mId; }
|
||||
|
||||
PxU32 getHashCode() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
bool operator == (const CachedVertex& other) const
|
||||
{
|
||||
return mId == other.mId;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Elem, PxU32 MaxCount>
|
||||
struct CacheMap
|
||||
{
|
||||
PX_COMPILE_TIME_ASSERT(MaxCount < 0xFF);
|
||||
Elem mCache[MaxCount];
|
||||
PxU8 mNextInd[MaxCount];
|
||||
PxU8 mIndex[MaxCount];
|
||||
PxU32 mSize;
|
||||
|
||||
CacheMap() : mSize(0)
|
||||
{
|
||||
for(PxU32 a = 0; a < MaxCount; ++a)
|
||||
{
|
||||
mIndex[a] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
bool addData(const Elem& data)
|
||||
{
|
||||
if(mSize == MaxCount)
|
||||
return false;
|
||||
|
||||
const PxU8 hash = PxU8(data.getHashCode() % MaxCount);
|
||||
|
||||
PxU8 index = hash;
|
||||
PxU8 nextInd = mIndex[hash];
|
||||
while(nextInd != 0xFF)
|
||||
{
|
||||
index = nextInd;
|
||||
if(mCache[index] == data)
|
||||
return false;
|
||||
nextInd = mNextInd[nextInd];
|
||||
}
|
||||
|
||||
if(mIndex[hash] == 0xFF)
|
||||
{
|
||||
mIndex[hash] = PxTo8(mSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
mNextInd[index] = PxTo8(mSize);
|
||||
}
|
||||
mNextInd[mSize] = 0xFF;
|
||||
mCache[mSize++] = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool contains(const Elem& data) const
|
||||
{
|
||||
PxU32 hash = (data.getHashCode() % MaxCount);
|
||||
PxU8 index = mIndex[hash];
|
||||
|
||||
while(index != 0xFF)
|
||||
{
|
||||
if(mCache[index] == data)
|
||||
return true;
|
||||
index = mNextInd[index];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const Elem* get(const Elem& data) const
|
||||
{
|
||||
PxU32 hash = (data.getHashCode() % MaxCount);
|
||||
PxU8 index = mIndex[hash];
|
||||
|
||||
while(index != 0xFF)
|
||||
{
|
||||
if(mCache[index] == data)
|
||||
return &mCache[index];
|
||||
index = mNextInd[index];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
template <PxU32 MaxTriangles>
|
||||
struct TriangleCache
|
||||
{
|
||||
PxVec3 mVertices[3*MaxTriangles];
|
||||
PxU32 mIndices[3*MaxTriangles];
|
||||
PxU32 mTriangleIndex[MaxTriangles];
|
||||
PxU8 mEdgeFlags[MaxTriangles];
|
||||
PxU32 mNumTriangles;
|
||||
|
||||
TriangleCache() : mNumTriangles(0)
|
||||
{
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool isEmpty() const { return mNumTriangles == 0; }
|
||||
PX_FORCE_INLINE bool isFull() const { return mNumTriangles == MaxTriangles; }
|
||||
PX_FORCE_INLINE void reset() { mNumTriangles = 0; }
|
||||
|
||||
void addTriangle(const PxVec3* verts, const PxU32* indices, PxU32 triangleIndex, PxU8 edgeFlag)
|
||||
{
|
||||
PX_ASSERT(mNumTriangles < MaxTriangles);
|
||||
PxU32 triInd = mNumTriangles++;
|
||||
PxU32 triIndMul3 = triInd*3;
|
||||
mVertices[triIndMul3] = verts[0];
|
||||
mVertices[triIndMul3+1] = verts[1];
|
||||
mVertices[triIndMul3+2] = verts[2];
|
||||
mIndices[triIndMul3] = indices[0];
|
||||
mIndices[triIndMul3+1] = indices[1];
|
||||
mIndices[triIndMul3+2] = indices[2];
|
||||
mTriangleIndex[triInd] = triangleIndex;
|
||||
mEdgeFlags[triInd] = edgeFlag;
|
||||
}
|
||||
};
|
||||
|
||||
template <PxU32 MaxTetrahedrons>
|
||||
struct TetrahedronCache
|
||||
{
|
||||
PxVec3 mVertices[4 * MaxTetrahedrons];
|
||||
PxU32 mTetVertIndices[4 * MaxTetrahedrons];
|
||||
PxU32 mTetrahedronIndices[MaxTetrahedrons];
|
||||
PxU32 mNumTetrahedrons;
|
||||
|
||||
TetrahedronCache() : mNumTetrahedrons(0)
|
||||
{
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE bool isEmpty() const { return mNumTetrahedrons == 0; }
|
||||
PX_FORCE_INLINE bool isFull() const { return mNumTetrahedrons == MaxTetrahedrons; }
|
||||
PX_FORCE_INLINE void reset() { mNumTetrahedrons = 0; }
|
||||
|
||||
void addTetrahedrons(const PxVec3* verts, const PxU32* indices, PxU32 tetIndex)
|
||||
{
|
||||
PX_ASSERT(mNumTetrahedrons < MaxTetrahedrons);
|
||||
PxU32 tetInd = mNumTetrahedrons++;
|
||||
PxU32 tetIndMul4 = tetInd * 4;
|
||||
mVertices[tetIndMul4] = verts[0];
|
||||
mVertices[tetIndMul4 + 1] = verts[1];
|
||||
mVertices[tetIndMul4 + 2] = verts[2];
|
||||
mVertices[tetIndMul4 + 3] = verts[3];
|
||||
mTetVertIndices[tetIndMul4] = indices[0];
|
||||
mTetVertIndices[tetIndMul4 + 1] = indices[1];
|
||||
mTetVertIndices[tetIndMul4 + 2] = indices[2];
|
||||
mTetVertIndices[tetIndMul4 + 3] = indices[3];
|
||||
mTetrahedronIndices[tetInd] = tetIndex;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
341
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMesh.cpp
vendored
Normal file
341
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMesh.cpp
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
// 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 "GuMidphaseInterface.h"
|
||||
#include "GuMeshFactory.h"
|
||||
#include "GuConvexEdgeFlags.h"
|
||||
#include "GuEdgeList.h"
|
||||
#include "geometry/PxGeometryInternal.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static PxConcreteType::Enum gTable[] = { PxConcreteType::eTRIANGLE_MESH_BVH33,
|
||||
PxConcreteType::eTRIANGLE_MESH_BVH34
|
||||
};
|
||||
|
||||
TriangleMesh::TriangleMesh(MeshFactory* factory, TriangleMeshData& d) :
|
||||
PxTriangleMesh (PxType(gTable[d.mType]), PxBaseFlag::eOWNS_MEMORY | PxBaseFlag::eIS_RELEASABLE),
|
||||
mNbVertices (d.mNbVertices),
|
||||
mNbTriangles (d.mNbTriangles),
|
||||
mVertices (d.mVertices),
|
||||
mTriangles (d.mTriangles),
|
||||
mAABB (d.mAABB),
|
||||
mExtraTrigData (d.mExtraTrigData),
|
||||
mGeomEpsilon (d.mGeomEpsilon),
|
||||
mFlags (d.mFlags),
|
||||
mMaterialIndices (d.mMaterialIndices),
|
||||
mFaceRemap (d.mFaceRemap),
|
||||
mAdjacencies (d.mAdjacencies),
|
||||
mMeshFactory (factory),
|
||||
mEdgeList (NULL),
|
||||
mMass (d.mMass),
|
||||
mInertia (d.mInertia),
|
||||
mLocalCenterOfMass (d.mLocalCenterOfMass),
|
||||
mGRB_triIndices (d.mGRB_primIndices),
|
||||
mGRB_triAdjacencies (d.mGRB_primAdjacencies),
|
||||
mGRB_faceRemap (d.mGRB_faceRemap),
|
||||
mGRB_faceRemapInverse (d.mGRB_faceRemapInverse),
|
||||
mGRB_BV32Tree (d.mGRB_BV32Tree),
|
||||
mSdfData (d.mSdfData),
|
||||
mAccumulatedTrianglesRef (d.mAccumulatedTrianglesRef),
|
||||
mTrianglesReferences (d.mTrianglesReferences),
|
||||
mNbTrianglesReferences (d.mNbTrianglesReferences)
|
||||
{
|
||||
// this constructor takes ownership of memory from the data object
|
||||
d.mVertices = NULL;
|
||||
d.mTriangles = NULL;
|
||||
d.mExtraTrigData = NULL;
|
||||
d.mFaceRemap = NULL;
|
||||
d.mAdjacencies = NULL;
|
||||
d.mMaterialIndices = NULL;
|
||||
|
||||
d.mGRB_primIndices = NULL;
|
||||
|
||||
d.mGRB_primAdjacencies = NULL;
|
||||
d.mGRB_faceRemap = NULL;
|
||||
d.mGRB_faceRemapInverse = NULL;
|
||||
d.mGRB_BV32Tree = NULL;
|
||||
|
||||
d.mSdfData.mSdf = NULL;
|
||||
d.mSdfData.mSubgridStartSlots = NULL;
|
||||
d.mSdfData.mSubgridSdf = NULL;
|
||||
|
||||
d.mAccumulatedTrianglesRef = NULL;
|
||||
d.mTrianglesReferences = NULL;
|
||||
|
||||
// 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(TriangleMesh, mExtraTrigData)>=PX_OFFSET_OF(TriangleMesh, mAABB)+4);
|
||||
}
|
||||
|
||||
// PT: temporary for Kit
|
||||
TriangleMesh::TriangleMesh(const PxTriangleMeshInternalData& data) :
|
||||
PxTriangleMesh (PxConcreteType::eTRIANGLE_MESH_BVH34, PxBaseFlags(0)),
|
||||
mNbVertices (data.mNbVertices),
|
||||
mNbTriangles (data.mNbTriangles),
|
||||
mVertices (data.mVertices),
|
||||
mTriangles (data.mTriangles),
|
||||
mExtraTrigData (NULL),
|
||||
mGeomEpsilon (data.mGeomEpsilon),
|
||||
mFlags (data.mFlags),
|
||||
mMaterialIndices (NULL),
|
||||
mFaceRemap (data.mFaceRemap),
|
||||
mAdjacencies (NULL),
|
||||
mMeshFactory (NULL),
|
||||
mEdgeList (NULL),
|
||||
mGRB_triIndices (NULL),
|
||||
mGRB_triAdjacencies (NULL),
|
||||
mGRB_faceRemap (NULL),
|
||||
mGRB_faceRemapInverse (NULL),
|
||||
mGRB_BV32Tree (NULL),
|
||||
mAccumulatedTrianglesRef(NULL),
|
||||
mTrianglesReferences (NULL),
|
||||
mNbTrianglesReferences (0)
|
||||
{
|
||||
mAABB.mCenter = data.mAABB_Center;
|
||||
mAABB.mExtents = data.mAABB_Extents;
|
||||
}
|
||||
//~ PT: temporary for Kit
|
||||
|
||||
TriangleMesh::~TriangleMesh()
|
||||
{
|
||||
if(getBaseFlags() & PxBaseFlag::eOWNS_MEMORY)
|
||||
{
|
||||
PX_FREE(mExtraTrigData);
|
||||
PX_FREE(mFaceRemap);
|
||||
PX_FREE(mAdjacencies);
|
||||
PX_FREE(mMaterialIndices);
|
||||
PX_FREE(mTriangles);
|
||||
PX_FREE(mVertices);
|
||||
|
||||
PX_FREE(mGRB_triIndices);
|
||||
PX_FREE(mGRB_triAdjacencies);
|
||||
PX_FREE(mGRB_faceRemap);
|
||||
PX_FREE(mGRB_faceRemapInverse);
|
||||
PX_DELETE(mGRB_BV32Tree);
|
||||
|
||||
PX_FREE(mAccumulatedTrianglesRef);
|
||||
PX_FREE(mTrianglesReferences);
|
||||
}
|
||||
|
||||
PX_DELETE(mEdgeList);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// PT: used to be automatic but making it manual saves bytes in the internal mesh
|
||||
|
||||
void TriangleMesh::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
//PX_DEFINE_DYNAMIC_ARRAY(TriangleMesh, mVertices, PxField::eVEC3, mNbVertices, Ps::PxFieldFlag::eSERIALIZE),
|
||||
if(mVertices)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mVertices, mNbVertices * sizeof(PxVec3));
|
||||
}
|
||||
|
||||
if(mTriangles)
|
||||
{
|
||||
const PxU32 triangleSize = mFlags & PxTriangleMeshFlag::e16_BIT_INDICES ? sizeof(PxU16) : sizeof(PxU32);
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mTriangles, mNbTriangles * 3 * triangleSize);
|
||||
}
|
||||
|
||||
//PX_DEFINE_DYNAMIC_ARRAY(TriangleMesh, mExtraTrigData, PxField::eBYTE, mNbTriangles, Ps::PxFieldFlag::eSERIALIZE),
|
||||
if(mExtraTrigData)
|
||||
{
|
||||
// PT: it might not be needed to 16-byte align this array of PxU8....
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mExtraTrigData, mNbTriangles * sizeof(PxU8));
|
||||
}
|
||||
|
||||
if(mMaterialIndices)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mMaterialIndices, mNbTriangles * sizeof(PxU16));
|
||||
}
|
||||
|
||||
if(mFaceRemap)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mFaceRemap, mNbTriangles * sizeof(PxU32));
|
||||
}
|
||||
|
||||
if(mAdjacencies)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mAdjacencies, mNbTriangles * sizeof(PxU32) * 3);
|
||||
}
|
||||
|
||||
if(mGRB_triIndices)
|
||||
{
|
||||
const PxU32 triangleSize = mFlags & PxTriangleMeshFlag::e16_BIT_INDICES ? sizeof(PxU16) : sizeof(PxU32);
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mGRB_triIndices, mNbTriangles * 3 * triangleSize);
|
||||
}
|
||||
|
||||
if(mGRB_triAdjacencies)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mGRB_triAdjacencies, mNbTriangles * sizeof(PxU32) * 4);
|
||||
}
|
||||
|
||||
if(mGRB_faceRemap)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mGRB_faceRemap, mNbTriangles * sizeof(PxU32));
|
||||
}
|
||||
|
||||
if(mGRB_faceRemapInverse)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mGRB_faceRemapInverse, mNbTriangles * sizeof(PxU32));
|
||||
}
|
||||
|
||||
if(mGRB_BV32Tree)
|
||||
{
|
||||
stream.alignData(PX_SERIAL_ALIGN);
|
||||
stream.writeData(mGRB_BV32Tree, sizeof(BV32Tree));
|
||||
mGRB_BV32Tree->exportExtraData(stream);
|
||||
}
|
||||
|
||||
mSdfData.exportExtraData(stream);
|
||||
}
|
||||
|
||||
void TriangleMesh::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
// PT: vertices are followed by indices, so it will be safe to V4Load vertices from a deserialized binary file
|
||||
if(mVertices)
|
||||
mVertices = context.readExtraData<PxVec3, PX_SERIAL_ALIGN>(mNbVertices);
|
||||
|
||||
if(mTriangles)
|
||||
{
|
||||
if(mFlags & PxTriangleMeshFlag::e16_BIT_INDICES)
|
||||
mTriangles = context.readExtraData<PxU16, PX_SERIAL_ALIGN>(3*mNbTriangles);
|
||||
else
|
||||
mTriangles = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(3*mNbTriangles);
|
||||
}
|
||||
|
||||
if(mExtraTrigData)
|
||||
mExtraTrigData = context.readExtraData<PxU8, PX_SERIAL_ALIGN>(mNbTriangles);
|
||||
|
||||
if(mMaterialIndices)
|
||||
mMaterialIndices = context.readExtraData<PxU16, PX_SERIAL_ALIGN>(mNbTriangles);
|
||||
|
||||
if(mFaceRemap)
|
||||
mFaceRemap = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(mNbTriangles);
|
||||
|
||||
if(mAdjacencies)
|
||||
mAdjacencies = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(3*mNbTriangles);
|
||||
|
||||
if(mGRB_triIndices)
|
||||
{
|
||||
if(mFlags & PxTriangleMeshFlag::e16_BIT_INDICES)
|
||||
mGRB_triIndices = context.readExtraData<PxU16, PX_SERIAL_ALIGN>(3 * mNbTriangles);
|
||||
else
|
||||
mGRB_triIndices = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(3 * mNbTriangles);
|
||||
}
|
||||
|
||||
if(mGRB_triAdjacencies)
|
||||
{
|
||||
mGRB_triAdjacencies = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(4 * mNbTriangles);
|
||||
}
|
||||
|
||||
if(mGRB_faceRemap)
|
||||
{
|
||||
mGRB_faceRemap = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(mNbTriangles);
|
||||
}
|
||||
|
||||
if(mGRB_faceRemapInverse)
|
||||
{
|
||||
mGRB_faceRemapInverse = context.readExtraData<PxU32, PX_SERIAL_ALIGN>(mNbTriangles);
|
||||
}
|
||||
|
||||
if(mGRB_BV32Tree)
|
||||
{
|
||||
mGRB_BV32Tree = context.readExtraData<BV32Tree, PX_SERIAL_ALIGN>();
|
||||
PX_PLACEMENT_NEW(mGRB_BV32Tree, BV32Tree(PxEmpty));
|
||||
mGRB_BV32Tree->importExtraData(context);
|
||||
}
|
||||
|
||||
mSdfData.importExtraData(context);
|
||||
}
|
||||
|
||||
void TriangleMesh::onRefCountZero()
|
||||
{
|
||||
::onRefCountZero(this, mMeshFactory, false, "PxTriangleMesh::release: double deletion detected!");
|
||||
}
|
||||
|
||||
void TriangleMesh::release()
|
||||
{
|
||||
Cm::RefCountable_decRefCount(*this);
|
||||
}
|
||||
|
||||
PxVec3* TriangleMesh::getVerticesForModification()
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxTriangleMesh::getVerticesForModification() is not supported for this type of meshes.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PxBounds3 TriangleMesh::refitBVH()
|
||||
{
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "PxTriangleMesh::refitBVH() is not supported for this type of meshes.");
|
||||
|
||||
return PxBounds3(mAABB.getMin(), mAABB.getMax());
|
||||
}
|
||||
|
||||
void TriangleMesh::setAllEdgesActive()
|
||||
{
|
||||
if(mExtraTrigData)
|
||||
{
|
||||
const PxU32 nbTris = mNbTriangles;
|
||||
for(PxU32 i=0; i<nbTris; i++)
|
||||
mExtraTrigData[i] |= ETD_CONVEX_EDGE_ALL;
|
||||
}
|
||||
}
|
||||
|
||||
const EdgeList* TriangleMesh::requestEdgeList() const
|
||||
{
|
||||
if(!mEdgeList)
|
||||
{
|
||||
EDGELISTCREATE create;
|
||||
create.NbFaces = mNbTriangles;
|
||||
create.Verts = mVertices;
|
||||
if(has16BitIndices())
|
||||
create.WFaces = reinterpret_cast<const PxU16*>(mTriangles);
|
||||
else
|
||||
create.DFaces = reinterpret_cast<const PxU32*>(mTriangles);
|
||||
|
||||
mEdgeList = PX_NEW(EdgeList);
|
||||
mEdgeList->init(create);
|
||||
}
|
||||
return mEdgeList;
|
||||
}
|
||||
346
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMesh.h
vendored
Normal file
346
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMesh.h
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
// 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_TRIANGLEMESH_H
|
||||
#define GU_TRIANGLEMESH_H
|
||||
|
||||
#include "foundation/PxIO.h"
|
||||
#include "geometry/PxTriangle.h"
|
||||
#include "geometry/PxTriangleMeshGeometry.h"
|
||||
#include "geometry/PxSimpleTriangleMesh.h"
|
||||
#include "geometry/PxTriangleMesh.h"
|
||||
|
||||
#include "GuMeshData.h"
|
||||
#include "GuCenterExtents.h"
|
||||
#include "CmScaling.h"
|
||||
#include "CmRefCountable.h"
|
||||
#include "common/PxRenderOutput.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
class PxMeshScale;
|
||||
struct PxTriangleMeshInternalData;
|
||||
|
||||
namespace Gu
|
||||
{
|
||||
PX_FORCE_INLINE void getVertexRefs(PxU32 triangleIndex, PxU32& vref0, PxU32& vref1, PxU32& vref2, const void* indices, bool has16BitIndices)
|
||||
{
|
||||
if(has16BitIndices)
|
||||
{
|
||||
const PxU16* inds = reinterpret_cast<const PxU16*>(indices) + triangleIndex*3;
|
||||
vref0 = inds[0];
|
||||
vref1 = inds[1];
|
||||
vref2 = inds[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
const PxU32* inds = reinterpret_cast<const PxU32*>(indices) + triangleIndex*3;
|
||||
vref0 = inds[0];
|
||||
vref1 = inds[1];
|
||||
vref2 = inds[2];
|
||||
}
|
||||
}
|
||||
|
||||
class MeshFactory;
|
||||
#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 EdgeList;
|
||||
|
||||
class TriangleMesh : public PxTriangleMesh, public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
|
||||
// PX_SERIALIZATION
|
||||
TriangleMesh(PxBaseFlags baseFlags) : PxTriangleMesh(baseFlags), mSdfData(PxEmpty) {}
|
||||
|
||||
void preExportDataReset() { Cm::RefCountable_preExportDataReset(*this); }
|
||||
virtual void exportExtraData(PxSerializationContext& context);
|
||||
void importExtraData(PxDeserializationContext& context);
|
||||
virtual void release();
|
||||
virtual void requiresObjects(PxProcessPxBaseCallback&){}
|
||||
//~PX_SERIALIZATION
|
||||
TriangleMesh(MeshFactory* factory, TriangleMeshData& data);
|
||||
TriangleMesh(const PxTriangleMeshInternalData& data);
|
||||
virtual ~TriangleMesh();
|
||||
|
||||
// PxBase
|
||||
virtual void onRefCountZero();
|
||||
//~PxBase
|
||||
|
||||
// PxRefCounted
|
||||
virtual void acquireReference() { Cm::RefCountable_incRefCount(*this); }
|
||||
virtual PxU32 getReferenceCount() const { return Cm::RefCountable_getRefCount(*this); }
|
||||
//~PxRefCounted
|
||||
|
||||
// PxTriangleMesh
|
||||
virtual PxU32 getNbVertices() const { return mNbVertices;}
|
||||
virtual const PxVec3* getVertices() const { return mVertices; }
|
||||
|
||||
virtual PxVec3* getVerticesForModification();
|
||||
virtual PxBounds3 refitBVH();
|
||||
virtual PxU32 getNbTriangles() const { return mNbTriangles; }
|
||||
virtual const void* getTriangles() const { return mTriangles; }
|
||||
virtual PxTriangleMeshFlags getTriangleMeshFlags() const { return PxTriangleMeshFlags(mFlags); }
|
||||
virtual const PxU32* getTrianglesRemap() const { return mFaceRemap; }
|
||||
virtual void setPreferSDFProjection(bool preferProjection)
|
||||
{
|
||||
if (preferProjection)
|
||||
mFlags &= PxU8(~PxTriangleMeshFlag::ePREFER_NO_SDF_PROJ);
|
||||
else
|
||||
mFlags |= PxTriangleMeshFlag::ePREFER_NO_SDF_PROJ;
|
||||
}
|
||||
|
||||
virtual bool getPreferSDFProjection() const { return !(mFlags & PxTriangleMeshFlag::ePREFER_NO_SDF_PROJ); }
|
||||
|
||||
virtual PxMaterialTableIndex getTriangleMaterialIndex(PxTriangleID triangleIndex) const
|
||||
{
|
||||
return hasPerTriangleMaterials() ? getMaterials()[triangleIndex] : PxMaterialTableIndex(0xffff);
|
||||
}
|
||||
|
||||
virtual PxBounds3 getLocalBounds() const
|
||||
{
|
||||
PX_ASSERT(mAABB.isValid());
|
||||
return PxBounds3::centerExtents(mAABB.mCenter, mAABB.mExtents);
|
||||
}
|
||||
|
||||
virtual const PxReal* getSDF() const
|
||||
{
|
||||
return mSdfData.mSdf;
|
||||
}
|
||||
|
||||
virtual void getSDFDimensions(PxU32& numX, PxU32& numY, PxU32& numZ) const
|
||||
{
|
||||
if(mSdfData.mSdf)
|
||||
{
|
||||
numX = mSdfData.mDims.x;
|
||||
numY = mSdfData.mDims.y;
|
||||
numZ = mSdfData.mDims.z;
|
||||
}
|
||||
else
|
||||
numX = numY = numZ = 0;
|
||||
}
|
||||
|
||||
virtual void getMassInformation(PxReal& mass, PxMat33& localInertia, PxVec3& localCenterOfMass) const
|
||||
{
|
||||
mass = mMass; localInertia = mInertia; localCenterOfMass = mLocalCenterOfMass;
|
||||
}
|
||||
|
||||
//~PxTriangleMesh
|
||||
|
||||
virtual bool getInternalData(PxTriangleMeshInternalData&, bool) const { return false; }
|
||||
|
||||
// PT: this one is just to prevent instancing Gu::TriangleMesh.
|
||||
// But you should use PxBase::getConcreteType() instead to avoid the virtual call.
|
||||
virtual PxMeshMidPhase::Enum getMidphaseID() const = 0;
|
||||
|
||||
PX_FORCE_INLINE const PxU32* getFaceRemap() const { return mFaceRemap; }
|
||||
PX_FORCE_INLINE bool has16BitIndices() const { return (mFlags & PxMeshFlag::e16_BIT_INDICES) ? true : false; }
|
||||
PX_FORCE_INLINE bool hasPerTriangleMaterials() const { return mMaterialIndices != NULL; }
|
||||
PX_FORCE_INLINE PxU32 getNbVerticesFast() const { return mNbVertices; }
|
||||
PX_FORCE_INLINE PxU32 getNbTrianglesFast() const { return mNbTriangles; }
|
||||
PX_FORCE_INLINE const void* getTrianglesFast() const { return mTriangles; }
|
||||
PX_FORCE_INLINE const PxVec3* getVerticesFast() const { return mVertices; }
|
||||
PX_FORCE_INLINE const PxU32* getAdjacencies() const { return mAdjacencies; }
|
||||
PX_FORCE_INLINE PxReal getGeomEpsilon() const { return mGeomEpsilon; }
|
||||
PX_FORCE_INLINE const CenterExtents& getLocalBoundsFast() const { return mAABB; }
|
||||
PX_FORCE_INLINE const PxU16* getMaterials() const { return mMaterialIndices; }
|
||||
PX_FORCE_INLINE const PxU8* getExtraTrigData() const { return mExtraTrigData; }
|
||||
|
||||
PX_FORCE_INLINE const PxU32* getAccumulatedTriangleRef() const { return mAccumulatedTrianglesRef; }
|
||||
PX_FORCE_INLINE const PxU32* getTriangleReferences() const { return mTrianglesReferences; }
|
||||
PX_FORCE_INLINE PxU32 getNbTriangleReferences() const { return mNbTrianglesReferences; }
|
||||
|
||||
PX_FORCE_INLINE const CenterExtentsPadded& getPaddedBounds() const
|
||||
{
|
||||
// PT: see compile-time assert in cpp
|
||||
return static_cast<const CenterExtentsPadded&>(mAABB);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void computeWorldTriangle(
|
||||
PxTriangle& worldTri, PxTriangleID triangleIndex, const PxMat34& worldMatrix, bool flipNormal = false,
|
||||
PxU32* PX_RESTRICT vertexIndices=NULL, PxU32* PX_RESTRICT adjacencyIndices=NULL) const;
|
||||
PX_FORCE_INLINE void getLocalTriangle(PxTriangle& localTri, PxTriangleID triangleIndex, bool flipNormal = false) const;
|
||||
|
||||
void setMeshFactory(MeshFactory* factory) { mMeshFactory = factory; }
|
||||
|
||||
// SDF methods
|
||||
PX_FORCE_INLINE const SDF& getSdfDataFast() const { return mSdfData; }
|
||||
//~SDF methods
|
||||
|
||||
PX_FORCE_INLINE PxReal getMass() const { return mMass; }
|
||||
|
||||
// PT: for debug viz
|
||||
PX_PHYSX_COMMON_API const Gu::EdgeList* requestEdgeList() const;
|
||||
|
||||
protected:
|
||||
PxU32 mNbVertices;
|
||||
PxU32 mNbTriangles;
|
||||
PxVec3* mVertices;
|
||||
void* mTriangles; //!< 16 (<= 0xffff #vertices) or 32 bit trig indices (mNbTriangles * 3)
|
||||
// 16 bytes block
|
||||
|
||||
// PT: WARNING: bounds must be followed by at least 32bits of data for safe SIMD loading
|
||||
CenterExtents mAABB;
|
||||
PxU8* mExtraTrigData; //one per trig
|
||||
PxReal mGeomEpsilon; //!< see comments in cooking code referencing this variable
|
||||
// 16 bytes block
|
||||
/*
|
||||
low 3 bits (mask: 7) are the edge flags:
|
||||
b001 = 1 = ignore edge 0 = edge v0-->v1
|
||||
b010 = 2 = ignore edge 1 = edge v0-->v2
|
||||
b100 = 4 = ignore edge 2 = edge v1-->v2
|
||||
*/
|
||||
PxU8 mFlags; //!< Flag whether indices are 16 or 32 bits wide
|
||||
//!< Flag whether triangle adajacencies are build
|
||||
PxU16* mMaterialIndices; //!< the size of the array is numTriangles.
|
||||
PxU32* mFaceRemap; //!< new faces to old faces mapping (after cleaning, etc). Usage: old = faceRemap[new]
|
||||
PxU32* mAdjacencies; //!< Adjacency information for each face - 3 adjacent faces
|
||||
//!< Set to 0xFFFFffff if no adjacent face
|
||||
|
||||
MeshFactory* mMeshFactory; // PT: changed to pointer for serialization
|
||||
mutable Gu::EdgeList* mEdgeList; // PT: for debug viz
|
||||
|
||||
|
||||
PxReal mMass; //this is mass assuming a unit density that can be scaled by instances!
|
||||
PxMat33 mInertia; //in local space of mesh!
|
||||
PxVec3 mLocalCenterOfMass; //local space com
|
||||
public:
|
||||
|
||||
// GRB data -------------------------
|
||||
void* mGRB_triIndices; //!< GRB: GPU-friendly tri indices
|
||||
|
||||
// TODO avoroshilov: cooking - adjacency info - duplicated, remove it and use 'mAdjacencies' and 'mExtraTrigData' see GuTriangleMesh.cpp:325
|
||||
void* mGRB_triAdjacencies; //!< GRB: adjacency data, with BOUNDARY and NONCONVEX flags (flags replace adj indices where applicable)
|
||||
|
||||
PxU32* mGRB_faceRemap; //!< GRB : gpu to cpu triangle indice remap
|
||||
PxU32* mGRB_faceRemapInverse;
|
||||
Gu::BV32Tree* mGRB_BV32Tree; //!< GRB: BV32 tree
|
||||
// End of GRB data ------------------
|
||||
|
||||
// SDF data -------------------------
|
||||
SDF mSdfData;
|
||||
// End of SDF data ------------------
|
||||
|
||||
void setAllEdgesActive();
|
||||
//Vertex mapping data
|
||||
PxU32* mAccumulatedTrianglesRef;//runsum
|
||||
PxU32* mTrianglesReferences;
|
||||
PxU32 mNbTrianglesReferences;
|
||||
//End of vertex mapping data
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
PX_FORCE_INLINE void Gu::TriangleMesh::computeWorldTriangle(PxTriangle& worldTri, PxTriangleID triangleIndex, const PxMat34& worldMatrix, bool flipNormal,
|
||||
PxU32* PX_RESTRICT vertexIndices, PxU32* PX_RESTRICT adjacencyIndices) const
|
||||
{
|
||||
PxU32 vref0, vref1, vref2;
|
||||
getVertexRefs(triangleIndex, vref0, vref1, vref2, mTriangles, has16BitIndices());
|
||||
|
||||
if(flipNormal)
|
||||
PxSwap<PxU32>(vref1, vref2);
|
||||
|
||||
const PxVec3* PX_RESTRICT vertices = getVerticesFast();
|
||||
worldTri.verts[0] = worldMatrix.transform(vertices[vref0]);
|
||||
worldTri.verts[1] = worldMatrix.transform(vertices[vref1]);
|
||||
worldTri.verts[2] = worldMatrix.transform(vertices[vref2]);
|
||||
|
||||
if(vertexIndices)
|
||||
{
|
||||
vertexIndices[0] = vref0;
|
||||
vertexIndices[1] = vref1;
|
||||
vertexIndices[2] = vref2;
|
||||
}
|
||||
|
||||
if(adjacencyIndices)
|
||||
{
|
||||
if(mAdjacencies)
|
||||
{
|
||||
// PT: TODO: is this correct?
|
||||
adjacencyIndices[0] = flipNormal ? mAdjacencies[triangleIndex*3 + 2] : mAdjacencies[triangleIndex*3 + 0];
|
||||
adjacencyIndices[1] = mAdjacencies[triangleIndex*3 + 1];
|
||||
adjacencyIndices[2] = flipNormal ? mAdjacencies[triangleIndex*3 + 0] : mAdjacencies[triangleIndex*3 + 2];
|
||||
}
|
||||
else
|
||||
{
|
||||
adjacencyIndices[0] = 0xffffffff;
|
||||
adjacencyIndices[1] = 0xffffffff;
|
||||
adjacencyIndices[2] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void Gu::TriangleMesh::getLocalTriangle(PxTriangle& localTri, PxTriangleID triangleIndex, bool flipNormal) const
|
||||
{
|
||||
PxU32 vref0, vref1, vref2;
|
||||
getVertexRefs(triangleIndex, vref0, vref1, vref2, mTriangles, has16BitIndices());
|
||||
|
||||
if(flipNormal)
|
||||
PxSwap<PxU32>(vref1, vref2);
|
||||
|
||||
const PxVec3* PX_RESTRICT vertices = getVerticesFast();
|
||||
localTri.verts[0] = vertices[vref0];
|
||||
localTri.verts[1] = vertices[vref1];
|
||||
localTri.verts[2] = vertices[vref2];
|
||||
}
|
||||
|
||||
PX_INLINE float computeSweepData(const PxTriangleMeshGeometry& triMeshGeom, /*const Cm::FastVertex2ShapeScaling& scaling,*/ PxVec3& sweepOrigin, PxVec3& sweepExtents, PxVec3& sweepDir, float distance)
|
||||
{
|
||||
PX_ASSERT(!Cm::isEmpty(sweepOrigin, sweepExtents));
|
||||
|
||||
const PxVec3 endPt = sweepOrigin + sweepDir*distance;
|
||||
PX_ASSERT(!Cm::isEmpty(endPt, sweepExtents));
|
||||
|
||||
const Cm::FastVertex2ShapeScaling meshScaling(triMeshGeom.scale.getInverse()); // shape to vertex transform
|
||||
|
||||
const PxMat33& vertex2ShapeSkew = meshScaling.getVertex2ShapeSkew();
|
||||
|
||||
const PxVec3 originBoundsCenter = vertex2ShapeSkew * sweepOrigin;
|
||||
const PxVec3 originBoundsExtents = Cm::basisExtent(vertex2ShapeSkew.column0, vertex2ShapeSkew.column1, vertex2ShapeSkew.column2, sweepExtents);
|
||||
|
||||
sweepOrigin = originBoundsCenter;
|
||||
sweepExtents = originBoundsExtents;
|
||||
sweepDir = (vertex2ShapeSkew * endPt) - originBoundsCenter;
|
||||
return sweepDir.normalizeSafe();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const Gu::TriangleMesh* _getMeshData(const PxTriangleMeshGeometry& meshGeom)
|
||||
{
|
||||
return static_cast<const Gu::TriangleMesh*>(meshGeom.triangleMesh);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
166
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshBV4.cpp
vendored
Normal file
166
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshBV4.cpp
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
// 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 "GuTriangleMesh.h"
|
||||
#include "GuTriangleMeshBV4.h"
|
||||
#include "geometry/PxGeometryInternal.h"
|
||||
|
||||
using namespace physx;
|
||||
using namespace Gu;
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
// PT: temporary for Kit
|
||||
|
||||
BV4TriangleMesh::BV4TriangleMesh(const PxTriangleMeshInternalData& data) : TriangleMesh(data)
|
||||
{
|
||||
mMeshInterface.setNbTriangles(getNbTrianglesFast());
|
||||
if(has16BitIndices())
|
||||
mMeshInterface.setPointers(NULL, const_cast<IndTri16*>(reinterpret_cast<const IndTri16*>(getTrianglesFast())), getVerticesFast());
|
||||
else
|
||||
mMeshInterface.setPointers(const_cast<IndTri32*>(reinterpret_cast<const IndTri32*>(getTrianglesFast())), NULL, getVerticesFast());
|
||||
mBV4Tree.mMeshInterface = &mMeshInterface;
|
||||
|
||||
mBV4Tree.mLocalBounds.mCenter = data.mAABB_Center;
|
||||
mBV4Tree.mLocalBounds.mExtentsMagnitude = data.mAABB_Extents.magnitude();
|
||||
|
||||
mBV4Tree.mNbNodes = data.mNbNodes;
|
||||
mBV4Tree.mNodes = data.mNodes;
|
||||
mBV4Tree.mInitData = data.mInitData;
|
||||
mBV4Tree.mCenterOrMinCoeff = data.mCenterOrMinCoeff;
|
||||
mBV4Tree.mExtentsOrMaxCoeff = data.mExtentsOrMaxCoeff;
|
||||
mBV4Tree.mQuantized = data.mQuantized;
|
||||
mBV4Tree.mUserAllocated = true;
|
||||
}
|
||||
|
||||
bool BV4TriangleMesh::getInternalData(PxTriangleMeshInternalData& data, bool takeOwnership) const
|
||||
{
|
||||
data.mNbVertices = mNbVertices;
|
||||
data.mNbTriangles = mNbTriangles;
|
||||
data.mVertices = mVertices;
|
||||
data.mTriangles = mTriangles;
|
||||
data.mFaceRemap = mFaceRemap;
|
||||
data.mAABB_Center = mAABB.mCenter;
|
||||
data.mAABB_Extents = mAABB.mExtents;
|
||||
data.mGeomEpsilon = mGeomEpsilon;
|
||||
data.mFlags = mFlags;
|
||||
|
||||
data.mNbNodes = mBV4Tree.mNbNodes;
|
||||
data.mNodeSize = mBV4Tree.mQuantized ? sizeof(BVDataPackedQ) : sizeof(BVDataPackedNQ);
|
||||
data.mNodes = mBV4Tree.mNodes;
|
||||
data.mInitData = mBV4Tree.mInitData;
|
||||
data.mCenterOrMinCoeff = mBV4Tree.mCenterOrMinCoeff;
|
||||
data.mExtentsOrMaxCoeff = mBV4Tree.mExtentsOrMaxCoeff;
|
||||
data.mQuantized = mBV4Tree.mQuantized;
|
||||
|
||||
if(takeOwnership)
|
||||
{
|
||||
const_cast<BV4TriangleMesh*>(this)->setBaseFlag(PxBaseFlag::eOWNS_MEMORY, false);
|
||||
const_cast<BV4TriangleMesh*>(this)->mBV4Tree.mUserAllocated = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PxGetTriangleMeshInternalData(PxTriangleMeshInternalData& data, const PxTriangleMesh& mesh, bool takeOwnership)
|
||||
{
|
||||
return static_cast<const TriangleMesh&>(mesh).getInternalData(data, takeOwnership);
|
||||
}
|
||||
|
||||
//~ PT: temporary for Kit
|
||||
|
||||
BV4TriangleMesh::BV4TriangleMesh(MeshFactory* factory, TriangleMeshData& d) : TriangleMesh(factory, d)
|
||||
{
|
||||
PX_ASSERT(d.mType==PxMeshMidPhase::eBVH34);
|
||||
|
||||
BV4TriangleData& bv4Data = static_cast<BV4TriangleData&>(d);
|
||||
mMeshInterface = bv4Data.mMeshInterface;
|
||||
mBV4Tree = bv4Data.mBV4Tree;
|
||||
mBV4Tree.mMeshInterface = &mMeshInterface;
|
||||
}
|
||||
|
||||
TriangleMesh* BV4TriangleMesh::createObject(PxU8*& address, PxDeserializationContext& context)
|
||||
{
|
||||
BV4TriangleMesh* obj = PX_PLACEMENT_NEW(address, BV4TriangleMesh(PxBaseFlag::eIS_RELEASABLE));
|
||||
address += sizeof(BV4TriangleMesh);
|
||||
obj->importExtraData(context);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void BV4TriangleMesh::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
mBV4Tree.exportExtraData(stream);
|
||||
TriangleMesh::exportExtraData(stream);
|
||||
}
|
||||
|
||||
void BV4TriangleMesh::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
mBV4Tree.importExtraData(context);
|
||||
TriangleMesh::importExtraData(context);
|
||||
|
||||
if(has16BitIndices())
|
||||
mMeshInterface.setPointers(NULL, const_cast<IndTri16*>(reinterpret_cast<const IndTri16*>(getTrianglesFast())), getVerticesFast());
|
||||
else
|
||||
mMeshInterface.setPointers(const_cast<IndTri32*>(reinterpret_cast<const IndTri32*>(getTrianglesFast())), NULL, getVerticesFast());
|
||||
mBV4Tree.mMeshInterface = &mMeshInterface;
|
||||
}
|
||||
|
||||
PxVec3 * BV4TriangleMesh::getVerticesForModification()
|
||||
{
|
||||
return const_cast<PxVec3*>(getVertices());
|
||||
}
|
||||
|
||||
PxBounds3 BV4TriangleMesh::refitBVH()
|
||||
{
|
||||
PxBounds3 newBounds;
|
||||
|
||||
const float gBoxEpsilon = 2e-4f;
|
||||
if(mBV4Tree.refit(newBounds, gBoxEpsilon))
|
||||
{
|
||||
mAABB.setMinMax(newBounds.minimum, newBounds.maximum);
|
||||
}
|
||||
else
|
||||
{
|
||||
newBounds = PxBounds3::centerExtents(mAABB.mCenter, mAABB.mExtents);
|
||||
|
||||
PxGetFoundation().error(PxErrorCode::eINVALID_OPERATION, PX_FL, "BVH34 trees: refit operation only available on non-quantized trees.\n");
|
||||
}
|
||||
|
||||
// PT: copied from RTreeTriangleMesh::refitBVH()
|
||||
// reset edge flags and remember we did that using a mesh flag (optimization)
|
||||
if(!mBV4Tree.mIsEdgeSet)
|
||||
{
|
||||
mBV4Tree.mIsEdgeSet = true;
|
||||
setAllEdgesActive();
|
||||
}
|
||||
|
||||
return newBounds;
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
80
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshBV4.h
vendored
Normal file
80
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshBV4.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
// 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_TRIANGLEMESH_BV4_H
|
||||
#define GU_TRIANGLEMESH_BV4_H
|
||||
|
||||
#include "GuTriangleMesh.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class MeshFactory;
|
||||
|
||||
#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 BV4TriangleMesh : public TriangleMesh
|
||||
{
|
||||
public:
|
||||
virtual const char* getConcreteTypeName() const { return "PxBVH34TriangleMesh"; }
|
||||
// PX_SERIALIZATION
|
||||
BV4TriangleMesh(PxBaseFlags baseFlags) : TriangleMesh(baseFlags), mMeshInterface(PxEmpty), mBV4Tree(PxEmpty) {}
|
||||
PX_PHYSX_COMMON_API virtual void exportExtraData(PxSerializationContext& ctx);
|
||||
void importExtraData(PxDeserializationContext&);
|
||||
PX_PHYSX_COMMON_API static TriangleMesh* createObject(PxU8*& address, PxDeserializationContext& context);
|
||||
//~PX_SERIALIZATION
|
||||
BV4TriangleMesh(MeshFactory* factory, TriangleMeshData& data);
|
||||
virtual ~BV4TriangleMesh(){}
|
||||
|
||||
virtual PxMeshMidPhase::Enum getMidphaseID() const { return PxMeshMidPhase::eBVH34; }
|
||||
|
||||
virtual PxVec3* getVerticesForModification();
|
||||
virtual PxBounds3 refitBVH();
|
||||
|
||||
PX_PHYSX_COMMON_API BV4TriangleMesh(const PxTriangleMeshInternalData& data);
|
||||
virtual bool getInternalData(PxTriangleMeshInternalData&, bool) const;
|
||||
|
||||
PX_FORCE_INLINE const Gu::BV4Tree& getBV4Tree() const { return mBV4Tree; }
|
||||
private:
|
||||
Gu::SourceMesh mMeshInterface;
|
||||
Gu::BV4Tree mBV4Tree;
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
138
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshRTree.cpp
vendored
Normal file
138
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshRTree.cpp
vendored
Normal file
@@ -0,0 +1,138 @@
|
||||
// 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 "GuTriangleMesh.h"
|
||||
#include "GuTriangleMeshRTree.h"
|
||||
|
||||
using namespace physx;
|
||||
|
||||
namespace physx
|
||||
{
|
||||
|
||||
Gu::RTreeTriangleMesh::RTreeTriangleMesh(MeshFactory* factory, TriangleMeshData& d) : TriangleMesh(factory, d)
|
||||
{
|
||||
PX_ASSERT(d.mType==PxMeshMidPhase::eBVH33);
|
||||
|
||||
RTreeTriangleData& rtreeData = static_cast<RTreeTriangleData&>(d);
|
||||
mRTree = rtreeData.mRTree;
|
||||
rtreeData.mRTree.mPages = NULL;
|
||||
}
|
||||
|
||||
Gu::TriangleMesh* Gu::RTreeTriangleMesh::createObject(PxU8*& address, PxDeserializationContext& context)
|
||||
{
|
||||
RTreeTriangleMesh* obj = PX_PLACEMENT_NEW(address, RTreeTriangleMesh(PxBaseFlag::eIS_RELEASABLE));
|
||||
address += sizeof(RTreeTriangleMesh);
|
||||
obj->importExtraData(context);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void Gu::RTreeTriangleMesh::exportExtraData(PxSerializationContext& stream)
|
||||
{
|
||||
mRTree.exportExtraData(stream);
|
||||
TriangleMesh::exportExtraData(stream);
|
||||
}
|
||||
|
||||
void Gu::RTreeTriangleMesh::importExtraData(PxDeserializationContext& context)
|
||||
{
|
||||
mRTree.importExtraData(context);
|
||||
TriangleMesh::importExtraData(context);
|
||||
}
|
||||
|
||||
PxVec3 * Gu::RTreeTriangleMesh::getVerticesForModification()
|
||||
{
|
||||
return const_cast<PxVec3*>(getVertices());
|
||||
}
|
||||
|
||||
template<typename IndexType>
|
||||
struct RefitCallback : Gu::RTree::CallbackRefit
|
||||
{
|
||||
const PxVec3* newPositions;
|
||||
const IndexType* indices;
|
||||
|
||||
RefitCallback(const PxVec3* aNewPositions, const IndexType* aIndices) : newPositions(aNewPositions), indices(aIndices) {}
|
||||
PX_FORCE_INLINE ~RefitCallback() {}
|
||||
|
||||
virtual void recomputeBounds(PxU32 index, aos::Vec3V& aMn, aos::Vec3V& aMx)
|
||||
{
|
||||
using namespace aos;
|
||||
|
||||
// Each leaf box has a set of triangles
|
||||
Gu::LeafTriangles currentLeaf; currentLeaf.Data = index;
|
||||
PxU32 nbTris = currentLeaf.GetNbTriangles();
|
||||
PxU32 baseTri = currentLeaf.GetTriangleIndex();
|
||||
PX_ASSERT(nbTris > 0);
|
||||
const IndexType* vInds = indices + 3 * baseTri;
|
||||
Vec3V vPos = V3LoadU(newPositions[vInds[0]]);
|
||||
Vec3V mn = vPos, mx = vPos;
|
||||
//PxBounds3 result(newPositions[vInds[0]], newPositions[vInds[0]]);
|
||||
vPos = V3LoadU(newPositions[vInds[1]]);
|
||||
mn = V3Min(mn, vPos); mx = V3Max(mx, vPos);
|
||||
vPos = V3LoadU(newPositions[vInds[2]]);
|
||||
mn = V3Min(mn, vPos); mx = V3Max(mx, vPos);
|
||||
for (PxU32 i = 1; i < nbTris; i++)
|
||||
{
|
||||
const IndexType* vInds1 = indices + 3 * (baseTri + i);
|
||||
vPos = V3LoadU(newPositions[vInds1[0]]);
|
||||
mn = V3Min(mn, vPos); mx = V3Max(mx, vPos);
|
||||
vPos = V3LoadU(newPositions[vInds1[1]]);
|
||||
mn = V3Min(mn, vPos); mx = V3Max(mx, vPos);
|
||||
vPos = V3LoadU(newPositions[vInds1[2]]);
|
||||
mn = V3Min(mn, vPos); mx = V3Max(mx, vPos);
|
||||
}
|
||||
|
||||
aMn = mn;
|
||||
aMx = mx;
|
||||
}
|
||||
};
|
||||
|
||||
PxBounds3 Gu::RTreeTriangleMesh::refitBVH()
|
||||
{
|
||||
PxBounds3 meshBounds;
|
||||
if (has16BitIndices())
|
||||
{
|
||||
RefitCallback<PxU16> cb(mVertices, static_cast<const PxU16*>(mTriangles));
|
||||
mRTree.refitAllStaticTree(cb, &meshBounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
RefitCallback<PxU32> cb(mVertices, static_cast<const PxU32*>(mTriangles));
|
||||
mRTree.refitAllStaticTree(cb, &meshBounds);
|
||||
}
|
||||
|
||||
// reset edge flags and remember we did that using a mesh flag (optimization)
|
||||
if ((mRTree.mFlags & RTree::IS_EDGE_SET) == 0)
|
||||
{
|
||||
mRTree.mFlags |= RTree::IS_EDGE_SET;
|
||||
setAllEdgesActive();
|
||||
}
|
||||
|
||||
mAABB = meshBounds;
|
||||
return meshBounds;
|
||||
}
|
||||
|
||||
} // namespace physx
|
||||
76
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshRTree.h
vendored
Normal file
76
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleMeshRTree.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions
|
||||
// are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Copyright (c) 2008-2025 NVIDIA Corporation. All rights reserved.
|
||||
// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
|
||||
// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
|
||||
|
||||
#ifndef GU_TRIANGLEMESH_RTREE_H
|
||||
#define GU_TRIANGLEMESH_RTREE_H
|
||||
|
||||
#include "GuTriangleMesh.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
class MeshFactory;
|
||||
|
||||
#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 RTreeTriangleMesh : public TriangleMesh
|
||||
{
|
||||
public:
|
||||
virtual const char* getConcreteTypeName() const { return "PxBVH33TriangleMesh"; }
|
||||
// PX_SERIALIZATION
|
||||
RTreeTriangleMesh(PxBaseFlags baseFlags) : TriangleMesh(baseFlags), mRTree(PxEmpty) {}
|
||||
PX_PHYSX_COMMON_API virtual void exportExtraData(PxSerializationContext& ctx);
|
||||
void importExtraData(PxDeserializationContext&);
|
||||
PX_PHYSX_COMMON_API static TriangleMesh* createObject(PxU8*& address, PxDeserializationContext& context);
|
||||
//~PX_SERIALIZATION
|
||||
RTreeTriangleMesh(MeshFactory* factory, TriangleMeshData& data);
|
||||
virtual ~RTreeTriangleMesh(){}
|
||||
|
||||
virtual PxMeshMidPhase::Enum getMidphaseID() const { return PxMeshMidPhase::eBVH33; }
|
||||
|
||||
virtual PxVec3* getVerticesForModification();
|
||||
virtual PxBounds3 refitBVH();
|
||||
|
||||
PX_FORCE_INLINE const Gu::RTree& getRTree() const { return mRTree; }
|
||||
private:
|
||||
Gu::RTree mRTree;
|
||||
};
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
} // namespace Gu
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
121
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleRefinement.h
vendored
Normal file
121
engine/third_party/physx/source/geomutils/src/mesh/GuTriangleRefinement.h
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// 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_TRIANGLE_REFINEMENT_H
|
||||
#define GU_TRIANGLE_REFINEMENT_H
|
||||
|
||||
// Indexing scheme for sub-triangles in recursive triangle subdivision scheme
|
||||
// Each subdivision step creates 4 triangles out of the previous one:
|
||||
// - First triangle is the "a corner"
|
||||
// - Second triangle is the "b corner"
|
||||
// - Third triangle is the "c corner"
|
||||
// - Fourth triangle is the center
|
||||
|
||||
#include "foundation/PxVec3.h"
|
||||
|
||||
namespace physx {
|
||||
namespace Gu {
|
||||
PX_FORCE_INLINE PX_CUDA_CALLABLE void getSubTriangle4(int id, PxVec3& baryA, PxVec3& baryB, PxVec3& baryC)
|
||||
{
|
||||
|
||||
PxVec3 ab = 0.5f * (baryA + baryB);
|
||||
PxVec3 bc = 0.5f * (baryB + baryC);
|
||||
PxVec3 ca = 0.5f * (baryC + baryA);
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case 0:
|
||||
baryB = ab;
|
||||
baryC = ca;
|
||||
break;
|
||||
case 1:
|
||||
baryA = ab;
|
||||
baryC = bc;
|
||||
break;
|
||||
case 2:
|
||||
baryA = ca;
|
||||
baryB = bc;
|
||||
break;
|
||||
case 3:
|
||||
baryA = ab;
|
||||
baryB = bc;
|
||||
baryC = ca;
|
||||
break;
|
||||
default:
|
||||
PX_ASSERT(false);
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PX_CUDA_CALLABLE void getSubTriangle(PxVec3& a, PxVec3& b, PxVec3& c, PxU32 id, PxU32 numSubdivisionSteps)
|
||||
{
|
||||
for (PxU32 i = 0; i < numSubdivisionSteps; ++i)
|
||||
{
|
||||
PxU32 j = numSubdivisionSteps - i - 1;
|
||||
PxU32 local = id >> (2 * j);
|
||||
local = local & 3;
|
||||
getSubTriangle4(local, a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PX_CUDA_CALLABLE PxU32 encodeSubdivisionId(PxU32 subdivisionLevel, PxU32 subTriangleIndex)
|
||||
{
|
||||
//4 bits for subdivision level, the rest for the index
|
||||
const PxU32 shift = 30 - 4;
|
||||
return (subdivisionLevel << shift) | subTriangleIndex;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PX_CUDA_CALLABLE void decodeSubdivisionId(PxU32 encodedId, PxU32& subdivisionLevel, PxU32& subTriangleIndex)
|
||||
{
|
||||
const PxU32 shift = 30 - 4;
|
||||
subdivisionLevel = encodedId >> shift;
|
||||
subTriangleIndex = encodedId & ((1 << shift) - 1);
|
||||
}
|
||||
|
||||
//Increases the subdivision level by one and sets the index to the specified sub triangle that got created out of the previous triangle due to one additional level of subdivision
|
||||
PX_FORCE_INLINE PX_CUDA_CALLABLE PxU32 elevateSubdivisionId(PxU32 encodedId, PxU32 subTriangle = 0)
|
||||
{
|
||||
PX_ASSERT(subTriangle >= 0 && subTriangle < 4);
|
||||
|
||||
PxU32 subdivisionLevel;
|
||||
PxU32 subTriangleIndex;
|
||||
decodeSubdivisionId(encodedId, subdivisionLevel, subTriangleIndex);
|
||||
|
||||
return encodeSubdivisionId(subdivisionLevel + 1, 4 * subTriangleIndex + subTriangle);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PX_CUDA_CALLABLE void getSubTriangleEncoded(PxVec3& a, PxVec3& b, PxVec3& c, PxU32 encodedSubIndex)
|
||||
{
|
||||
PxU32 subdivisionLevel;
|
||||
PxU32 subTriangleIndex;
|
||||
decodeSubdivisionId(encodedSubIndex, subdivisionLevel, subTriangleIndex);
|
||||
getSubTriangle(a, b, c, subTriangleIndex, subdivisionLevel);
|
||||
}
|
||||
|
||||
} // namespace Gu
|
||||
} // namespace physx
|
||||
#endif // GU_TRIANGLE_REFINEMENT_H
|
||||
Reference in New Issue
Block a user