aboutsummaryrefslogtreecommitdiff
path: root/PhysX_3.4/Source/GeomUtils/src/GuSweepSharedTests.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/GuSweepSharedTests.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/GuSweepSharedTests.cpp')
-rw-r--r--PhysX_3.4/Source/GeomUtils/src/GuSweepSharedTests.cpp726
1 files changed, 726 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/GuSweepSharedTests.cpp b/PhysX_3.4/Source/GeomUtils/src/GuSweepSharedTests.cpp
new file mode 100644
index 00000000..162de3f5
--- /dev/null
+++ b/PhysX_3.4/Source/GeomUtils/src/GuSweepSharedTests.cpp
@@ -0,0 +1,726 @@
+// 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 "GuHeightFieldUtil.h"
+#include "CmScaling.h"
+#include "GuConvexMesh.h"
+#include "GuIntersectionRayPlane.h"
+#include "GuVecBox.h"
+#include "GuVecShrunkBox.h"
+#include "GuVecCapsule.h"
+#include "GuVecConvexHull.h"
+#include "GuSweepMTD.h"
+#include "PxConvexMeshGeometry.h"
+#include "PxSphereGeometry.h"
+#include "GuSweepSphereCapsule.h"
+#include "GuSweepCapsuleCapsule.h"
+#include "GuSweepTriangleUtils.h"
+#include "GuSweepCapsuleTriangle.h"
+#include "GuInternal.h"
+#include "GuGJKRaycast.h"
+
+using namespace physx;
+using namespace Gu;
+using namespace Cm;
+using namespace physx::shdfnd::aos;
+
+static const PxReal gEpsilon = .01f;
+
+static PxU32 computeSweepConvexPlane(
+ const PxConvexMeshGeometry& convexGeom, ConvexHullData* hullData, const PxU32& nbPolys, const PxTransform& pose,
+ const PxVec3& impact_, const PxVec3& unitDir)
+{
+ PX_ASSERT(nbPolys);
+
+ const PxVec3 impact = impact_ - unitDir * gEpsilon;
+
+ const PxVec3 localPoint = pose.transformInv(impact);
+ const PxVec3 localDir = pose.rotateInv(unitDir);
+
+ const FastVertex2ShapeScaling scaling(convexGeom.scale);
+
+ PxU32 minIndex = 0;
+ PxReal minD = PX_MAX_REAL;
+ for(PxU32 j=0; j<nbPolys; j++)
+ {
+ const PxPlane& pl = hullData->mPolygons[j].mPlane;
+
+ PxPlane plane;
+ scaling.transformPlaneToShapeSpace(pl.n, pl.d, plane.n, plane.d);
+
+ PxReal d = plane.distance(localPoint);
+ if(d<0.0f)
+ continue;
+
+ const PxReal tweak = plane.n.dot(localDir) * gEpsilon;
+ d += tweak;
+
+ if(d<minD)
+ {
+ minIndex = j;
+ minD = d;
+ }
+ }
+ return minIndex;
+}
+
+static PX_FORCE_INLINE bool computeFaceIndex(PxSweepHit& sweepHit, const PxHitFlags hitFlags, const PxConvexMeshGeometry& convexGeom, ConvexHullData* hullData, const PxTransform& pose, const PxVec3& unitDir)
+{
+ if(hitFlags & PxHitFlag::eFACE_INDEX)
+ {
+ // PT: compute closest polygon using the same tweak as in swept-capsule-vs-mesh
+ sweepHit.faceIndex = computeSweepConvexPlane(convexGeom, hullData, hullData->mNbPolygons, pose, sweepHit.position, unitDir);
+ sweepHit.flags |= PxHitFlag::eFACE_INDEX;
+ }
+ return true;
+}
+
+static PX_FORCE_INLINE bool hasInitialOverlap(PxSweepHit& sweepHit, const PxVec3& unitDir,
+ const FloatVArg toi,
+ const Vec3VArg normal, const Vec3VArg closestA,
+ const PsTransformV& convexPose,
+ const bool isMtd, const bool impactPointOnTheOtherShape)
+{
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL;
+
+ const FloatV zero = FZero();
+ if(FAllGrtrOrEq(zero, toi))
+ {
+ //ML: initial overlap
+ if(isMtd)
+ {
+ sweepHit.flags |= PxHitFlag::ePOSITION;
+ const FloatV length = toi;
+ const Vec3V worldPointA = convexPose.transform(closestA);
+ const Vec3V worldNormal = V3Normalize(convexPose.rotate(normal));
+ if(impactPointOnTheOtherShape)
+ {
+ const Vec3V destWorldPointA = V3NegScaleSub(worldNormal, length, worldPointA);
+ V3StoreU(worldNormal, sweepHit.normal);
+ V3StoreU(destWorldPointA, sweepHit.position);
+ }
+ else
+ {
+ const Vec3V destNormal = V3Neg(worldNormal);
+ V3StoreU(destNormal, sweepHit.normal);
+ V3StoreU(worldPointA, sweepHit.position);
+ }
+ FStore(length, &sweepHit.distance);
+ }
+ else
+ {
+ sweepHit.distance = 0.0f;
+ sweepHit.normal = -unitDir;
+ }
+ sweepHit.faceIndex = 0xffffffff;
+ return true;
+ }
+ return false;
+}
+
+///////////////////////////////////////////////// sweepCapsule/Sphere //////////////////////////////////////////////////////
+bool sweepCapsule_SphereGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
+{
+ PX_UNUSED(capsuleGeom_);
+ PX_UNUSED(capsulePose_);
+
+ PX_ASSERT(geom.getType() == PxGeometryType::eSPHERE);
+ const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom);
+
+ const Sphere sphere(pose.p, sphereGeom.radius+inflation);
+
+ if(!sweepSphereCapsule(sphere, lss, -unitDir, distance, sweepHit.distance, sweepHit.position, sweepHit.normal, hitFlags))
+ return false;
+
+ const bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ if(isMtd)
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+
+ if(sweepHit.distance == 0.f)
+ {
+ //intialOverlap
+ if(lss.p0 == lss.p1)
+ {
+ //sphere
+ return computeSphere_SphereMTD(sphere, Sphere(lss.p0, lss.radius), sweepHit);
+ }
+ else
+ {
+ //capsule
+ return computeSphere_CapsuleMTD(sphere, lss, sweepHit);
+ }
+ }
+ }
+ else
+ {
+ if(sweepHit.distance!=0.0f)
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+ else
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL;
+ }
+ return true;
+}
+
+bool sweepCapsule_PlaneGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
+{
+ PX_UNUSED(capsuleGeom_);
+ PX_UNUSED(capsulePose_);
+
+ PX_ASSERT(geom.getType() == PxGeometryType::ePLANE);
+ PX_UNUSED(geom);
+// const PxPlaneGeometry& planeGeom = static_cast<const PxPlaneGeometry&>(geom);
+
+ const PxPlane& worldPlane = getPlane(pose);
+
+ const PxF32 capsuleRadius = lss.radius + inflation;
+
+ PxU32 index = 0;
+ PxVec3 pts[2];
+
+ PxReal minDp = PX_MAX_REAL;
+
+ sweepHit.faceIndex = 0xFFFFffff; // spec says face index is undefined for planes
+
+ // Find extreme point on the capsule
+ // AP: removed if (lss.p0 == lss.p1 clause because it wasn't properly computing minDp)
+ pts[0] = lss.p0;
+ pts[1] = lss.p1;
+ for(PxU32 i=0; i<2; i++)
+ {
+ const PxReal dp = pts[i].dot(worldPlane.n);
+ if(dp<minDp)
+ {
+ minDp = dp;
+ index = i;
+ }
+ }
+
+ const bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ if(isMtd)
+ {
+ //initial overlap with the plane
+ if(minDp <= capsuleRadius - worldPlane.d)
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE|PxHitFlag::eNORMAL| PxHitFlag::ePOSITION;
+ return computePlane_CapsuleMTD(worldPlane, lss, sweepHit);
+ }
+ }
+ else
+ {
+ if(!(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP))
+ {
+ // test if the capsule initially overlaps with plane
+ if(minDp <= capsuleRadius - worldPlane.d)
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE|PxHitFlag::eNORMAL;
+ sweepHit.distance = 0.0f;
+ sweepHit.normal = -unitDir;
+ return true;
+ }
+ }
+ }
+
+ const PxVec3 ptOnCapsule = pts[index] - worldPlane.n*capsuleRadius;
+
+ // Raycast extreme vertex against plane
+ bool hitPlane = intersectRayPlane(ptOnCapsule, unitDir, worldPlane, sweepHit.distance, &sweepHit.position);
+ if(hitPlane && sweepHit.distance > 0 && sweepHit.distance <= distance)
+ {
+ sweepHit.normal = worldPlane.n;
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+ return true;
+ }
+ return false;
+}
+
+bool sweepCapsule_CapsuleGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
+{
+ PX_UNUSED(capsuleGeom_);
+ PX_UNUSED(capsulePose_);
+
+ PX_ASSERT(geom.getType() == PxGeometryType::eCAPSULE);
+ const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom);
+
+ Capsule staticCapsule;
+ getCapsule(staticCapsule, capsuleGeom, pose);
+ staticCapsule.radius +=inflation;
+
+ const bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ PxU16 outFlags;
+ if(!sweepCapsuleCapsule(lss, staticCapsule, -unitDir, distance, sweepHit.distance, sweepHit.position, sweepHit.normal, hitFlags, outFlags))
+ return false;
+
+ sweepHit.flags = PxHitFlags(outFlags);
+ if(sweepHit.distance == 0.0f)
+ {
+ //initial overlap
+ if(isMtd)
+ {
+ sweepHit.flags |= PxHitFlag::ePOSITION;
+ return computeCapsule_CapsuleMTD(lss, staticCapsule, sweepHit);
+ }
+ }
+ return true;
+}
+
+bool sweepCapsule_ConvexGeom(GU_CAPSULE_SWEEP_FUNC_PARAMS)
+{
+ PX_ASSERT(geom.getType() == PxGeometryType::eCONVEXMESH);
+
+ using namespace Ps::aos;
+
+ PX_ASSERT(geom.getType() == PxGeometryType::eCONVEXMESH);
+ const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom);
+
+ ConvexMesh* convexMesh = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+ ConvexHullData* hullData = &convexMesh->getHull();
+
+ const Vec3V zeroV = V3Zero();
+ const FloatV zero = FZero();
+ const FloatV dist = FLoad(distance);
+ const Vec3V worldDir = V3LoadU(unitDir);
+
+ const PsTransformV capPose = loadTransformU(capsulePose_);
+ const PsTransformV convexPose = loadTransformU(pose);
+
+ const PsMatTransformV aToB(convexPose.transformInv(capPose));
+
+ const FloatV capsuleHalfHeight = FLoad(capsuleGeom_.halfHeight);
+ const FloatV capsuleRadius = FLoad(lss.radius);
+
+ const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
+
+ CapsuleV capsule(aToB.p, aToB.rotate( V3Scale(V3UnitX(), capsuleHalfHeight)), capsuleRadius);
+ ConvexHullV convexHull(hullData, zeroV, vScale, vQuat, convexGeom.scale.isIdentity());
+
+ const Vec3V dir = convexPose.rotateInv(V3Neg(V3Scale(worldDir, dist)));
+
+ bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ FloatV toi;
+ Vec3V closestA, normal;//closestA and normal is in the local space of convex hull
+ LocalConvex<CapsuleV> convexA(capsule);
+ LocalConvex<ConvexHullV> convexB(convexHull);
+ const Vec3V initialSearchDir = V3Sub(capsule.getCenter(), convexHull.getCenter());
+ if(!gjkRaycastPenetration< LocalConvex<CapsuleV>, LocalConvex<ConvexHullV> >(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, lss.radius + inflation, isMtd))
+ return false;
+
+ if(hasInitialOverlap(sweepHit, unitDir, toi, normal, closestA, convexPose, isMtd, true))
+ return true;
+
+ sweepHit.flags |= PxHitFlag::ePOSITION;
+ const Vec3V worldPointA = convexPose.transform(closestA);
+ const FloatV length = FMul(dist, toi);
+ const Vec3V destNormal = V3Normalize(convexPose.rotate(normal));
+ const Vec3V destWorldPointA = V3ScaleAdd(worldDir, length, worldPointA);
+ V3StoreU(destNormal, sweepHit.normal);
+ V3StoreU(destWorldPointA, sweepHit.position);
+ FStore(length, &sweepHit.distance);
+
+ return computeFaceIndex(sweepHit, hitFlags, convexGeom, hullData, pose, unitDir);
+}
+
+///////////////////////////////////////////////// sweepBox //////////////////////////////////////////////////////
+
+bool sweepBox_PlaneGeom(GU_BOX_SWEEP_FUNC_PARAMS)
+{
+ PX_ASSERT(geom.getType() == PxGeometryType::ePLANE);
+ PX_UNUSED(geom);
+ PX_UNUSED(boxPose_);
+ PX_UNUSED(boxGeom_);
+
+// const PxPlaneGeometry& planeGeom = static_cast<const PxPlaneGeometry&>(geom);
+
+ sweepHit.faceIndex = 0xFFFFffff; // spec says face index is undefined for planes
+
+ PxPlane worldPlane = getPlane(pose);
+ worldPlane.d -=inflation;
+
+ // Find extreme point on the box
+ PxVec3 boxPts[8];
+ box.computeBoxPoints(boxPts);
+ PxU32 index = 0;
+ PxReal minDp = PX_MAX_REAL;
+ for(PxU32 i=0;i<8;i++)
+ {
+ const PxReal dp = boxPts[i].dot(worldPlane.n);
+
+ if(dp<minDp)
+ {
+ minDp = dp;
+ index = i;
+ }
+ }
+
+ bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ if(isMtd)
+ {
+ // test if box initially overlap with plane
+ if(minDp <= -worldPlane.d)
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+ //compute Mtd;
+ return computePlane_BoxMTD(worldPlane, box, sweepHit);
+ }
+ }
+ else
+ {
+ if(!(hitFlags & PxHitFlag::eASSUME_NO_INITIAL_OVERLAP))
+ {
+ // test if box initially overlap with plane
+ if(minDp <= -worldPlane.d)
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE|PxHitFlag::eNORMAL;
+ sweepHit.distance = 0.0f;
+ sweepHit.normal = -unitDir;
+ return true;
+ }
+ }
+ }
+
+ // Raycast extreme vertex against plane
+ bool hitPlane = intersectRayPlane(boxPts[index], unitDir, worldPlane, sweepHit.distance, &sweepHit.position);
+ if(hitPlane && sweepHit.distance > 0 && sweepHit.distance <= distance)
+ {
+ sweepHit.normal = worldPlane.n;
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+ return true;
+ }
+ return false;
+}
+
+bool sweepBox_ConvexGeom(GU_BOX_SWEEP_FUNC_PARAMS)
+{
+ PX_UNUSED(boxGeom_);
+
+ using namespace Ps::aos;
+ PX_ASSERT(geom.getType() == PxGeometryType::eCONVEXMESH);
+ const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom);
+
+ ConvexMesh* convexMesh = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+ ConvexHullData* hullData = &convexMesh->getHull();
+
+ const Vec3V zeroV = V3Zero();
+ const FloatV zero = FZero();
+
+ const PsTransformV boxPose = loadTransformU(boxPose_);
+ const PsTransformV convexPose = loadTransformU(pose);
+
+ const PsMatTransformV aToB(convexPose.transformInv(boxPose));
+
+ const Vec3V boxExtents = V3LoadU(box.extents);
+
+ const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
+
+ ShrunkBoxV boxV(zeroV, boxExtents);
+ ConvexHullV convexHull(hullData, zeroV, vScale, vQuat, convexGeom.scale.isIdentity());
+
+ const Vec3V worldDir = V3LoadU(unitDir);
+ const FloatV dist = FLoad(distance);
+ const Vec3V dir = convexPose.rotateInv(V3Neg(V3Scale(worldDir, dist)));
+
+ bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ FloatV toi;
+ Vec3V closestA, normal;
+ RelativeConvex<BoxV> convexA(boxV, aToB);
+ LocalConvex<ConvexHullV> convexB(convexHull);
+ if(!gjkRaycastPenetration< RelativeConvex<BoxV>,LocalConvex<ConvexHullV> >(convexA, convexB, aToB.p, zero, zeroV, dir, toi, normal, closestA, inflation, isMtd))
+ return false;
+
+ if(hasInitialOverlap(sweepHit, unitDir, toi, normal, closestA, convexPose, isMtd, true))
+ return true;
+
+ sweepHit.flags |= PxHitFlag::ePOSITION;
+ const Vec3V destNormal = V3Normalize(convexPose.rotate(normal));
+ const FloatV length = FMul(dist, toi);
+ const Vec3V worldPointA = convexPose.transform(closestA);
+ const Vec3V destWorldPointA = V3ScaleAdd(worldDir, length, worldPointA);
+ V3StoreU(destNormal, sweepHit.normal);
+ V3StoreU(destWorldPointA, sweepHit.position);
+ FStore(length, &sweepHit.distance);
+
+ return computeFaceIndex(sweepHit, hitFlags, convexGeom, hullData, pose, unitDir);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool Gu::sweepCapsuleTriangles(GU_SWEEP_TRIANGLES_FUNC_PARAMS(PxCapsuleGeometry))
+{
+ Capsule capsule;
+ getCapsule(capsule, geom, pose);
+ capsule.radius +=inflation;
+
+ // Compute swept box
+ Box capsuleBox;
+ computeBoxAroundCapsule(capsule, capsuleBox);
+
+ BoxPadded sweptBounds;
+ computeSweptBox(sweptBounds, capsuleBox.extents, capsuleBox.center, capsuleBox.rot, unitDir, distance);
+
+ PxVec3 triNormal;
+ return sweepCapsuleTriangles_Precise(nbTris, triangles, capsule, unitDir, distance, cachedIndex, hit, triNormal, hitFlags, doubleSided, &sweptBounds);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+bool sweepConvex_SphereGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
+{
+ PX_ASSERT(geom.getType() == PxGeometryType::eSPHERE);
+ const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom);
+
+ ConvexMesh* convexMesh = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+ ConvexHullData* hullData = &convexMesh->getHull();
+
+ const Vec3V zeroV = V3Zero();
+ const FloatV zero= FZero();
+
+ const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
+
+ const FloatV sphereRadius = FLoad(sphereGeom.radius);
+
+ const PsTransformV sphereTransf = loadTransformU(pose);
+ const PsTransformV convexTransf = loadTransformU(convexPose);
+
+ const PsMatTransformV aToB(convexTransf.transformInv(sphereTransf));
+
+ const Vec3V worldDir = V3LoadU(unitDir);
+ const FloatV dist = FLoad(distance);
+ const Vec3V dir = convexTransf.rotateInv(V3Scale(worldDir, dist));
+
+ ConvexHullV convexHull(hullData, zeroV, vScale, vQuat, convexGeom.scale.isIdentity());
+ //CapsuleV capsule(zeroV, sphereRadius);
+ CapsuleV capsule(aToB.p, sphereRadius);
+
+ const bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ FloatV toi;
+ Vec3V closestA, normal;
+ LocalConvex<CapsuleV> convexA(capsule);
+ LocalConvex<ConvexHullV> convexB(convexHull);
+ const Vec3V initialSearchDir = V3Sub(capsule.getCenter(), convexHull.getCenter());
+ if(!gjkRaycastPenetration< LocalConvex<CapsuleV>, LocalConvex<ConvexHullV> >(convexA, convexB, initialSearchDir, zero, zeroV, dir, toi, normal, closestA, sphereGeom.radius+inflation, isMtd))
+ return false;
+
+ if(hasInitialOverlap(sweepHit, unitDir, toi, normal, closestA, convexPose, isMtd, false))
+ return true;
+
+ sweepHit.flags |= PxHitFlag::ePOSITION;
+ const Vec3V destNormal = V3Neg(V3Normalize(convexTransf.rotate(normal)));
+ const FloatV length = FMul(dist, toi);
+ const Vec3V destWorldPointA = convexTransf.transform(closestA);
+ V3StoreU(destNormal, sweepHit.normal);
+ V3StoreU(destWorldPointA, sweepHit.position);
+ FStore(length, &sweepHit.distance);
+ sweepHit.faceIndex = 0xffffffff;
+ return true;
+}
+
+bool sweepConvex_PlaneGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
+{
+ PX_ASSERT(geom.getType() == PxGeometryType::ePLANE);
+ PX_UNUSED(hitFlags);
+ PX_UNUSED(geom);
+
+ ConvexMesh* convexMesh = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+ ConvexHullData* hullData = &convexMesh->getHull();
+
+ sweepHit.faceIndex = 0xFFFFffff; // spec says face index is undefined for planes
+
+ const PxVec3* PX_RESTRICT hullVertices = hullData->getHullVertices();
+ PxU32 numHullVertices = hullData->mNbHullVertices;
+
+ const bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ const FastVertex2ShapeScaling convexScaling(convexGeom.scale);
+
+ PxPlane plane = getPlane(pose);
+ plane.d -=inflation;
+
+ sweepHit.distance = distance;
+ bool status = false;
+ bool initialOverlap = false;
+ while(numHullVertices--)
+ {
+ const PxVec3& vertex = *hullVertices++;
+ const PxVec3 worldPt = convexPose.transform(convexScaling * vertex);
+ float t;
+ PxVec3 pointOnPlane;
+ if(intersectRayPlane(worldPt, unitDir, plane, t, &pointOnPlane))
+ {
+ if(plane.distance(worldPt) <= 0.0f)
+ {
+ initialOverlap = true;
+ break;
+ //// Convex touches plane
+ //sweepHit.distance = 0.0f;
+ //sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL;
+ //sweepHit.normal = -unitDir;
+ //return true;
+ }
+
+ if(t > 0.0f && t <= sweepHit.distance)
+ {
+ sweepHit.distance = t;
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+ sweepHit.position = pointOnPlane;
+ sweepHit.normal = plane.n;
+ status = true;
+ }
+ }
+ }
+
+ if(initialOverlap)
+ {
+ if(isMtd)
+ {
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::ePOSITION | PxHitFlag::eNORMAL;
+ return computePlane_ConvexMTD(plane, convexGeom, convexPose, sweepHit);
+ }
+ else
+ {
+ sweepHit.distance = 0.0f;
+ sweepHit.flags = PxHitFlag::eDISTANCE | PxHitFlag::eNORMAL;
+ sweepHit.normal = -unitDir;
+ return true;
+ }
+ }
+ return status;
+}
+
+bool sweepConvex_CapsuleGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
+{
+ PX_ASSERT(geom.getType() == PxGeometryType::eCAPSULE);
+ const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom);
+
+ Capsule capsule;
+ getCapsule(capsule, capsuleGeom, pose);
+
+ // remove PxHitFlag::eFACE_INDEX, not neeeded to compute.
+ PxHitFlags tempHitFlags = hitFlags;
+ tempHitFlags &= ~PxHitFlag::eFACE_INDEX;
+
+ if(!sweepCapsule_ConvexGeom(convexGeom, convexPose, capsuleGeom, pose, capsule, -unitDir, distance, sweepHit, tempHitFlags, inflation))
+ return false;
+
+ if(sweepHit.flags & PxHitFlag::ePOSITION)
+ sweepHit.position += unitDir * sweepHit.distance;
+
+ sweepHit.normal = -sweepHit.normal;
+ sweepHit.faceIndex = 0xffffffff;
+ return true;
+}
+
+bool sweepConvex_BoxGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
+{
+ PX_ASSERT(geom.getType() == PxGeometryType::eBOX);
+ const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom);
+
+ Box box;
+ buildFrom(box, pose.p, boxGeom.halfExtents, pose.q);
+
+ // remove PxHitFlag::eFACE_INDEX, not neeeded to compute.
+ PxHitFlags tempHitFlags = hitFlags;
+ tempHitFlags &= ~PxHitFlag::eFACE_INDEX;
+
+ if(!sweepBox_ConvexGeom(convexGeom, convexPose, boxGeom, pose, box, -unitDir, distance, sweepHit, tempHitFlags, inflation))
+ return false;
+
+ if(sweepHit.flags & PxHitFlag::ePOSITION)
+ sweepHit.position += unitDir * sweepHit.distance;
+
+ sweepHit.normal = -sweepHit.normal;
+ sweepHit.faceIndex = 0xffffffff;
+ return true;
+}
+
+bool sweepConvex_ConvexGeom(GU_CONVEX_SWEEP_FUNC_PARAMS)
+{
+ using namespace Ps::aos;
+ PX_ASSERT(geom.getType() == PxGeometryType::eCONVEXMESH);
+ const PxConvexMeshGeometry& otherConvexGeom = static_cast<const PxConvexMeshGeometry&>(geom);
+ ConvexMesh& otherConvexMesh = *static_cast<ConvexMesh*>(otherConvexGeom.convexMesh);
+
+ ConvexMesh* convexMesh = static_cast<ConvexMesh*>(convexGeom.convexMesh);
+ ConvexHullData* hullData = &convexMesh->getHull();
+
+ ConvexHullData* otherHullData = &otherConvexMesh.getHull();
+
+ const Vec3V zeroV = V3Zero();
+ const FloatV zero = FZero();
+
+ const Vec3V otherVScale = V3LoadU_SafeReadW(otherConvexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV otherVQuat = QuatVLoadU(&otherConvexGeom.scale.rotation.x);
+
+ const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
+ const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
+
+ const PsTransformV otherTransf = loadTransformU(pose);
+ const PsTransformV convexTransf = loadTransformU(convexPose);
+
+ const Vec3V worldDir = V3LoadU(unitDir);
+ const FloatV dist = FLoad(distance);
+ const Vec3V dir = convexTransf.rotateInv(V3Scale(worldDir, dist));
+
+ const PsMatTransformV aToB(convexTransf.transformInv(otherTransf));
+
+ ConvexHullV otherConvexHull(otherHullData, zeroV, otherVScale, otherVQuat, otherConvexGeom.scale.isIdentity());
+ ConvexHullV convexHull(hullData, zeroV, vScale, vQuat, convexGeom.scale.isIdentity());
+
+ const bool isMtd = hitFlags & PxHitFlag::eMTD;
+
+ FloatV toi;
+ Vec3V closestA, normal;
+ RelativeConvex<ConvexHullV> convexA(otherConvexHull, aToB);
+ LocalConvex<ConvexHullV> convexB(convexHull);
+ if(!gjkRaycastPenetration< RelativeConvex<ConvexHullV>, LocalConvex<ConvexHullV> >(convexA, convexB, aToB.p, zero, zeroV, dir, toi, normal, closestA, inflation, isMtd))
+ return false;
+
+ if(hasInitialOverlap(sweepHit, unitDir, toi, normal, closestA, convexPose, isMtd, false))
+ return true;
+
+ sweepHit.flags |= PxHitFlag::ePOSITION;
+ const Vec3V worldPointA = convexTransf.transform(closestA);
+ const Vec3V destNormal = V3Neg(V3Normalize(convexTransf.rotate(normal)));
+ const FloatV length = FMul(dist, toi);
+ V3StoreU(destNormal, sweepHit.normal);
+ V3StoreU(worldPointA, sweepHit.position);
+ FStore(length, &sweepHit.distance);
+
+ return computeFaceIndex(sweepHit, hitFlags, otherConvexGeom, otherHullData, pose, unitDir);
+}