GRK-Projekt/dependencies/physx-4.1/source/geomutils/src/mesh/GuBV4_SphereSweep.cpp

387 lines
12 KiB
C++
Raw Normal View History

2021-12-27 11:28:19 +01:00
//
// 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-2019 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 "GuSIMDHelpers.h"
#include "GuSweepSphereTriangle.h"
using namespace physx;
using namespace Gu;
#if PX_INTEL_FAMILY && !defined(PX_SIMD_DISABLED)
#include "PsVecMath.h"
using namespace physx::shdfnd::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(Vec3p mCenterOrMinCoeff_PaddedAligned);
BV4_ALIGN16(Vec3p mExtentsOrMaxCoeff_PaddedAligned);
#ifndef GU_BV4_USE_SLABS
BV4_ALIGN16(Vec3p mData2_PaddedAligned);
BV4_ALIGN16(Vec3p mFDir_PaddedAligned);
BV4_ALIGN16(Vec3p mData_PaddedAligned);
#endif
BV4_ALIGN16(Vec3p mLocalDir_Padded); // PT: TODO: this one could be switched to PaddedAligned & V4LoadA (TA34704)
BV4_ALIGN16(Vec3p 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;
};
}
#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 distEpsilon = GU_EPSILON_SAME_DISTANCE; // pick a farther hit within distEpsilon that is more opposing than the previous closest hit
const PxReal alignmentValue = computeAlignmentValue(normal, params->mLocalDir_Padded);
if(keepTriangle(dist, alignmentValue, params->mBestDistance, params->mBestAlignmentValue, params->mMaxDist, distEpsilon))
{
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, dist, params->mOrigin_Padded, params->mLocalDir_Padded);
#endif
}
return true;
}
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 Ps::IntBool 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 TrianglePadded& 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"
Ps::IntBool 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 = 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 Ps::IntBool 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 terrible 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 = 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 = 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);
}
}
#endif