diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/mesh/GuMidphaseBV4.cpp | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/GeomUtils/src/mesh/GuMidphaseBV4.cpp')
| -rw-r--r-- | PhysX_3.4/Source/GeomUtils/src/mesh/GuMidphaseBV4.cpp | 999 |
1 files changed, 999 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/mesh/GuMidphaseBV4.cpp b/PhysX_3.4/Source/GeomUtils/src/mesh/GuMidphaseBV4.cpp new file mode 100644 index 00000000..1cab487f --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/mesh/GuMidphaseBV4.cpp @@ -0,0 +1,999 @@ +// This code contains NVIDIA Confidential Information and is disclosed to you +// under a form of NVIDIA software license agreement provided separately to you. +// +// Notice +// NVIDIA Corporation and its licensors retain all intellectual property and +// proprietary rights in and to this software and related documentation and +// any modifications thereto. Any use, reproduction, disclosure, or +// distribution of this software and related documentation without an express +// license agreement from NVIDIA Corporation is strictly prohibited. +// +// ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES +// NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO +// THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, +// MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Information and code furnished is believed to be accurate and reliable. +// However, NVIDIA Corporation assumes no responsibility for the consequences of use of such +// information or for any infringement of patents or other rights of third parties that may +// result from its use. No license is granted by implication or otherwise under any patent +// or patent rights of NVIDIA Corporation. Details are subject to change without notice. +// This code supersedes and replaces all information previously supplied. +// NVIDIA Corporation products are not authorized for use as critical +// components in life support devices or systems without express written approval of +// NVIDIA Corporation. +// +// Copyright (c) 2008-2016 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 "PsVecMath.h" +using namespace physx::shdfnd::aos; + +#include "GuSweepMesh.h" +#include "GuBV4Build.h" +#include "GuBV4_Common.h" +#include "GuSphere.h" +#include "GuCapsule.h" +#include "GuBoxConversion.h" +#include "GuConvexUtilsInternal.h" +#include "GuVecTriangle.h" +#include "GuIntersectionTriangleBox.h" +#include "GuIntersectionCapsuleTriangle.h" +#include "GuIntersectionRayBox.h" +#include "PxTriangleMeshGeometry.h" +#include "CmScaling.h" +#include "GuTriangleMeshBV4.h" + +// This file contains code specific to the BV4 midphase. + +// PT: TODO: revisit/inline static sweep functions (TA34704) + +using namespace physx; +using namespace Gu; +using namespace Cm; + +#if PX_INTEL_FAMILY +Ps::IntBool BV4_RaycastSingle (const PxVec3& origin, const PxVec3& dir, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxRaycastHit* PX_RESTRICT hit, float maxDist, float geomEpsilon, PxU32 flags, PxHitFlags hitFlags); +PxU32 BV4_RaycastAll (const PxVec3& origin, const PxVec3& dir, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxRaycastHit* PX_RESTRICT hits, PxU32 maxNbHits, float maxDist, float geomEpsilon, PxU32 flags, PxHitFlags hitFlags); +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); + +Ps::IntBool BV4_OverlapSphereAny (const Sphere& sphere, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned); +PxU32 BV4_OverlapSphereAll (const Sphere& sphere, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxU32* results, PxU32 size, bool& overflow); +void BV4_OverlapSphereCB (const Sphere& sphere, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, MeshOverlapCallback callback, void* userData); + +Ps::IntBool BV4_OverlapBoxAny (const Box& box, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned); +PxU32 BV4_OverlapBoxAll (const Box& box, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxU32* results, PxU32 size, bool& overflow); +void BV4_OverlapBoxCB (const Box& box, const BV4Tree& tree, MeshOverlapCallback callback, void* userData); + +Ps::IntBool BV4_OverlapCapsuleAny (const Capsule& capsule, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned); +PxU32 BV4_OverlapCapsuleAll (const Capsule& capsule, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, PxU32* results, PxU32 size, bool& overflow); +void BV4_OverlapCapsuleCB (const Capsule& capsule, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, MeshOverlapCallback callback, void* userData); + +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); +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); + +Ps::IntBool 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); +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); + +Ps::IntBool BV4_CapsuleSweepSingle (const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags); +Ps::IntBool BV4_CapsuleSweepSingleAA(const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree& tree, SweepHit* PX_RESTRICT hit, PxU32 flags); +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); +void BV4_CapsuleSweepAACB (const Capsule& capsule, const PxVec3& dir, float maxDist, const BV4Tree& tree, const PxMat44* PX_RESTRICT worldm_Aligned, SweepUnlimitedCallback callback, void* userData, PxU32 flags); + +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); +void BV4_GenericSweepCB (const Box& box, const PxVec3& dir, float maxDist, const BV4Tree& tree, MeshSweepCallback callback, void* userData, bool anyHit); + +static PX_FORCE_INLINE void setIdentity(PxMat44& m) +{ + m.column0 = PxVec4(1.0f, 0.0f, 0.0f, 0.0f); + m.column1 = PxVec4(0.0f, 1.0f, 0.0f, 0.0f); + m.column2 = PxVec4(0.0f, 0.0f, 1.0f, 0.0f); + m.column3 = PxVec4(0.0f, 0.0f, 0.0f, 1.0f); +} + +static PX_FORCE_INLINE void setRotation(PxMat44& m, const PxQuat& q) +{ + const PxReal x = q.x; + const PxReal y = q.y; + const PxReal z = q.z; + const PxReal w = q.w; + + const PxReal x2 = x + x; + const PxReal y2 = y + y; + const PxReal z2 = z + z; + + const PxReal xx = x2*x; + const PxReal yy = y2*y; + const PxReal zz = z2*z; + + const PxReal xy = x2*y; + const PxReal xz = x2*z; + const PxReal xw = x2*w; + + const PxReal yz = y2*z; + const PxReal yw = y2*w; + const PxReal zw = z2*w; + + m.column0 = PxVec4(1.0f - yy - zz, xy + zw, xz - yw, 0.0f); + m.column1 = PxVec4(xy - zw, 1.0f - xx - zz, yz + xw, 0.0f); + m.column2 = PxVec4(xz + yw, yz - xw, 1.0f - xx - yy, 0.0f); +} + +#define IEEE_1_0 0x3f800000 //!< integer representation of 1.0 +static PX_FORCE_INLINE const PxMat44* setupWorldMatrix(PxMat44& world, const float* meshPos, const float* meshRot) +{ +// world = PxMat44(PxIdentity); + setIdentity(world); + + bool isIdt = true; + if(meshRot) + { + const PxU32* Bin = reinterpret_cast<const PxU32*>(meshRot); + if(Bin[0]!=0 || Bin[1]!=0 || Bin[2]!=0 || Bin[3]!=IEEE_1_0) + { +// const PxQuat Q(meshRot[0], meshRot[1], meshRot[2], meshRot[3]); +// world = PxMat44(Q); + setRotation(world, PxQuat(meshRot[0], meshRot[1], meshRot[2], meshRot[3])); + isIdt = false; + } + } + + if(meshPos) + { + const PxU32* Bin = reinterpret_cast<const PxU32*>(meshPos); + if(Bin[0]!=0 || Bin[1]!=0 || Bin[2]!=0) + { +// world.setPosition(PxVec3(meshPos[0], meshPos[1], meshPos[2])); + world.column3.x = meshPos[0]; + world.column3.y = meshPos[1]; + world.column3.z = meshPos[2]; + isIdt = false; + } + } + return isIdt ? NULL : &world; +} + +static PX_FORCE_INLINE PxU32 setupFlags(bool anyHit, bool doubleSided, bool meshBothSides) +{ + PxU32 flags = 0; + if(anyHit) + flags |= QUERY_MODIFIER_ANY_HIT; + if(doubleSided) + flags |= QUERY_MODIFIER_DOUBLE_SIDED; + if(meshBothSides) + flags |= QUERY_MODIFIER_MESH_BOTH_SIDES; + return flags; +} + +static Ps::IntBool boxSweepVsMesh(SweepHit& h, const BV4Tree& tree, const float* meshPos, const float* meshRot, const Box& box, const PxVec3& dir, float maxDist, bool anyHit, bool doubleSided, bool meshBothSides) +{ + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, meshPos, meshRot); + + const PxU32 flags = setupFlags(anyHit, doubleSided, meshBothSides); + return BV4_BoxSweepSingle(box, dir, maxDist, tree, TM, &h, flags); +} + +static Ps::IntBool sphereSweepVsMesh(SweepHit& h, const BV4Tree& tree, const PxVec3& center, float radius, const PxVec3& dir, float maxDist, const PxMat44* TM, const PxU32 flags) +{ + // PT: TODO: avoid this copy (TA34704) + const Sphere tmp(center, radius); + + return BV4_SphereSweepSingle(tmp, dir, maxDist, tree, TM, &h, flags); +} + +static bool capsuleSweepVsMesh(SweepHit& h, const BV4Tree& tree, const Capsule& capsule, const PxVec3& dir, float maxDist, const PxMat44* TM, const PxU32 flags) +{ + Capsule localCapsule; + computeLocalCapsule(localCapsule, capsule, TM); + + // PT: TODO: optimize + PxVec3 localDir, unused; + computeLocalRay(localDir, unused, dir, dir, TM); + + const PxVec3 capsuleDir = localCapsule.p1 - localCapsule.p0; + PxU32 nbNullComponents = 0; + const float epsilon = 1e-3f; + if(PxAbs(capsuleDir.x)<epsilon) + nbNullComponents++; + if(PxAbs(capsuleDir.y)<epsilon) + nbNullComponents++; + if(PxAbs(capsuleDir.z)<epsilon) + nbNullComponents++; + + // PT: TODO: consider passing TM to BV4_CapsuleSweepSingleXX just to do the final transforms there instead + // of below. It would make the parameters slightly inconsistent (local input + world TM) but it might make + // the code better overall, more aligned with the "unlimited results" version. + Ps::IntBool status; + if(nbNullComponents==2) + { + status = BV4_CapsuleSweepSingleAA(localCapsule, localDir, maxDist, tree, &h, flags); + } + else + { + status = BV4_CapsuleSweepSingle(localCapsule, localDir, maxDist, tree, &h, flags); + } + if(status && TM) + { + h.mPos = TM->transform(h.mPos); + h.mNormal = TM->rotate(h.mNormal); + } + return status!=0; +} + +static PX_FORCE_INLINE void boxSweepVsMeshCBOld(const BV4Tree& tree, const float* meshPos, const float* meshRot, const PxVec3& center, const PxVec3& extents, const PxVec3& dir, float maxDist, MeshSweepCallback callback, void* userData) +{ + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, meshPos, meshRot); + + BV4_GenericSweepCB_Old(center, extents, dir, maxDist, tree, TM, callback, userData); +} + +// + +static PX_FORCE_INLINE bool raycastVsMesh(PxRaycastHit& hitData, const BV4Tree& tree, const float* meshPos, const float* meshRot, const PxVec3& orig, const PxVec3& dir, float maxDist, float geomEpsilon, bool doubleSided, PxHitFlags hitFlags) +{ + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, meshPos, meshRot); + + const bool anyHit = hitFlags & PxHitFlag::eMESH_ANY; + const PxU32 flags = setupFlags(anyHit, doubleSided, false); + + if(!BV4_RaycastSingle(orig, dir, tree, TM, &hitData, maxDist, geomEpsilon, flags, hitFlags)) + return false; + + return true; +} + +/*static PX_FORCE_INLINE PxU32 raycastVsMeshAll(PxRaycastHit* hits, PxU32 maxNbHits, const BV4Tree& tree, const float* meshPos, const float* meshRot, const PxVec3& orig, const PxVec3& dir, float maxDist, float geomEpsilon, bool doubleSided, PxHitFlags hitFlags) +{ + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, meshPos, meshRot); + + const bool anyHit = hitFlags & PxHitFlag::eMESH_ANY; + const PxU32 flags = setupFlags(anyHit, doubleSided, false); + + return BV4_RaycastAll(orig, dir, tree, TM, hits, maxNbHits, maxDist, geomEpsilon, flags, hitFlags); +}*/ + +static PX_FORCE_INLINE void raycastVsMeshCB(const BV4Tree& tree, const PxVec3& orig, const PxVec3& dir, float maxDist, float geomEpsilon, bool doubleSided, MeshRayCallback callback, void* userData) +{ + const PxU32 flags = setupFlags(false, doubleSided, false); + BV4_RaycastCB(orig, dir, tree, NULL, maxDist, geomEpsilon, flags, callback, userData); +} + +struct BV4RaycastCBParams +{ + PX_FORCE_INLINE BV4RaycastCBParams( PxRaycastHit* hits, PxU32 maxHits, const PxMeshScale* scale, const PxTransform* pose, + const Cm::Matrix34* world2vertexSkew, PxU32 hitFlags, + const PxVec3& rayDir, bool isDoubleSided, float distCoeff) : + mDstBase (hits), + mHitNum (0), + mMaxHits (maxHits), + mScale (scale), + mPose (pose), + mWorld2vertexSkew (world2vertexSkew), + mHitFlags (hitFlags), + mRayDir (rayDir), + mIsDoubleSided (isDoubleSided), + mDistCoeff (distCoeff) + { + } + + PxRaycastHit* mDstBase; + PxU32 mHitNum; + PxU32 mMaxHits; + const PxMeshScale* mScale; + const PxTransform* mPose; + const Cm::Matrix34* mWorld2vertexSkew; + PxU32 mHitFlags; + const PxVec3& mRayDir; + bool mIsDoubleSided; + float mDistCoeff; + +private: + BV4RaycastCBParams& operator=(const BV4RaycastCBParams&); +}; + +static PX_FORCE_INLINE PxVec3 processLocalNormal(const Cm::Matrix34* PX_RESTRICT world2vertexSkew, const PxTransform* PX_RESTRICT pose, const PxVec3& localNormal, const PxVec3& rayDir, const bool isDoubleSided) +{ + PxVec3 normal; + if(world2vertexSkew) + normal = world2vertexSkew->rotateTranspose(localNormal); + else + normal = pose->rotate(localNormal); + 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(isDoubleSided && normal.dot(rayDir) > 0.0f) + normal = -normal; + return normal; +} + +static HitCode gRayCallback(void* userData, const PxVec3& lp0, const PxVec3& lp1, const PxVec3& lp2, PxU32 triangleIndex, float dist, float u, float v) +{ + BV4RaycastCBParams* params = reinterpret_cast<BV4RaycastCBParams*>(userData); + +//const bool last = params->mHitNum == params->mMaxHits; + + //not worth concatenating to do 1 transform: PxMat34Legacy vertex2worldSkew = scaling.getVertex2WorldSkew(absPose); + // PT: TODO: revisit this for N hits + PX_ALIGN_PREFIX(16) char buffer[sizeof(PxRaycastHit)] PX_ALIGN_SUFFIX(16); + PxRaycastHit& hit = reinterpret_cast<PxRaycastHit&>(buffer); +//PxRaycastHit& hit = last ? (PxRaycastHit&)buffer : params->mDstBase[params->mHitNum]; + + hit.distance = dist * params->mDistCoeff; + hit.u = u; + hit.v = v; + hit.faceIndex = triangleIndex; + + PxVec3 localImpact = (1.0f - u - v)*lp0 + u*lp1 + v*lp2; + if(params->mWorld2vertexSkew) + { + localImpact = params->mScale->transform(localImpact); + if(params->mScale->hasNegativeDeterminant()) + Ps::swap<PxReal>(hit.u, hit.v); // have to swap the UVs though since they were computed in mesh local space + } + + hit.position = params->mPose->transform(localImpact); + hit.flags = PxHitFlag::ePOSITION|PxHitFlag::eDISTANCE|PxHitFlag::eUV|PxHitFlag::eFACE_INDEX; + + PxVec3 normal(0.0f); + // Compute additional information if needed + if(params->mHitFlags & PxHitFlag::eNORMAL) + { + const PxVec3 localNormal = (lp1 - lp0).cross(lp2 - lp0); + normal = processLocalNormal(params->mWorld2vertexSkew, params->mPose, localNormal, params->mRayDir, params->mIsDoubleSided); + hit.flags |= PxHitFlag::eNORMAL; + } + hit.normal = normal; + + // PT: no callback => store results in provided buffer + if(params->mHitNum == params->mMaxHits) +// if(last) + return HIT_EXIT; + + params->mDstBase[params->mHitNum++] = hit; +// params->mHitNum++; + + return HIT_NONE; +} + +PxU32 physx::Gu::raycast_triangleMesh_BV4( const TriangleMesh* mesh, const PxTriangleMeshGeometry& meshGeom, const PxTransform& pose, + const PxVec3& rayOrigin, const PxVec3& rayDir, PxReal maxDist, + PxHitFlags hitFlags, PxU32 maxHits, PxRaycastHit* PX_RESTRICT hits) +{ + PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4TriangleMesh* meshData = static_cast<const BV4TriangleMesh*>(mesh); + + const bool multipleHits = (maxHits > 1); + const bool idtScale = meshGeom.scale.isIdentity(); + + const bool isDoubleSided = meshGeom.meshFlags.isSet(PxMeshGeometryFlag::eDOUBLE_SIDED); + const bool bothSides = isDoubleSided || (hitFlags & PxHitFlag::eMESH_BOTH_SIDES); + + const BV4Tree& tree = static_cast<const BV4TriangleMesh*>(meshData)->getBV4Tree(); + if(idtScale && !multipleHits) + { + bool b = raycastVsMesh(*hits, tree, &pose.p.x, &pose.q.x, rayOrigin, rayDir, maxDist, meshData->getGeomEpsilon(), bothSides, hitFlags); + if(b) + { + PxHitFlags dstFlags = PxHitFlag::ePOSITION|PxHitFlag::eDISTANCE|PxHitFlag::eUV|PxHitFlag::eFACE_INDEX; + + // PT: TODO: pass flags to BV4 code (TA34704) + if(hitFlags & PxHitFlag::eNORMAL) + { + dstFlags |= PxHitFlag::eNORMAL; + if(isDoubleSided) + { + PxVec3 normal = hits->normal; + // 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(normal.dot(rayDir) > 0.0f) + normal = -normal; + hits->normal = normal; + } + } + else + { + hits->normal = PxVec3(0.0f); + } + hits->flags = dstFlags; + } + return PxU32(b); + } + +/* + if(idtScale && multipleHits) + { + PxU32 nbHits = raycastVsMeshAll(hits, maxHits, tree, &pose.p.x, &pose.q.x, rayOrigin, rayDir, maxDist, meshData->getGeomEpsilon(), bothSides, hitFlags); + + return nbHits; + } +*/ + + //scaling: transform the ray to vertex space + PxVec3 orig, dir; + Cm::Matrix34 world2vertexSkew; + Cm::Matrix34* world2vertexSkewP = NULL; + PxReal distCoeff = 1.0f; + if(idtScale) + { + 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; + } + } + + if(!multipleHits) + { + bool b = raycastVsMesh(*hits, tree, NULL, NULL, orig, dir, maxDist, meshData->getGeomEpsilon(), bothSides, hitFlags); + if(b) + { + hits->distance *= distCoeff; + hits->position = pose.transform(meshGeom.scale.transform(hits->position)); + PxHitFlags dstFlags = PxHitFlag::ePOSITION|PxHitFlag::eDISTANCE|PxHitFlag::eUV|PxHitFlag::eFACE_INDEX; + + if(meshGeom.scale.hasNegativeDeterminant()) + Ps::swap<PxReal>(hits->u, hits->v); // have to swap the UVs though since they were computed in mesh local space + + // PT: TODO: pass flags to BV4 code (TA34704) + // Compute additional information if needed + if(hitFlags & PxHitFlag::eNORMAL) + { + dstFlags |= PxHitFlag::eNORMAL; + hits->normal = processLocalNormal(world2vertexSkewP, &pose, hits->normal, rayDir, isDoubleSided); + } + else + { + hits->normal = PxVec3(0.0f); + } + hits->flags = dstFlags; + } + return PxU32(b); + } + + BV4RaycastCBParams callback(hits, maxHits, &meshGeom.scale, &pose, world2vertexSkewP, hitFlags, rayDir, isDoubleSided, distCoeff); + + raycastVsMeshCB( static_cast<const BV4TriangleMesh*>(meshData)->getBV4Tree(), + orig, dir, + maxDist, meshData->getGeomEpsilon(), bothSides, + gRayCallback, &callback); + return callback.mHitNum; +} + +namespace +{ +struct IntersectShapeVsMeshCallback +{ + IntersectShapeVsMeshCallback(LimitedResults* results, bool flipNormal) : mResults(results), mAnyHits(false), mFlipNormal(flipNormal) {} + + LimitedResults* mResults; + bool mAnyHits; + bool mFlipNormal; + + PX_FORCE_INLINE bool recordHit(PxU32 faceIndex, Ps::IntBool hit) + { + if(hit) + { + mAnyHits = true; + if(mResults) + mResults->add(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 + } +}; + +// PT: TODO: get rid of this (TA34704) +struct IntersectSphereVsMeshCallback : IntersectShapeVsMeshCallback +{ + PX_FORCE_INLINE IntersectSphereVsMeshCallback(const PxMeshScale& meshScale, const PxTransform& meshTransform, const Sphere& sphere, LimitedResults* r, bool flipNormal) + : IntersectShapeVsMeshCallback(r, flipNormal) + { + mVertexToShapeSkew = meshScale.toMat33(); + mLocalCenter = meshTransform.transformInv(sphere.center); // sphereCenterInMeshSpace + mSphereRadius2 = sphere.radius*sphere.radius; + } + + PxMat33 mVertexToShapeSkew; + PxVec3 mLocalCenter; // PT: sphere center in local/mesh space + PxF32 mSphereRadius2; + + PX_FORCE_INLINE PxAgain processHit(PxU32 faceIndex, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2) + { + const Vec3V v0 = V3LoadU(mVertexToShapeSkew * av0); + const Vec3V v1 = V3LoadU(mVertexToShapeSkew * (mFlipNormal ? av2 : av1)); + const Vec3V v2 = V3LoadU(mVertexToShapeSkew * (mFlipNormal ? av1 : av2)); + + FloatV dummy1, dummy2; + Vec3V closestP; + PxReal dist2; + FStore(distancePointTriangleSquared(V3LoadU(mLocalCenter), v0, v1, v2, dummy1, dummy2, closestP), &dist2); + return recordHit(faceIndex, dist2 <= mSphereRadius2); + } +}; + +// PT: TODO: get rid of this (TA34704) +struct IntersectCapsuleVsMeshCallback : IntersectShapeVsMeshCallback +{ + PX_FORCE_INLINE IntersectCapsuleVsMeshCallback(const PxMeshScale& meshScale, const PxTransform& meshTransform, const Capsule& capsule, LimitedResults* r, bool flipNormal) + : IntersectShapeVsMeshCallback(r, flipNormal) + { + mVertexToShapeSkew = meshScale.toMat33(); + + // transform world capsule to mesh shape space + mLocalCapsule.p0 = meshTransform.transformInv(capsule.p0); + mLocalCapsule.p1 = meshTransform.transformInv(capsule.p1); + mLocalCapsule.radius = capsule.radius; + mParams.init(mLocalCapsule); + } + + PxMat33 mVertexToShapeSkew; + Capsule mLocalCapsule; // PT: capsule in mesh/local space + CapsuleTriangleOverlapData mParams; + + PX_FORCE_INLINE PxAgain processHit(PxU32 faceIndex, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2) + { + 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); + bool hit = intersectCapsuleTriangle(normal, v0, v1, v2, mLocalCapsule, mParams); + return recordHit(faceIndex, hit); + } +}; + +// PT: TODO: get rid of this (TA34704) +struct IntersectBoxVsMeshCallback : IntersectShapeVsMeshCallback +{ + PX_FORCE_INLINE IntersectBoxVsMeshCallback(const PxMeshScale& meshScale, const PxTransform& meshTransform, const Box& box, LimitedResults* r, bool flipNormal) + : IntersectShapeVsMeshCallback(r, flipNormal) + { + const PxMat33 vertexToShapeSkew = meshScale.toMat33(); + + // mesh scale needs to be included - inverse transform and optimize the box + const PxMat33 vertexToWorldSkew_Rot = PxMat33Padded(meshTransform.q) * vertexToShapeSkew; + const PxVec3& vertexToWorldSkew_Trans = meshTransform.p; + + Matrix34 tmp; + buildMatrixFromBox(tmp, box); + const Matrix34 inv = tmp.getInverseRT(); + const Matrix34 _vertexToWorldSkew(vertexToWorldSkew_Rot, vertexToWorldSkew_Trans); + + mVertexToBox = inv * _vertexToWorldSkew; + mBoxCenter = PxVec3(0.0f); + mBoxExtents = box.extents; // extents do not change + } + + Matrix34 mVertexToBox; + Vec3p mBoxExtents, mBoxCenter; + + PX_FORCE_INLINE PxAgain processHit(PxU32 faceIndex, const PxVec3& av0, const PxVec3& av1, const PxVec3& av2) + { + const Vec3p v0 = mVertexToBox.transform(av0); + const Vec3p v1 = mVertexToBox.transform(mFlipNormal ? av2 : av1); + const Vec3p v2 = mVertexToBox.transform(mFlipNormal ? av1 : av2); + + // PT: this one is safe because we're using Vec3p for all parameters + const Ps::IntBool hit = intersectTriangleBox_Unsafe(mBoxCenter, mBoxExtents, v0, v1, v2); + return recordHit(faceIndex, hit); + } +}; +} + +static bool gSphereVsMeshCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* /*vertexIndices*/) +{ + IntersectSphereVsMeshCallback* callback = reinterpret_cast<IntersectSphereVsMeshCallback*>(userData); + return !callback->processHit(triangleIndex, p0, p1, p2); +} + +static bool gCapsuleVsMeshCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* /*vertexIndices*/) +{ + IntersectCapsuleVsMeshCallback* callback = reinterpret_cast<IntersectCapsuleVsMeshCallback*>(userData); + return !callback->processHit(triangleIndex, p0, p1, p2); +} + +static bool gBoxVsMeshCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* /*vertexIndices*/) +{ + IntersectBoxVsMeshCallback* callback = reinterpret_cast<IntersectBoxVsMeshCallback*>(userData); + return !callback->processHit(triangleIndex, p0, p1, p2); +} + +bool physx::Gu::intersectSphereVsMesh_BV4(const Sphere& sphere, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results) +{ + PX_ASSERT(triMesh.getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4Tree& tree = static_cast<const BV4TriangleMesh&>(triMesh).getBV4Tree(); + + if(meshScale.isIdentity()) + { + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, &meshTransform.p.x, &meshTransform.q.x); + if(results) + { + const PxU32 nbResults = BV4_OverlapSphereAll(sphere, tree, TM, results->mResults, results->mMaxResults, results->mOverflow); + results->mNbResults = nbResults; + return nbResults!=0; + } + else + { + return BV4_OverlapSphereAny(sphere, tree, TM)!=0; + } + } + else + { + // PT: TODO: we don't need to use this callback here (TA34704) + IntersectSphereVsMeshCallback callback(meshScale, meshTransform, sphere, results, meshScale.hasNegativeDeterminant()); + + const Box worldOBB_(sphere.center, PxVec3(sphere.radius), PxMat33(PxIdentity)); + Box vertexOBB; + computeVertexSpaceOBB(vertexOBB, worldOBB_, meshTransform, meshScale); + + BV4_OverlapBoxCB(vertexOBB, tree, gSphereVsMeshCallback, &callback); + return callback.mAnyHits; + } +} + +bool physx::Gu::intersectBoxVsMesh_BV4(const Box& box, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results) +{ + PX_ASSERT(triMesh.getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4Tree& tree = static_cast<const BV4TriangleMesh&>(triMesh).getBV4Tree(); + + if(meshScale.isIdentity()) + { + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, &meshTransform.p.x, &meshTransform.q.x); + if(results) + { + const PxU32 nbResults = BV4_OverlapBoxAll(box, tree, TM, results->mResults, results->mMaxResults, results->mOverflow); + results->mNbResults = nbResults; + return nbResults!=0; + } + else + { + return BV4_OverlapBoxAny(box, tree, TM)!=0; + } + } + else + { + // PT: TODO: we don't need to use this callback here (TA34704) + IntersectBoxVsMeshCallback callback(meshScale, meshTransform, box, results, meshScale.hasNegativeDeterminant()); + + Box vertexOBB; // query box in vertex space + computeVertexSpaceOBB(vertexOBB, box, meshTransform, meshScale); + + BV4_OverlapBoxCB(vertexOBB, tree, gBoxVsMeshCallback, &callback); + return callback.mAnyHits; + } +} + +bool physx::Gu::intersectCapsuleVsMesh_BV4(const Capsule& capsule, const TriangleMesh& triMesh, const PxTransform& meshTransform, const PxMeshScale& meshScale, LimitedResults* results) +{ + PX_ASSERT(triMesh.getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4Tree& tree = static_cast<const BV4TriangleMesh&>(triMesh).getBV4Tree(); + + if(meshScale.isIdentity()) + { + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, &meshTransform.p.x, &meshTransform.q.x); + if(results) + { + const PxU32 nbResults = BV4_OverlapCapsuleAll(capsule, tree, TM, results->mResults, results->mMaxResults, results->mOverflow); + results->mNbResults = nbResults; + return nbResults!=0; + } + else + { + return BV4_OverlapCapsuleAny(capsule, tree, TM)!=0; + } + } + else + { + // PT: TODO: we don't need to use this callback here (TA34704) + IntersectCapsuleVsMeshCallback callback(meshScale, meshTransform, capsule, results, meshScale.hasNegativeDeterminant()); + + // make vertex space OBB + Box vertexOBB; + Box worldOBB_; + worldOBB_.create(capsule); // AP: potential optimization (meshTransform.inverse is already in callback.mCapsule) + computeVertexSpaceOBB(vertexOBB, worldOBB_, meshTransform, meshScale); + + BV4_OverlapBoxCB(vertexOBB, tree, gCapsuleVsMeshCallback, &callback); + return callback.mAnyHits; + } +} + +// PT: TODO: get rid of this (TA34704) +static bool gVolumeCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, const PxU32* vertexIndices) +{ + MeshHitCallback<PxRaycastHit>* callback = reinterpret_cast<MeshHitCallback<PxRaycastHit>*>(userData); + PX_ALIGN_PREFIX(16) char buffer[sizeof(PxRaycastHit)] PX_ALIGN_SUFFIX(16); + PxRaycastHit& hit = reinterpret_cast<PxRaycastHit&>(buffer); + hit.faceIndex = triangleIndex; + PxReal dummy; + return !callback->processHit(hit, p0, p1, p2, dummy, vertexIndices); +} + +void physx::Gu::intersectOBB_BV4(const TriangleMesh* mesh, const Box& obb, MeshHitCallback<PxRaycastHit>& callback, bool bothTriangleSidesCollide, bool checkObbIsAligned) +{ + PX_UNUSED(checkObbIsAligned); + PX_UNUSED(bothTriangleSidesCollide); + BV4_OverlapBoxCB(obb, static_cast<const BV4TriangleMesh*>(mesh)->getBV4Tree(), gVolumeCallback, &callback); +} + + + + +#include "GuVecCapsule.h" +#include "GuSweepMTD.h" + +static bool gCapsuleMeshSweepCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, /*const PxU32* vertexIndices,*/ float& dist) +{ + SweepCapsuleMeshHitCallback* callback = reinterpret_cast<SweepCapsuleMeshHitCallback*>(userData); + PxRaycastHit meshHit; + meshHit.faceIndex = triangleIndex; + return !callback->SweepCapsuleMeshHitCallback::processHit(meshHit, p0, p1, p2, dist, NULL/*vertexIndices*/); +} + +// PT: TODO: refactor/share bits of this (TA34704) +bool physx::Gu::sweepCapsule_MeshGeom_BV4( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose, + const Capsule& lss, const PxVec3& unitDir, const PxReal distance, + PxSweepHit& sweepHit, PxHitFlags hitFlags, const PxReal inflation) +{ + PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4TriangleMesh* meshData = static_cast<const BV4TriangleMesh*>(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; + + if(isIdentity) + { + const BV4Tree& tree = meshData->getBV4Tree(); + const bool anyHit = hitFlags & PxHitFlag::eMESH_ANY; + + BV4_ALIGN16(PxMat44 World); + const PxMat44* TM = setupWorldMatrix(World, &pose.p.x, &pose.q.x); + + const PxU32 flags = setupFlags(anyHit, isDoubleSided, meshBothSides!=0); + + SweepHit hitData; + if(lss.p0==lss.p1) + { + if(!sphereSweepVsMesh(hitData, tree, inflatedCapsule.p0, inflatedCapsule.radius, unitDir, distance, TM, flags)) + return false; + } + else + { + if(!capsuleSweepVsMesh(hitData, tree, inflatedCapsule, unitDir, distance, TM, flags)) + return false; + } + + sweepHit.distance = hitData.mDistance; + sweepHit.position = hitData.mPos; + sweepHit.normal = hitData.mNormal; + sweepHit.faceIndex = hitData.mTriangleID; + + if(hitData.mDistance==0.0f) + { + sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL; + + if(meshBothSides) + isDoubleSided = true; + + // PT: TODO: consider using 'setInitialOverlapResults' here + bool hasContacts = false; + if(hitFlags & PxHitFlag::eMTD) + { + const Vec3V p0 = V3LoadU(inflatedCapsule.p0); + const Vec3V p1 = V3LoadU(inflatedCapsule.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, inflatedCapsule.radius, isDoubleSided, sweepHit); + } + setupSweepHitForMTD(sweepHit, hasContacts, unitDir); + } + else + sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX; + return true; + } + + // 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 distCoef = 1.0f; + Matrix34 poseWithScale; + if(!isIdentity) + { + poseWithScale = pose * triMeshGeom.scale; + distance1 = computeSweepData(triMeshGeom, sweepOrigin, sweepExtents, sweepDir, distance); + distCoef = distance1 / distance; + } else + poseWithScale = Matrix34(pose); + + SweepCapsuleMeshHitCallback callback(sweepHit, poseWithScale, distance, isDoubleSided, inflatedCapsule, unitDir, hitFlags, triMeshGeom.scale.hasNegativeDeterminant(), distCoef); + + boxSweepVsMeshCBOld(meshData->getBV4Tree(), NULL, NULL, sweepOrigin, sweepExtents, sweepDir, distance1, gCapsuleMeshSweepCallback, &callback); + + if(meshBothSides) + isDoubleSided = true; + + return callback.finalizeHit(sweepHit, inflatedCapsule, triMeshGeom, pose, isDoubleSided); +} + +#include "GuSweepSharedTests.h" +static bool gBoxMeshSweepCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, /*const PxU32* vertexIndices,*/ float& dist) +{ + SweepBoxMeshHitCallback* callback = reinterpret_cast<SweepBoxMeshHitCallback*>(userData); + PxRaycastHit meshHit; + meshHit.faceIndex = triangleIndex; + return !callback->SweepBoxMeshHitCallback::processHit(meshHit, p0, p1, p2, dist, NULL/*vertexIndices*/); +} + +// PT: TODO: refactor/share bits of this (TA34704) +bool physx::Gu::sweepBox_MeshGeom_BV4( const TriangleMesh* mesh, const PxTriangleMeshGeometry& triMeshGeom, const PxTransform& pose, + const Box& box, const PxVec3& unitDir, const PxReal distance, + PxSweepHit& sweepHit, PxHitFlags hitFlags, const PxReal inflation) +{ + PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4TriangleMesh* meshData = static_cast<const BV4TriangleMesh*>(mesh); + + const bool isIdentity = triMeshGeom.scale.isIdentity(); + + const bool meshBothSides = hitFlags & PxHitFlag::eMESH_BOTH_SIDES; + const bool isDoubleSided = triMeshGeom.meshFlags & PxMeshGeometryFlag::eDOUBLE_SIDED; + + if(isIdentity && inflation==0.0f) + { + const bool anyHit = hitFlags & PxHitFlag::eMESH_ANY; + + // PT: TODO: this is wrong, we shouldn't actually sweep the inflated version +// const PxVec3 inflated = (box.extents + PxVec3(inflation)) * 1.01f; + // PT: TODO: avoid this copy +// const Box tmp(box.center, inflated, box.rot); + + SweepHit hitData; +// if(!boxSweepVsMesh(hitData, meshData->getBV4Tree(), &pose.p.x, &pose.q.x, tmp, unitDir, distance, anyHit, isDoubleSided, meshBothSides)) + if(!boxSweepVsMesh(hitData, meshData->getBV4Tree(), &pose.p.x, &pose.q.x, box, unitDir, distance, anyHit, isDoubleSided, meshBothSides)) + return false; + + sweepHit.distance = hitData.mDistance; + sweepHit.position = hitData.mPos; + sweepHit.normal = hitData.mNormal; + sweepHit.faceIndex = hitData.mTriangleID; + + if(hitData.mDistance==0.0f) + { + sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL; + + const bool bothTriangleSidesCollide = isDoubleSided || meshBothSides; + const PxTransform boxTransform = box.getTransform(); + + bool hasContacts = false; + if(hitFlags & PxHitFlag::eMTD) + hasContacts = computeBox_TriangleMeshMTD(triMeshGeom, pose, box, boxTransform, inflation, bothTriangleSidesCollide, sweepHit); + + setupSweepHitForMTD(sweepHit, hasContacts, unitDir); + } + else + { + sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL | PxHitFlag::eFACE_INDEX; + } + return true; + } + + // PT: TODO: revisit this codepath, we don't need to sweep an AABB all the time (TA34704) + + Matrix34 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 = Matrix34(pose); + PxMat33 worldToMeshRot(pose.q.getConjugate()); // extract rotation matrix from pose.q + meshSpaceOrigin = worldToMeshRot.transform(box.center - pose.p); + meshSpaceDir = worldToMeshRot.transform(unitDir) * distance; + 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) * triMeshGeom.scale.toMat33(); + 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 Matrix34 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 + Matrix34 worldToBox; + computeWorldToBoxMatrix(worldToBox, box); + + const bool bothTriangleSidesCollide = isDoubleSided || meshBothSides; + + const Matrix34Padded meshToBox = worldToBox*meshToWorldSkew; + const PxTransform boxTransform = box.getTransform(); // PT: TODO: this is not needed when there's no hit (TA34704) + + 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); + + const PxVec3 dir = meshSpaceDir/dirLen; + boxSweepVsMeshCBOld(meshData->getBV4Tree(), NULL, NULL, meshSpaceOrigin, sweptAABBMeshSpaceExtents, dir, dirLen, gBoxMeshSweepCallback, &callback); + + return callback.finalizeHit(sweepHit, triMeshGeom, pose, boxTransform, localDir, meshBothSides, isDoubleSided); +} + +static bool gConvexVsMeshSweepCallback(void* userData, const PxVec3& p0, const PxVec3& p1, const PxVec3& p2, PxU32 triangleIndex, /*const PxU32* vertexIndices,*/ float& dist) +{ + SweepConvexMeshHitCallback* callback = reinterpret_cast<SweepConvexMeshHitCallback*>(userData); + PX_ALIGN_PREFIX(16) char buffer[sizeof(PxRaycastHit)] PX_ALIGN_SUFFIX(16); + PxRaycastHit& hit = reinterpret_cast<PxRaycastHit&>(buffer); + hit.faceIndex = triangleIndex; + return !callback->SweepConvexMeshHitCallback::processHit(hit, p0, p1, p2, dist, NULL/*vertexIndices*/); +} + +void physx::Gu::sweepConvex_MeshGeom_BV4(const TriangleMesh* mesh, const Box& hullBox, const PxVec3& localDir, const PxReal distance, SweepConvexMeshHitCallback& callback, bool anyHit) +{ + PX_ASSERT(mesh->getConcreteType()==PxConcreteType::eTRIANGLE_MESH_BVH34); + const BV4TriangleMesh* meshData = static_cast<const BV4TriangleMesh*>(mesh); + BV4_GenericSweepCB(hullBox, localDir, distance, meshData->getBV4Tree(), gConvexVsMeshSweepCallback, &callback, anyHit); +} + +#endif + |