aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/mesh/GuSweepsMesh.cpp
diff options
context:
space:
mode:
authorgit perforce import user <a@b>2016-10-25 12:29:14 -0600
committerSheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees>2016-10-25 18:56:37 -0500
commit3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch)
treefa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/mesh/GuSweepsMesh.cpp
downloadphysx-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/GuSweepsMesh.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/mesh/GuSweepsMesh.cpp602
1 files changed, 602 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/mesh/GuSweepsMesh.cpp b/PhysX_3.4/Source/GeomUtils/src/mesh/GuSweepsMesh.cpp
new file mode 100644
index 00000000..6efb85db
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/mesh/GuSweepsMesh.cpp
@@ -0,0 +1,602 @@
+// 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 "GuSweepTests.h"
+#include "GuSweepMesh.h"
+#include "GuInternal.h"
+#include "GuConvexUtilsInternal.h"
+#include "CmScaling.h"
+#include "GuVecShrunkBox.h"
+#include "GuSweepMTD.h"
+#include "GuVecCapsule.h"
+#include "GuSweepBoxTriangle_SAT.h"
+#include "GuSweepCapsuleTriangle.h"
+#include "GuSweepSphereTriangle.h"
+#include "GuDistancePointTriangle.h"
+#include "GuCapsule.h"
+
+using namespace physx;
+using namespace Gu;
+using namespace Cm;
+using namespace physx::shdfnd::aos;
+
+#include "GuSweepConvexTri.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool sweepSphereTriangle(const PxTriangle& tri,
+ const PxVec3& center, PxReal radius,
+ const PxVec3& unitDir, const PxReal distance,
+ PxSweepHit& 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 mode, const PxHitFlags& hitFlags, bool flipNormal, float distCoef) :
+ MeshHitCallback<PxRaycastHit> (mode),
+ mHitFlags (hitFlags),
+ mStatus (false),
+ mInitialOverlap (false),
+ mFlipNormal (flipNormal),
+ mDistCoeff (distCoef)
+{
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SweepCapsuleMeshHitCallback::SweepCapsuleMeshHitCallback(
+ PxSweepHit& sweepHit, const Matrix34& 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 PxRaycastHit& 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));
+
+ PxSweepHit 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, distEpsilon))
+ {
+ 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::eMESH_ANY)
+ return false; // abort traversal
+ }
+ return true;
+}
+
+bool SweepCapsuleMeshHitCallback::finalizeHit( PxSweepHit& 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
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL | PxHitFlag::ePOSITION | PxHitFlag::eFACE_INDEX;
+ }
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool sweepCapsule_MeshGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
+{
+ 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 Matrix34Padded& 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 Matrix34Padded& meshToBox, PxReal distance, bool bothTriangleSidesCollide,
+ const Box& box, const PxVec3& localMotion, const PxVec3& localDir, const PxVec3& unitDir,
+ const PxHitFlags& hitFlags, const 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 PxRaycastHit& 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
+ LocalConvex<TriangleV> convexA(triangleV);
+ 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( PxSweepHit& 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::eDISTANCE | 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 PsTransformV 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(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, const PxReal distance, PxHitFlags hitFlags, const bool bothTriangleSidesCollide, const PxReal inflation,
+ const 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 PsTransformV meshPoseV(p0, q0);
+ const PsTransformV 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 PxRaycastHit& 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( PxSweepHit& 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);
+ 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, Matrix34(convexPose), Matrix34(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::eMESH_ANY;
+ 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);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+