feat(physics): wire physx sdk into build
This commit is contained in:
580
engine/third_party/physx/source/geomutils/src/GuAABBTree.h
vendored
Normal file
580
engine/third_party/physx/source/geomutils/src/GuAABBTree.h
vendored
Normal file
@@ -0,0 +1,580 @@
|
||||
// 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_AABBTREE_H
|
||||
#define GU_AABBTREE_H
|
||||
|
||||
#include "foundation/PxMemory.h"
|
||||
#include "foundation/PxArray.h"
|
||||
#include "foundation/PxBounds3.h"
|
||||
#include "foundation/PxUserAllocated.h"
|
||||
#include "common/PxPhysXCommonConfig.h"
|
||||
#include "GuPrunerTypedef.h"
|
||||
#include "GuAABBTreeQuery.h"
|
||||
#include "GuDistancePointTriangle.h"
|
||||
#include "GuDistancePointTetrahedron.h"
|
||||
|
||||
namespace physx
|
||||
{
|
||||
namespace Gu
|
||||
{
|
||||
struct BVHNode;
|
||||
struct SAH_Buffers;
|
||||
class NodeAllocator;
|
||||
struct BuildStats;
|
||||
class AABBTreeBounds;
|
||||
|
||||
// PT: TODO: sometimes we export member functions, sometimes we export the whole class. What's the story here?
|
||||
|
||||
#if PX_VC
|
||||
#pragma warning(push)
|
||||
#pragma warning( disable : 4251 ) // class needs to have dll-interface to be used by clients of class
|
||||
#endif
|
||||
//! Contains AABB-tree build parameters
|
||||
class PX_PHYSX_COMMON_API AABBTreeBuildParams : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
AABBTreeBuildParams(PxU32 limit = 1, PxU32 nb_prims = 0, const AABBTreeBounds* bounds = NULL, BVHBuildStrategy bs = BVH_SPLATTER_POINTS) :
|
||||
mLimit (limit),
|
||||
mNbPrimitives (nb_prims),
|
||||
mBounds (bounds),
|
||||
mCache (NULL),
|
||||
mBuildStrategy (bs)
|
||||
{
|
||||
}
|
||||
~AABBTreeBuildParams()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void reset()
|
||||
{
|
||||
mLimit = mNbPrimitives = 0;
|
||||
mBounds = NULL;
|
||||
PX_FREE(mCache);
|
||||
}
|
||||
|
||||
PxU32 mLimit; //!< Limit number of primitives / node. If limit is 1, build a complete tree (2*N-1 nodes)
|
||||
PxU32 mNbPrimitives; //!< Number of (source) primitives.
|
||||
const AABBTreeBounds* mBounds; //!< Shortcut to an app-controlled array of AABBs.
|
||||
mutable PxVec3* mCache; //!< Cache for AABB centers - managed by build code.
|
||||
BVHBuildStrategy mBuildStrategy;
|
||||
};
|
||||
|
||||
//! AABB tree node used for building
|
||||
class PX_PHYSX_COMMON_API AABBTreeBuildNode : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
PX_FORCE_INLINE AABBTreeBuildNode() {}
|
||||
PX_FORCE_INLINE ~AABBTreeBuildNode() {}
|
||||
|
||||
PX_FORCE_INLINE const PxBounds3& getAABB() const { return mBV; }
|
||||
PX_FORCE_INLINE const AABBTreeBuildNode* getPos() const { return mPos; }
|
||||
PX_FORCE_INLINE const AABBTreeBuildNode* getNeg() const { const AABBTreeBuildNode* P = mPos; return P ? P + 1 : NULL; }
|
||||
|
||||
PX_FORCE_INLINE bool isLeaf() const { return !getPos(); }
|
||||
|
||||
PxBounds3 mBV; //!< Global bounding-volume enclosing all the node-related primitives
|
||||
const AABBTreeBuildNode* mPos; //!< "Positive" & "Negative" children
|
||||
|
||||
PxU32 mNodeIndex; //!< Index of node-related primitives (in the tree's mIndices array)
|
||||
PxU32 mNbPrimitives; //!< Number of primitives for this node
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbPrimitives() const { return mNbPrimitives; }
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbRuntimePrimitives() const { return mNbPrimitives; }
|
||||
PX_FORCE_INLINE void setNbRunTimePrimitives(PxU32 val) { mNbPrimitives = val; }
|
||||
PX_FORCE_INLINE const PxU32* getPrimitives(const PxU32* base) const { return base + mNodeIndex; }
|
||||
PX_FORCE_INLINE PxU32* getPrimitives(PxU32* base) { return base + mNodeIndex; }
|
||||
|
||||
void subdivide(const AABBTreeBuildParams& params, BuildStats& stats, NodeAllocator& allocator, PxU32* const indices);
|
||||
void subdivideSAH(const AABBTreeBuildParams& params, SAH_Buffers& sah, BuildStats& stats, NodeAllocator& allocator, PxU32* const indices);
|
||||
};
|
||||
|
||||
//! For complete trees we can predict the final number of nodes and preallocate them. For incomplete trees we can't.
|
||||
//! But we don't want to allocate nodes one by one (which would be quite slow), so we use this helper class to
|
||||
//! allocate N nodes at once, while minimizing the amount of nodes allocated for nothing. An initial amount of
|
||||
//! nodes is estimated using the max number for a complete tree, and the user-defined number of primitives per leaf.
|
||||
//! In ideal cases this estimated number will be quite close to the final number of nodes. When that number is not
|
||||
//! enough though, slabs of N=1024 extra nodes are allocated until the build is complete.
|
||||
class PX_PHYSX_COMMON_API NodeAllocator : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
NodeAllocator();
|
||||
~NodeAllocator();
|
||||
|
||||
void release();
|
||||
void init(PxU32 nbPrimitives, PxU32 limit);
|
||||
AABBTreeBuildNode* getBiNode();
|
||||
|
||||
AABBTreeBuildNode* mPool;
|
||||
|
||||
struct Slab
|
||||
{
|
||||
PX_FORCE_INLINE Slab() {}
|
||||
PX_FORCE_INLINE Slab(AABBTreeBuildNode* pool, PxU32 nbUsedNodes, PxU32 maxNbNodes) : mPool(pool), mNbUsedNodes(nbUsedNodes), mMaxNbNodes(maxNbNodes) {}
|
||||
AABBTreeBuildNode* mPool;
|
||||
PxU32 mNbUsedNodes;
|
||||
PxU32 mMaxNbNodes;
|
||||
};
|
||||
PxArray<Slab> mSlabs;
|
||||
PxU32 mCurrentSlabIndex;
|
||||
PxU32 mTotalNbNodes;
|
||||
};
|
||||
#if PX_VC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* \brief Builds AABBtree from given parameters.
|
||||
* \param params [in/out] AABBTree build params
|
||||
* \param nodeAllocator [in/out] Node allocator
|
||||
* \param stats [out] Statistics
|
||||
* \return Indices buffer allocated during build, or NULL if failed
|
||||
*/
|
||||
PX_PHYSX_COMMON_API PxU32* buildAABBTree(const AABBTreeBuildParams& params, NodeAllocator& nodeAllocator, BuildStats& stats);
|
||||
|
||||
// PT: TODO: explain how users should call these functions and maybe revisit this
|
||||
PX_PHYSX_COMMON_API void flattenTree(const NodeAllocator& nodeAllocator, BVHNode* dest, const PxU32* remap = NULL);
|
||||
|
||||
PX_PHYSX_COMMON_API void buildAABBTree(PxU32 nbBounds, const AABBTreeBounds& bounds, PxArray<BVHNode>& tree);
|
||||
|
||||
PxU32 reshuffle(PxU32 nb, PxU32* const PX_RESTRICT prims, const PxVec3* PX_RESTRICT centers, float splitValue, PxU32 axis);
|
||||
|
||||
class BitArray
|
||||
{
|
||||
public:
|
||||
BitArray() : mBits(NULL), mSize(0) {}
|
||||
BitArray(PxU32 nb_bits) { init(nb_bits); }
|
||||
~BitArray() { PX_FREE(mBits); }
|
||||
|
||||
bool init(PxU32 nb_bits);
|
||||
|
||||
// Data management
|
||||
PX_FORCE_INLINE void setBit(PxU32 bit_number)
|
||||
{
|
||||
mBits[bit_number>>5] |= 1<<(bit_number&31);
|
||||
}
|
||||
PX_FORCE_INLINE void clearBit(PxU32 bit_number)
|
||||
{
|
||||
mBits[bit_number>>5] &= ~(1<<(bit_number&31));
|
||||
}
|
||||
PX_FORCE_INLINE void toggleBit(PxU32 bit_number)
|
||||
{
|
||||
mBits[bit_number>>5] ^= 1<<(bit_number&31);
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void clearAll() { PxMemZero(mBits, mSize*4); }
|
||||
PX_FORCE_INLINE void setAll() { PxMemSet(mBits, 0xff, mSize*4); }
|
||||
|
||||
void resize(PxU32 maxBitNumber);
|
||||
|
||||
// Data access
|
||||
PX_FORCE_INLINE PxIntBool isSet(PxU32 bit_number) const
|
||||
{
|
||||
return PxIntBool(mBits[bit_number>>5] & (1<<(bit_number&31)));
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const PxU32* getBits() const { return mBits; }
|
||||
PX_FORCE_INLINE PxU32 getSize() const { return mSize; }
|
||||
|
||||
protected:
|
||||
PxU32* mBits; //!< Array of bits
|
||||
PxU32 mSize; //!< Size of the array in dwords
|
||||
};
|
||||
|
||||
//! Contains AABB-tree merge parameters
|
||||
class AABBTreeMergeData
|
||||
{
|
||||
public:
|
||||
AABBTreeMergeData(PxU32 nbNodes, const BVHNode* nodes, PxU32 nbIndices, const PxU32* indices, PxU32 indicesOffset) :
|
||||
mNbNodes(nbNodes), mNodes(nodes), mNbIndices(nbIndices), mIndices(indices), mIndicesOffset(indicesOffset)
|
||||
{
|
||||
}
|
||||
|
||||
~AABBTreeMergeData() {}
|
||||
|
||||
PX_FORCE_INLINE const BVHNode& getRootNode() const { return *mNodes; }
|
||||
|
||||
public:
|
||||
PxU32 mNbNodes; //!< Number of nodes of AABB tree merge
|
||||
const BVHNode* mNodes; //!< Nodes of AABB tree merge
|
||||
|
||||
PxU32 mNbIndices; //!< Number of indices of AABB tree merge
|
||||
const PxU32* mIndices; //!< Indices of AABB tree merge
|
||||
|
||||
PxU32 mIndicesOffset; //!< Indices offset from pruning pool
|
||||
};
|
||||
|
||||
// Progressive building
|
||||
class FIFOStack;
|
||||
//~Progressive building
|
||||
|
||||
// PT: base class used to share some data and code between Gu::AABBtree and Gu::BVH. This is WIP and subject to change.
|
||||
// Design dictated by refactoring necessities rather than a grand vision of something.
|
||||
class BVHCoreData : public PxUserAllocated
|
||||
{
|
||||
public:
|
||||
BVHCoreData() : mNbIndices(0), mNbNodes(0), mNodes(NULL), mIndices(NULL) {}
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbIndices() const { return mNbIndices; }
|
||||
PX_FORCE_INLINE const PxU32* getIndices() const { return mIndices; }
|
||||
PX_FORCE_INLINE PxU32* getIndices() { return mIndices; }
|
||||
PX_FORCE_INLINE void setIndices(PxU32* indices) { mIndices = indices; }
|
||||
|
||||
PX_FORCE_INLINE PxU32 getNbNodes() const { return mNbNodes; }
|
||||
PX_FORCE_INLINE const BVHNode* getNodes() const { return mNodes; }
|
||||
PX_FORCE_INLINE BVHNode* getNodes() { return mNodes; }
|
||||
|
||||
PX_PHYSX_COMMON_API void fullRefit(const PxBounds3* boxes);
|
||||
|
||||
// PT: I'm leaving the above accessors here to avoid refactoring the SQ code using them, but members became public.
|
||||
PxU32 mNbIndices; //!< Nb indices
|
||||
PxU32 mNbNodes; //!< Number of nodes in the tree.
|
||||
BVHNode* mNodes; //!< Linear pool of nodes.
|
||||
PxU32* mIndices; //!< Indices in the app list. Indices are reorganized during build (permutation).
|
||||
};
|
||||
|
||||
class BVHPartialRefitData : public BVHCoreData
|
||||
{
|
||||
public:
|
||||
PX_PHYSX_COMMON_API BVHPartialRefitData();
|
||||
PX_PHYSX_COMMON_API ~BVHPartialRefitData();
|
||||
|
||||
PX_PHYSX_COMMON_API void releasePartialRefitData(bool clearRefitMap);
|
||||
// adds node[index] to a list of nodes to refit when refitMarkedNodes is called
|
||||
// Note that this includes updating the hierarchy up the chain
|
||||
PX_PHYSX_COMMON_API void markNodeForRefit(TreeNodeIndex nodeIndex);
|
||||
PX_PHYSX_COMMON_API void refitMarkedNodes(const PxBounds3* boxes);
|
||||
|
||||
PX_FORCE_INLINE PxU32* getUpdateMap() { return mUpdateMap; }
|
||||
|
||||
protected:
|
||||
PxU32* mParentIndices; //!< PT: hot/cold split, keep parent data in separate array
|
||||
PxU32* mUpdateMap; //!< PT: Local index to tree node index
|
||||
BitArray mRefitBitmask; //!< bit is set for each node index in markForRefit
|
||||
PxU32 mRefitHighestSetWord;
|
||||
|
||||
PxU32* getParentIndices();
|
||||
public:
|
||||
void createUpdateMap(PxU32 nbObjects);
|
||||
};
|
||||
|
||||
//! AABB-tree, N primitives/leaf
|
||||
// PT: TODO: each PX_PHYSX_COMMON_API is a cross-DLL call, should we split that class in Gu/Sq parts to minimize this?
|
||||
class AABBTree : public BVHPartialRefitData
|
||||
{
|
||||
public:
|
||||
PX_PHYSX_COMMON_API AABBTree();
|
||||
PX_PHYSX_COMMON_API ~AABBTree();
|
||||
// Build
|
||||
PX_PHYSX_COMMON_API bool build(const AABBTreeBuildParams& params, NodeAllocator& nodeAllocator);
|
||||
// Progressive building
|
||||
PX_PHYSX_COMMON_API PxU32 progressiveBuild(const AABBTreeBuildParams& params, NodeAllocator& nodeAllocator, BuildStats& stats, PxU32 progress, PxU32 limit);
|
||||
//~Progressive building
|
||||
PX_PHYSX_COMMON_API void release(bool clearRefitMap=true);
|
||||
|
||||
// Merge tree with another one
|
||||
PX_PHYSX_COMMON_API void mergeTree(const AABBTreeMergeData& tree);
|
||||
// Initialize tree from given merge data
|
||||
PX_PHYSX_COMMON_API void initTree(const AABBTreeMergeData& tree);
|
||||
|
||||
// Data access
|
||||
PX_FORCE_INLINE PxU32 getTotalPrims() const { return mTotalPrims; }
|
||||
|
||||
PX_PHYSX_COMMON_API void shiftOrigin(const PxVec3& shift);
|
||||
|
||||
// Shift indices of the tree by offset. Used for merged trees, when initial indices needs to be shifted to match indices in current pruning pool
|
||||
PX_PHYSX_COMMON_API void shiftIndices(PxU32 offset);
|
||||
|
||||
#if PX_DEBUG
|
||||
void validate() {}
|
||||
#endif
|
||||
private:
|
||||
PxU32 mTotalPrims; //!< Copy of final BuildStats::mTotalPrims
|
||||
// Progressive building
|
||||
FIFOStack* mStack;
|
||||
//~Progressive building
|
||||
bool buildInit(const AABBTreeBuildParams& params, NodeAllocator& nodeAllocator, BuildStats& stats);
|
||||
void buildEnd(const AABBTreeBuildParams& params, NodeAllocator& nodeAllocator, const BuildStats& stats);
|
||||
// tree merge
|
||||
void mergeRuntimeNode(BVHNode& targetNode, const AABBTreeMergeData& tree, PxU32 targetNodeIndex);
|
||||
void mergeRuntimeLeaf(BVHNode& targetNode, const AABBTreeMergeData& tree, PxU32 targetNodeIndex);
|
||||
void addRuntimeChilds(PxU32& nodeIndex, const AABBTreeMergeData& tree);
|
||||
void traverseRuntimeNode(BVHNode& targetNode, const AABBTreeMergeData& tree, PxU32 nodeIndex);
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct TinyBVH
|
||||
{
|
||||
PxArray<Gu::BVHNode> mTree;
|
||||
|
||||
PX_PHYSX_COMMON_API static void constructFromTriangles(const PxU32* triangles, const PxU32 numTriangles, const PxVec3* points,
|
||||
TinyBVH& result, PxF32 enlargement = 1e-4f);
|
||||
|
||||
PX_PHYSX_COMMON_API static void constructFromTetrahedra(const PxU32* tetrahedra, const PxU32 numTetrahedra, const PxVec3* points,
|
||||
TinyBVH& result, PxF32 enlargement = 1e-4f);
|
||||
|
||||
template<typename T>
|
||||
void Traverse(T& traversalController, PxI32 rootNodeIndex = 0)
|
||||
{
|
||||
Gu::traverseBVH(mTree.begin(), traversalController, rootNodeIndex);
|
||||
}
|
||||
};
|
||||
|
||||
class ClosestDistanceToTetmeshTraversalController
|
||||
{
|
||||
private:
|
||||
PxReal mClosestDistanceSquared;
|
||||
const PxU32* mTetrahedra;
|
||||
const PxVec3* mPoints;
|
||||
const Gu::BVHNode* mNodes;
|
||||
PxVec3 mQueryPoint;
|
||||
PxVec3 mClosestPoint;
|
||||
PxI32 mClosestTetId;
|
||||
|
||||
public:
|
||||
PX_FORCE_INLINE ClosestDistanceToTetmeshTraversalController() {}
|
||||
|
||||
PX_FORCE_INLINE ClosestDistanceToTetmeshTraversalController(const PxU32* tetrahedra, const PxVec3* points, Gu::BVHNode* nodes) :
|
||||
mClosestDistanceSquared(PX_MAX_F32), mTetrahedra(tetrahedra), mPoints(points), mNodes(nodes), mQueryPoint(0.0f), mClosestPoint(0.0f), mClosestTetId(-1)
|
||||
{
|
||||
initialize(tetrahedra, points, nodes);
|
||||
}
|
||||
|
||||
void initialize(const PxU32* tetrahedra, const PxVec3* points, Gu::BVHNode* nodes)
|
||||
{
|
||||
mTetrahedra = tetrahedra;
|
||||
mPoints = points;
|
||||
mNodes = nodes;
|
||||
mQueryPoint = PxVec3(0.0f);
|
||||
mClosestPoint = PxVec3(0.0f);
|
||||
mClosestTetId = -1;
|
||||
mClosestDistanceSquared = PX_MAX_F32;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void setQueryPoint(const PxVec3& queryPoint)
|
||||
{
|
||||
mQueryPoint = queryPoint;
|
||||
mClosestDistanceSquared = PX_MAX_F32;
|
||||
mClosestPoint = PxVec3(0.0f);
|
||||
mClosestTetId = -1;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const PxVec3& getClosestPoint() const
|
||||
{
|
||||
return mClosestPoint;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxReal distancePointBoxSquared(const PxBounds3& box, const PxVec3& point)
|
||||
{
|
||||
PxVec3 closestPt = box.minimum.maximum(box.maximum.minimum(point));
|
||||
return (closestPt - point).magnitudeSquared();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE Gu::TraversalControl::Enum analyze(const Gu::BVHNode& node, PxI32)
|
||||
{
|
||||
if (distancePointBoxSquared(node.mBV, mQueryPoint) >= mClosestDistanceSquared)
|
||||
return Gu::TraversalControl::eDontGoDeeper;
|
||||
|
||||
if (node.isLeaf())
|
||||
{
|
||||
const PxI32 j = node.getPrimitiveIndex();
|
||||
const PxU32* tet = &mTetrahedra[4 * j];
|
||||
|
||||
PxVec3 closest = closestPtPointTetrahedronWithInsideCheck(mQueryPoint,
|
||||
mPoints[tet[0]], mPoints[tet[1]], mPoints[tet[2]], mPoints[tet[3]]);
|
||||
|
||||
PxReal d2 = (closest - mQueryPoint).magnitudeSquared();
|
||||
|
||||
if (d2 < mClosestDistanceSquared)
|
||||
{
|
||||
mClosestDistanceSquared = d2;
|
||||
mClosestTetId = j;
|
||||
mClosestPoint = closest;
|
||||
}
|
||||
if (d2 == 0.0f)
|
||||
return Gu::TraversalControl::eAbort;
|
||||
|
||||
return Gu::TraversalControl::eDontGoDeeper;
|
||||
}
|
||||
|
||||
const Gu::BVHNode& nodePos = mNodes[node.getPosIndex()];
|
||||
const PxReal distSquaredPos = distancePointBoxSquared(nodePos.mBV, mQueryPoint);
|
||||
const Gu::BVHNode& nodeNeg = mNodes[node.getNegIndex()];
|
||||
const PxReal distSquaredNeg = distancePointBoxSquared(nodeNeg.mBV, mQueryPoint);
|
||||
|
||||
if (distSquaredPos < distSquaredNeg)
|
||||
{
|
||||
if (distSquaredPos < mClosestDistanceSquared)
|
||||
return Gu::TraversalControl::eGoDeeper;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (distSquaredNeg < mClosestDistanceSquared)
|
||||
return Gu::TraversalControl::eGoDeeperNegFirst;
|
||||
}
|
||||
return Gu::TraversalControl::eDontGoDeeper;
|
||||
}
|
||||
|
||||
PxI32 getClosestTetId() const { return mClosestTetId; }
|
||||
|
||||
void setClosestStart(const PxReal closestDistanceSquared, PxI32 closestTetrahedron, const PxVec3& closestPoint)
|
||||
{
|
||||
mClosestDistanceSquared = closestDistanceSquared;
|
||||
mClosestTetId = closestTetrahedron;
|
||||
mClosestPoint = closestPoint;
|
||||
}
|
||||
|
||||
private:
|
||||
PX_NOCOPY(ClosestDistanceToTetmeshTraversalController)
|
||||
};
|
||||
|
||||
class ClosestDistanceToTrimeshTraversalController
|
||||
{
|
||||
private:
|
||||
PxReal mClosestDistanceSquared;
|
||||
const PxU32* mTriangles;
|
||||
const PxVec3* mPoints;
|
||||
const Gu::BVHNode* mNodes;
|
||||
PxVec3 mQueryPoint;
|
||||
PxVec3 mClosestPoint;
|
||||
PxI32 mClosestTriId;
|
||||
|
||||
public:
|
||||
PX_FORCE_INLINE ClosestDistanceToTrimeshTraversalController() {}
|
||||
|
||||
PX_FORCE_INLINE ClosestDistanceToTrimeshTraversalController(const PxU32* triangles, const PxVec3* points, Gu::BVHNode* nodes) :
|
||||
mClosestDistanceSquared(PX_MAX_F32), mTriangles(triangles), mPoints(points), mNodes(nodes), mQueryPoint(0.0f), mClosestPoint(0.0f), mClosestTriId(-1)
|
||||
{
|
||||
initialize(triangles, points, nodes);
|
||||
}
|
||||
|
||||
void initialize(const PxU32* triangles, const PxVec3* points, Gu::BVHNode* nodes)
|
||||
{
|
||||
mTriangles = triangles;
|
||||
mPoints = points;
|
||||
mNodes = nodes;
|
||||
mQueryPoint = PxVec3(0.0f);
|
||||
mClosestPoint = PxVec3(0.0f);
|
||||
mClosestTriId = -1;
|
||||
mClosestDistanceSquared = PX_MAX_F32;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE void setQueryPoint(const PxVec3& queryPoint)
|
||||
{
|
||||
mQueryPoint = queryPoint;
|
||||
mClosestDistanceSquared = PX_MAX_F32;
|
||||
mClosestPoint = PxVec3(0.0f);
|
||||
mClosestTriId = -1;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE const PxVec3& getClosestPoint() const
|
||||
{
|
||||
return mClosestPoint;
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE PxReal distancePointBoxSquared(const PxBounds3& box, const PxVec3& point)
|
||||
{
|
||||
PxVec3 closestPt = box.minimum.maximum(box.maximum.minimum(point));
|
||||
|
||||
return (closestPt - point).magnitudeSquared();
|
||||
}
|
||||
|
||||
PX_FORCE_INLINE Gu::TraversalControl::Enum analyze(const Gu::BVHNode& node, PxI32)
|
||||
{
|
||||
if (distancePointBoxSquared(node.mBV, mQueryPoint) >= mClosestDistanceSquared)
|
||||
return Gu::TraversalControl::eDontGoDeeper;
|
||||
|
||||
if (node.isLeaf())
|
||||
{
|
||||
const PxI32 j = node.getPrimitiveIndex();
|
||||
const PxU32* tri = &mTriangles[3 * j];
|
||||
|
||||
|
||||
aos::FloatV t1, t2;
|
||||
aos::Vec3V q = V3LoadU(mQueryPoint);
|
||||
aos::Vec3V a = V3LoadU(mPoints[tri[0]]);
|
||||
aos::Vec3V b = V3LoadU(mPoints[tri[1]]);
|
||||
aos::Vec3V c = V3LoadU(mPoints[tri[2]]);
|
||||
aos::Vec3V cp;
|
||||
aos::FloatV d = Gu::distancePointTriangleSquared2UnitBox(q, a, b, c, t1, t2, cp);
|
||||
PxReal d2;
|
||||
FStore(d, &d2);
|
||||
PxVec3 closest;
|
||||
V3StoreU(cp, closest);
|
||||
|
||||
//const PxVec3 closest = closestPtPointTriangle2UnitBox(mQueryPoint, mPoints[tri[0]], mPoints[tri[1]], mPoints[tri[2]]);
|
||||
//PxReal d2 = (closest - mQueryPoint).magnitudeSquared();
|
||||
if (d2 < mClosestDistanceSquared)
|
||||
{
|
||||
mClosestDistanceSquared = d2;
|
||||
mClosestTriId = j;
|
||||
mClosestPoint = closest;
|
||||
}
|
||||
return Gu::TraversalControl::eDontGoDeeper;
|
||||
}
|
||||
|
||||
const Gu::BVHNode& nodePos = mNodes[node.getPosIndex()];
|
||||
const PxReal distSquaredPos = distancePointBoxSquared(nodePos.mBV, mQueryPoint);
|
||||
const Gu::BVHNode& nodeNeg = mNodes[node.getNegIndex()];
|
||||
const PxReal distSquaredNeg = distancePointBoxSquared(nodeNeg.mBV, mQueryPoint);
|
||||
|
||||
if (distSquaredPos < distSquaredNeg)
|
||||
{
|
||||
if (distSquaredPos < mClosestDistanceSquared)
|
||||
return Gu::TraversalControl::eGoDeeper;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (distSquaredNeg < mClosestDistanceSquared)
|
||||
return Gu::TraversalControl::eGoDeeperNegFirst;
|
||||
}
|
||||
return Gu::TraversalControl::eDontGoDeeper;
|
||||
}
|
||||
|
||||
PxI32 getClosestTriId() const { return mClosestTriId; }
|
||||
|
||||
void setClosestStart(const PxReal closestDistanceSquared, PxI32 closestTriangle, const PxVec3& closestPoint)
|
||||
{
|
||||
mClosestDistanceSquared = closestDistanceSquared;
|
||||
mClosestTriId = closestTriangle;
|
||||
mClosestPoint = closestPoint;
|
||||
}
|
||||
|
||||
private:
|
||||
PX_NOCOPY(ClosestDistanceToTrimeshTraversalController)
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace Gu
|
||||
}
|
||||
|
||||
#endif // GU_AABBTREE_H
|
||||
Reference in New Issue
Block a user