GRK-Projekt/dependencies/physx-4.1/source/geomutils/src/GuMTD.cpp
2021-12-27 11:28:19 +01:00

1459 lines
47 KiB
C++

//
// 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 "geometry/PxMeshScale.h"
#include "geometry/PxConvexMeshGeometry.h"
#include "geomutils/GuContactBuffer.h"
#include "GuMTD.h"
#include "GuSphere.h"
#include "GuCapsule.h"
#include "GuDistancePointSegment.h"
#include "GuDistanceSegmentSegment.h"
#include "GuDistanceSegmentBox.h"
#include "GuVecBox.h"
#include "GuVecCapsule.h"
#include "GuVecConvexHull.h"
#include "GuVecConvexHullNoScale.h"
#include "GuInternal.h"
#include "GuContactMethodImpl.h"
#include "GuBoxConversion.h"
#include "GuGeometryUnion.h"
#include "GuShapeConvex.h"
#include "GuPCMShapeConvex.h"
#include "GuPCMContactGen.h"
#include "GuConvexMesh.h"
#include "GuGJK.h"
#include "PsUtilities.h"
#include "PsVecTransform.h"
#include "PsMathUtils.h"
using namespace physx;
using namespace Gu;
static PX_FORCE_INLINE PxF32 manualNormalize(PxVec3& mtd, const PxVec3& normal, PxReal lenSq)
{
const PxF32 len = PxSqrt(lenSq);
// We do a *manual* normalization to check for singularity condition
if(lenSq < 1e-6f)
mtd = PxVec3(1.0f, 0.0f, 0.0f); // PT: zero normal => pick up random one
else
mtd = normal * 1.0f / len;
return len;
}
static PX_FORCE_INLINE float validateDepth(float depth)
{
// PT: penetration depth must always be positive or null, but FPU accuracy being what it is, we sometimes
// end up with very small, epsilon-sized negative depths. We clamp those to zero, since they don't indicate
// real bugs in the MTD functions. However anything larger than epsilon is wrong, and caught with an assert.
const float epsilon = 1.e-3f;
//ML: because we are shrunking the shape in this moment, so the depth might be larger than eps, this condition is no longer valid
//PX_ASSERT(depth>=-epsilon);
PX_UNUSED(epsilon);
return PxMax(depth, 0.0f);
}
///////////////////////////////////////////////////////////////////////////////
// PT: the function names should follow the order in which the PxGeometryTypes are listed,
// i.e. computeMTD_Type0Type1 with Type0<=Type1. This is to guarantee that the proper results
// (following the desired convention) are returned from the PxGeometryQuery-level call.
///////////////////////////////////////////////////////////////////////////////
static bool computeMTD_SphereSphere(PxVec3& mtd, PxF32& depth, const Sphere& sphere0, const Sphere& sphere1)
{
const PxVec3 delta = sphere0.center - sphere1.center;
const PxReal d2 = delta.magnitudeSquared();
const PxReal radiusSum = sphere0.radius + sphere1.radius;
if(d2 > radiusSum*radiusSum)
return false;
const PxF32 d = manualNormalize(mtd, delta, d2);
depth = validateDepth(radiusSum - d);
return true;
}
///////////////////////////////////////////////////////////////////////////////
static bool computeMTD_SphereCapsule(PxVec3& mtd, PxF32& depth, const Sphere& sphere, const Capsule& capsule)
{
const PxReal radiusSum = sphere.radius + capsule.radius;
PxReal u;
const PxReal d2 = distancePointSegmentSquared(capsule, sphere.center, &u);
if(d2 > radiusSum*radiusSum)
return false;
const PxVec3 normal = sphere.center - capsule.getPointAt(u);
const PxReal lenSq = normal.magnitudeSquared();
const PxF32 d = manualNormalize(mtd, normal, lenSq);
depth = validateDepth(radiusSum - d);
return true;
}
///////////////////////////////////////////////////////////////////////////////
//This version is ported 1:1 from novodex
static PX_FORCE_INLINE bool ContactSphereBox(const PxVec3& sphereOrigin,
PxReal sphereRadius,
const PxVec3& boxExtents,
// const PxcCachedTransforms& boxCacheTransform,
const PxTransform& boxTransform,
PxVec3& point,
PxVec3& normal,
PxReal& separation,
PxReal contactDistance)
{
//returns true on contact
const PxVec3 delta = sphereOrigin - boxTransform.p; // s1.center - s2.center;
PxVec3 dRot = boxTransform.rotateInv(delta); //transform delta into OBB body coords.
//check if delta is outside ABB - and clip the vector to the ABB.
bool outside = false;
if (dRot.x < -boxExtents.x)
{
outside = true;
dRot.x = -boxExtents.x;
}
else if (dRot.x > boxExtents.x)
{
outside = true;
dRot.x = boxExtents.x;
}
if (dRot.y < -boxExtents.y)
{
outside = true;
dRot.y = -boxExtents.y;
}
else if (dRot.y > boxExtents.y)
{
outside = true;
dRot.y = boxExtents.y;
}
if (dRot.z < -boxExtents.z)
{
outside = true;
dRot.z =-boxExtents.z;
}
else if (dRot.z > boxExtents.z)
{
outside = true;
dRot.z = boxExtents.z;
}
if (outside) //if clipping was done, sphere center is outside of box.
{
point = boxTransform.rotate(dRot); //get clipped delta back in world coords.
normal = delta - point; //what we clipped away.
const PxReal lenSquared = normal.magnitudeSquared();
const PxReal inflatedDist = sphereRadius + contactDistance;
if (lenSquared > inflatedDist * inflatedDist)
return false; //disjoint
//normalize to make it into the normal:
separation = PxRecipSqrt(lenSquared);
normal *= separation;
separation *= lenSquared;
//any plane that touches the sphere is tangential, so a vector from contact point to sphere center defines normal.
//we could also use point here, which has same direction.
//this is either a faceFace or a vertexFace contact depending on whether the box's face or vertex collides, but we did not distinguish.
//We'll just use vertex face for now, this info isn't really being used anyway.
//contact point is point on surface of cube closest to sphere center.
point += boxTransform.p;
separation -= sphereRadius;
return true;
}
else
{
//center is in box, we definitely have a contact.
PxVec3 locNorm; //local coords contact normal
PxVec3 absdRot;
absdRot = PxVec3(PxAbs(dRot.x), PxAbs(dRot.y), PxAbs(dRot.z));
PxVec3 distToSurface = boxExtents - absdRot; //dist from embedded center to box surface along 3 dimensions.
//find smallest element of distToSurface
if (distToSurface.y < distToSurface.x)
{
if (distToSurface.y < distToSurface.z)
{
//y
locNorm = PxVec3(0.0f, dRot.y > 0.0f ? 1.0f : -1.0f, 0.0f);
separation = -distToSurface.y;
}
else
{
//z
locNorm = PxVec3(0.0f,0.0f, dRot.z > 0.0f ? 1.0f : -1.0f);
separation = -distToSurface.z;
}
}
else
{
if (distToSurface.x < distToSurface.z)
{
//x
locNorm = PxVec3(dRot.x > 0.0f ? 1.0f : -1.0f, 0.0f, 0.0f);
separation = -distToSurface.x;
}
else
{
//z
locNorm = PxVec3(0.0f,0.0f, dRot.z > 0.0f ? 1.0f : -1.0f);
separation = -distToSurface.z;
}
}
//separation so far is just the embedding of the center point; we still have to push out all of the radius.
point = sphereOrigin;
normal = boxTransform.rotate(locNorm);
separation -= sphereRadius;
return true;
}
}
static bool computeMTD_SphereBox(PxVec3& mtd, PxF32& depth, const Sphere& sphere, const Box& box)
{
PxVec3 point;
if(!ContactSphereBox( sphere.center, sphere.radius,
box.extents, PxTransform(box.center, PxQuat(box.rot)),
point, mtd, depth, 0.0f))
return false;
depth = validateDepth(-depth);
return true;
}
///////////////////////////////////////////////////////////////////////////////
static bool computeMTD_CapsuleCapsule(PxVec3& mtd, PxF32& depth, const Capsule& capsule0, const Capsule& capsule1)
{
PxReal s,t;
const PxReal d2 = distanceSegmentSegmentSquared(capsule0, capsule1, &s, &t);
const PxReal radiusSum = capsule0.radius + capsule1.radius;
if(d2 > radiusSum*radiusSum)
return false;
const PxVec3 normal = capsule0.getPointAt(s) - capsule1.getPointAt(t);
const PxReal lenSq = normal.magnitudeSquared();
const PxF32 d = manualNormalize(mtd, normal, lenSq);
depth = validateDepth(radiusSum - d);
return true;
}
///////////////////////////////////////////////////////////////////////////////
static PX_FORCE_INLINE void reorderMTD(PxVec3& mtd, const PxVec3& center0, const PxVec3& center1)
{
const PxVec3 witness = center0 - center1;
if(mtd.dot(witness) < 0.0f)
mtd = -mtd;
}
static PX_FORCE_INLINE void projectBox(PxReal& min, PxReal& max, const PxVec3& axis, const Box& box)
{
const PxReal boxCen = box.center.dot(axis);
const PxReal boxExt =
PxAbs(box.rot.column0.dot(axis)) * box.extents.x
+ PxAbs(box.rot.column1.dot(axis)) * box.extents.y
+ PxAbs(box.rot.column2.dot(axis)) * box.extents.z;
min = boxCen - boxExt;
max = boxCen + boxExt;
}
static bool PxcTestAxis(const PxVec3& axis, const Segment& segment, PxReal radius, const Box& box, PxReal& depth)
{
// Project capsule
PxReal min0 = segment.p0.dot(axis);
PxReal max0 = segment.p1.dot(axis);
if(min0>max0) Ps::swap(min0, max0);
min0 -= radius;
max0 += radius;
// Project box
PxReal Min1, Max1;
projectBox(Min1, Max1, axis, box);
// Test projections
if(max0<Min1 || Max1<min0)
return false;
const PxReal d0 = max0 - Min1;
PX_ASSERT(d0>=0.0f);
const PxReal d1 = Max1 - min0;
PX_ASSERT(d1>=0.0f);
depth = physx::intrinsics::selectMin(d0, d1);
return true;
}
static bool PxcCapsuleOBBOverlap3(const Segment& segment, PxReal radius, const Box& box, PxReal* t=NULL, PxVec3* pp=NULL)
{
PxVec3 Sep(0.0f);
PxReal PenDepth = PX_MAX_REAL;
// Test normals
for(PxU32 i=0;i<3;i++)
{
PxReal d;
if(!PxcTestAxis(box.rot[i], segment, radius, box, d))
return false;
if(d<PenDepth)
{
PenDepth = d;
Sep = box.rot[i];
}
}
// Test edges
PxVec3 CapsuleAxis(segment.p1 - segment.p0);
CapsuleAxis = CapsuleAxis.getNormalized();
for(PxU32 i=0;i<3;i++)
{
PxVec3 Cross = CapsuleAxis.cross(box.rot[i]);
if(!Ps::isAlmostZero(Cross))
{
Cross = Cross.getNormalized();
PxReal d;
if(!PxcTestAxis(Cross, segment, radius, box, d))
return false;
if(d<PenDepth)
{
PenDepth = d;
Sep = Cross;
}
}
}
reorderMTD(Sep, segment.computeCenter(), box.center);
if(t)
*t = validateDepth(PenDepth);
if(pp)
*pp = Sep;
return true;
}
static bool computeMTD_CapsuleBox(PxVec3& mtd, PxF32& depth, const Capsule& capsule, const Box& box)
{
PxReal t;
PxVec3 onBox;
const PxReal d2 = distanceSegmentBoxSquared(capsule.p0, capsule.p1, box.center, box.extents, box.rot, &t, &onBox);
if(d2 > capsule.radius*capsule.radius)
return false;
if(d2 != 0.0f)
{
// PT: the capsule segment doesn't intersect the box => distance-based version
const PxVec3 onSegment = capsule.getPointAt(t);
onBox = box.center + box.rot.transform(onBox);
PxVec3 normal = onSegment - onBox;
PxReal normalLen = normal.magnitude();
if(normalLen != 0.0f)
{
normal *= 1.0f/normalLen;
mtd = normal;
depth = validateDepth(capsule.radius - PxSqrt(d2));
return true;
}
}
// PT: the capsule segment intersects the box => penetration-based version
return PxcCapsuleOBBOverlap3(capsule, capsule.radius, box, &depth, &mtd);
}
///////////////////////////////////////////////////////////////////////////////
static bool PxcTestAxis(const PxVec3& axis, const Box& box0, const Box& box1, PxReal& depth)
{
// Project box
PxReal min0, max0;
projectBox(min0, max0, axis, box0);
// Project box
PxReal Min1, Max1;
projectBox(Min1, Max1, axis, box1);
// Test projections
if(max0<Min1 || Max1<min0)
return false;
const PxReal d0 = max0 - Min1;
PX_ASSERT(d0>=0.0f);
const PxReal d1 = Max1 - min0;
PX_ASSERT(d1>=0.0f);
depth = physx::intrinsics::selectMin(d0, d1);
return true;
}
static PX_FORCE_INLINE bool testBoxBoxAxis(PxVec3& mtd, PxF32& depth, const PxVec3& axis, const Box& box0, const Box& box1)
{
PxF32 d;
if(!PxcTestAxis(axis, box0, box1, d))
return false;
if(d<depth)
{
depth = d;
mtd = axis;
}
return true;
}
static bool computeMTD_BoxBox(PxVec3& _mtd, PxF32& _depth, const Box& box0, const Box& box1)
{
PxVec3 mtd;
PxF32 depth = PX_MAX_F32;
if(!testBoxBoxAxis(mtd, depth, box0.rot.column0, box0, box1))
return false;
if(!testBoxBoxAxis(mtd, depth, box0.rot.column1, box0, box1))
return false;
if(!testBoxBoxAxis(mtd, depth, box0.rot.column2, box0, box1))
return false;
if(!testBoxBoxAxis(mtd, depth, box1.rot.column0, box0, box1))
return false;
if(!testBoxBoxAxis(mtd, depth, box1.rot.column1, box0, box1))
return false;
if(!testBoxBoxAxis(mtd, depth, box1.rot.column2, box0, box1))
return false;
for(PxU32 j=0;j<3;j++)
{
for(PxU32 i=0;i<3;i++)
{
PxVec3 cross = box0.rot[i].cross(box1.rot[j]);
if(!Ps::isAlmostZero(cross))
{
cross = cross.getNormalized();
if(!testBoxBoxAxis(mtd, depth, cross, box0, box1))
return false;
}
}
}
reorderMTD(mtd, box1.center, box0.center);
_mtd = -mtd;
_depth = validateDepth(depth);
return true;
}
///////////////////////////////////////////////////////////////////////////////
using namespace physx::shdfnd::aos;
bool pointConvexDistance(PxVec3& normal_, PxVec3& closestPoint_, PxReal& sqDistance, const PxVec3& pt, const ConvexMesh* convexMesh, const PxMeshScale& meshScale, const PxTransform& convexPose)
{
const PxTransform transform0(pt);
PxVec3 onSegment, onConvex;
using namespace Ps::aos;
const Vec3V zeroV = V3Zero();
Vec3V closA, closB, normalV;
GjkStatus status;
FloatV dist;
{
const ConvexHullData* hullData = &convexMesh->getHull();
const Vec3V vScale = V3LoadU_SafeReadW(meshScale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
const QuatV vQuat = QuatVLoadU(&meshScale.rotation.x);
const ConvexHullV convexHull_(hullData, zeroV, vScale, vQuat, meshScale.isIdentity());
const PsMatTransformV aToB(convexPose.transformInv(transform0));
//const CapsuleV capsule(zeroV, zeroV, FZero());//this is a point
const CapsuleV capsule_(aToB.p, FZero());//this is a point
LocalConvex<CapsuleV> capsule(capsule_);
LocalConvex<ConvexHullV> convexHull(convexHull_);
status = gjk<LocalConvex<CapsuleV>, LocalConvex<ConvexHullV> >(capsule, convexHull, aToB.p, FMax(), closA, closB, normalV, dist);
}
bool intersect = status == GJK_CONTACT;
if(intersect)
{
sqDistance = 0.0f;
}
else
{
const FloatV sqDist = FMul(dist, dist);
FStore(sqDist, &sqDistance);
V3StoreU(normalV, normal_);
V3StoreU(closB, closestPoint_);
normal_ = convexPose.rotate(normal_);
closestPoint_ = convexPose.transform(closestPoint_);
}
return intersect;
}
static bool computeMTD_SphereConvex(PxVec3& mtd, PxF32& depth, const Sphere& sphere, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose)
{
PxReal d2;
const ConvexMesh* convexMesh = static_cast<const ConvexMesh*>(convexGeom.convexMesh);
PxVec3 dummy;
if(!pointConvexDistance(mtd, dummy, d2, sphere.center, convexMesh, convexGeom.scale, convexPose))
{
if(d2 > sphere.radius*sphere.radius)
return false;
depth = validateDepth(sphere.radius - PxSqrt(d2));
mtd = -mtd;
return true;
}
// PT: if we reach this place, the sphere center touched the convex => switch to penetration-based code
PxU32 nbPolygons = convexMesh->getNbPolygonsFast();
const HullPolygonData* polygons = convexMesh->getPolygons();
const PxVec3 localSphereCenter = convexPose.transformInv(sphere.center);
PxReal dmax = -PX_MAX_F32;
while(nbPolygons--)
{
const HullPolygonData& polygon = *polygons++;
const PxF32 d = polygon.mPlane.distance(localSphereCenter);
if(d>dmax)
{
dmax = d;
mtd = convexPose.rotate(polygon.mPlane.n);
}
}
depth = validateDepth(sphere.radius - dmax);
return true;
}
///////////////////////////////////////////////////////////////////////////////
//ML : capsule will be in the local space of convexHullV
static bool internalComputeMTD_CapsuleConvex(const CapsuleV& capsule, const bool idtScale, ConvexHullV& convexHullV, const Ps::aos::PsTransformV& transf1,
Ps::aos::FloatV& penetrationDepth, Ps::aos::Vec3V& normal)
{
PolygonalData polyData;
getPCMConvexData(convexHullV, idtScale, polyData);
PxU8 buff[sizeof(SupportLocalImpl<ConvexHullV>)];
SupportLocal* map = (idtScale ? static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff, SupportLocalImpl<ConvexHullNoScaleV>)(static_cast<ConvexHullNoScaleV&>(convexHullV), transf1, convexHullV.vertex2Shape, convexHullV.shape2Vertex, idtScale)) :
static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff, SupportLocalImpl<ConvexHullV>)(convexHullV, transf1, convexHullV.vertex2Shape, convexHullV.shape2Vertex, idtScale)));
return computeMTD(capsule, polyData, map, penetrationDepth, normal);
}
static bool computeMTD_CapsuleConvex(PxVec3& mtd, PxF32& depth, const Capsule& capsule, const PxTransform& capsulePose, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose)
{
const FloatV capsuleHalfHeight = FLoad(capsule.length()*0.5f);
const FloatV capsuleRadius = FLoad(capsule.radius);
const Vec3V zeroV = V3Zero();
// Convex mesh
const ConvexMesh* convexMesh = static_cast<const ConvexMesh*>(convexGeom.convexMesh);
const ConvexHullData* hull = &convexMesh->getHull();
const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
ConvexHullV convexHullV(hull, zeroV, vScale, vQuat, convexGeom.scale.isIdentity());
//~Convex mesh
const QuatV q0 = QuatVLoadU(&capsulePose.q.x);
const Vec3V p0 = V3LoadU(&capsulePose.p.x);
const QuatV q1 = QuatVLoadU(&convexPose.q.x);
const Vec3V p1 = V3LoadU(&convexPose.p.x);
const PsTransformV transf0(p0, q0);
const PsTransformV transf1(p1, q1);
const PsTransformV curRTrans(transf1.transformInv(transf0));
const PsMatTransformV aToB(curRTrans);
Vec3V normal = zeroV;
FloatV penetrationDepth = FZero();
CapsuleV capsuleV(aToB.p, aToB.rotate(V3Scale(V3UnitX(), capsuleHalfHeight)), capsuleRadius);
const bool idtScale = convexGeom.scale.isIdentity();
bool hasContacts = internalComputeMTD_CapsuleConvex(capsuleV, idtScale, convexHullV, transf1, penetrationDepth, normal);
if(hasContacts)
{
FStore(penetrationDepth, &depth);
depth = validateDepth(depth);
V3StoreU(normal, mtd);
}
return hasContacts;
}
///////////////////////////////////////////////////////////////////////////////
static bool internalComputeMTD_BoxConvex(const PxVec3 halfExtents, const BoxV& box, const bool idtScale, ConvexHullV& convexHullV, const Ps::aos::PsTransformV& transf0, const Ps::aos::PsTransformV& transf1,
Ps::aos::FloatV& penetrationDepth, Ps::aos::Vec3V& normal)
{
PolygonalData polyData0;
PCMPolygonalBox polyBox0(halfExtents);
polyBox0.getPolygonalData(&polyData0);
polyData0.mPolygonVertexRefs = gPCMBoxPolygonData;
PolygonalData polyData1;
getPCMConvexData(convexHullV, idtScale, polyData1);
Mat33V identity = M33Identity();
SupportLocalImpl<BoxV> map0(box, transf0, identity, identity, true);
PxU8 buff[sizeof(SupportLocalImpl<ConvexHullV>)];
SupportLocal* map1 = (idtScale ? static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff, SupportLocalImpl<ConvexHullNoScaleV>)(static_cast<ConvexHullNoScaleV&>(convexHullV), transf1, convexHullV.vertex2Shape, convexHullV.shape2Vertex, idtScale)) :
static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff, SupportLocalImpl<ConvexHullV>)(convexHullV, transf1, convexHullV.vertex2Shape, convexHullV.shape2Vertex, idtScale)));
return computeMTD(polyData0, polyData1, &map0, map1, penetrationDepth, normal);
}
static bool computeMTD_BoxConvex(PxVec3& mtd, PxF32& depth, const Box& box, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose)
{
const Vec3V zeroV = V3Zero();
const PxTransform boxPose = box.getTransform();
const Vec3V boxExtents = V3LoadU(box.extents);
BoxV boxV(zeroV, boxExtents);
// Convex mesh
const ConvexMesh* convexMesh = static_cast<const ConvexMesh*>(convexGeom.convexMesh);
const ConvexHullData* hull = &convexMesh->getHull();
const Vec3V vScale = V3LoadU_SafeReadW(convexGeom.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
const QuatV vQuat = QuatVLoadU(&convexGeom.scale.rotation.x);
ConvexHullV convexHullV(hull, zeroV, vScale, vQuat, convexGeom.scale.isIdentity());
//~Convex mesh
const QuatV q0 = QuatVLoadU(&boxPose.q.x);
const Vec3V p0 = V3LoadU(&boxPose.p.x);
const QuatV q1 = QuatVLoadU(&convexPose.q.x);
const Vec3V p1 = V3LoadU(&convexPose.p.x);
const PsTransformV transf0(p0, q0);
const PsTransformV transf1(p1, q1);
Vec3V normal=zeroV;
FloatV penetrationDepth=FZero();
const bool idtScale = convexGeom.scale.isIdentity();
bool hasContacts = internalComputeMTD_BoxConvex(box.extents, boxV, idtScale, convexHullV, transf0, transf1, penetrationDepth, normal);
if(hasContacts)
{
FStore(penetrationDepth, &depth);
depth = validateDepth(depth);
V3StoreU(normal, mtd);
}
return hasContacts;
}
static bool internalComputeMTD_ConvexConvex(const bool idtScale0, const bool idtScale1, ConvexHullV& convexHullV0, ConvexHullV& convexHullV1, const Ps::aos::PsTransformV& transf0, const Ps::aos::PsTransformV& transf1,
Ps::aos::FloatV& penetrationDepth, Ps::aos::Vec3V& normal)
{
PolygonalData polyData0, polyData1;
getPCMConvexData(convexHullV0, idtScale0, polyData0);
getPCMConvexData(convexHullV1, idtScale1, polyData1);
PxU8 buff0[sizeof(SupportLocalImpl<ConvexHullV>)];
PxU8 buff1[sizeof(SupportLocalImpl<ConvexHullV>)];
SupportLocal* map0 = (idtScale0 ? static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff0, SupportLocalImpl<ConvexHullNoScaleV>)(static_cast<ConvexHullNoScaleV&>(convexHullV0), transf0, convexHullV0.vertex2Shape, convexHullV0.shape2Vertex, idtScale0)) :
static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff0, SupportLocalImpl<ConvexHullV>)(convexHullV0, transf0, convexHullV0.vertex2Shape, convexHullV0.shape2Vertex, idtScale0)));
SupportLocal* map1 = (idtScale1 ? static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff1, SupportLocalImpl<ConvexHullNoScaleV>)(static_cast<ConvexHullNoScaleV&>(convexHullV1), transf1, convexHullV1.vertex2Shape, convexHullV1.shape2Vertex, idtScale1)) :
static_cast<SupportLocal*>(PX_PLACEMENT_NEW(buff1, SupportLocalImpl<ConvexHullV>)(convexHullV1, transf1, convexHullV1.vertex2Shape, convexHullV1.shape2Vertex, idtScale1)));
return computeMTD(polyData0, polyData1, map0, map1, penetrationDepth, normal);
}
///////////////////////////////////////////////////////////////////////////////
static bool computeMTD_ConvexConvex(PxVec3& mtd, PxF32& depth, const PxConvexMeshGeometry& convexGeom0, const PxTransform& convexPose0, const PxConvexMeshGeometry& convexGeom1, const PxTransform& convexPose1)
{
using namespace Ps::aos;
const Vec3V zeroV = V3Zero();
// Convex mesh
const ConvexMesh* convexMesh0 = static_cast<const ConvexMesh*>(convexGeom0.convexMesh);
const ConvexHullData* hull0 = &convexMesh0->getHull();
const Vec3V vScale0 = V3LoadU_SafeReadW(convexGeom0.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
const QuatV vQuat0 = QuatVLoadU(&convexGeom0.scale.rotation.x);
ConvexHullV convexHullV0(hull0, zeroV, vScale0, vQuat0, convexGeom0.scale.isIdentity());
//~Convex mesh
// Convex mesh
const ConvexMesh* convexMesh1 = static_cast<const ConvexMesh*>(convexGeom1.convexMesh);
const ConvexHullData* hull1 = &convexMesh1->getHull();
const Vec3V vScale1 = V3LoadU_SafeReadW(convexGeom1.scale.scale); // PT: safe because 'rotation' follows 'scale' in PxMeshScale
const QuatV vQuat1 = QuatVLoadU(&convexGeom1.scale.rotation.x);
ConvexHullV convexHullV1(hull1, zeroV, vScale1, vQuat1, convexGeom1.scale.isIdentity());
//~Convex mesh
const QuatV q0 = QuatVLoadU(&convexPose0.q.x);
const Vec3V p0 = V3LoadU(&convexPose0.p.x);
const QuatV q1 = QuatVLoadU(&convexPose1.q.x);
const Vec3V p1 = V3LoadU(&convexPose1.p.x);
const PsTransformV transf0(p0, q0);
const PsTransformV transf1(p1, q1);
Vec3V normal = zeroV;
FloatV penetrationDepth = FZero();
const bool idtScale0 = convexGeom0.scale.isIdentity();
const bool idtScale1 = convexGeom1.scale.isIdentity();
bool hasContacts = internalComputeMTD_ConvexConvex(idtScale0, idtScale1, convexHullV0, convexHullV1, transf0, transf1, penetrationDepth, normal);
if(hasContacts)
{
FStore(penetrationDepth, &depth);
depth = validateDepth(depth);
V3StoreU(normal, mtd);
}
return hasContacts;
}
///////////////////////////////////////////////////////////////////////////////
static bool computeMTD_SpherePlane(PxVec3& mtd, PxF32& depth, const Sphere& sphere, const PxPlane& plane)
{
const PxReal d = plane.distance(sphere.center);
if(d>sphere.radius)
return false;
mtd = plane.n;
depth = validateDepth(sphere.radius - d);
return true;
}
static bool computeMTD_PlaneBox(PxVec3& mtd, PxF32& depth, const PxPlane& plane, const Box& box)
{
PxVec3 pts[8];
box.computeBoxPoints(pts);
PxReal dmin = plane.distance(pts[0]);
for(PxU32 i=1;i<8;i++)
{
const PxReal d = plane.distance(pts[i]);
dmin = physx::intrinsics::selectMin(dmin, d);
}
if(dmin>0.0f)
return false;
mtd = -plane.n;
depth = validateDepth(-dmin);
return true;
}
static bool computeMTD_PlaneCapsule(PxVec3& mtd, PxF32& depth, const PxPlane& plane, const Capsule& capsule)
{
const PxReal d0 = plane.distance(capsule.p0);
const PxReal d1 = plane.distance(capsule.p1);
const PxReal dmin = physx::intrinsics::selectMin(d0, d1) - capsule.radius;
if(dmin>0.0f)
return false;
mtd = -plane.n;
depth = validateDepth(-dmin);
return true;
}
static bool computeMTD_PlaneConvex(PxVec3& mtd, PxF32& depth, const PxPlane& plane, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose)
{
const ConvexMesh* convexMesh = static_cast<const ConvexMesh*>(convexGeom.convexMesh);
PxU32 nbVerts = convexMesh->getNbVerts();
const PxVec3* PX_RESTRICT verts = convexMesh->getVerts();
PxReal dmin = plane.distance(convexPose.transform(verts[0]));
for(PxU32 i=1;i<nbVerts;i++)
{
const PxReal d = plane.distance(convexPose.transform(verts[i]));
dmin = physx::intrinsics::selectMin(dmin, d);
}
if(dmin>0.0f)
return false;
mtd = -plane.n;
depth = validateDepth(-dmin);
return true;
}
///////////////////////////////////////////////////////////////////////////////
static bool processContacts(PxVec3& mtd, PxF32& depth, PxU32 nbContacts, const ContactPoint* contacts)
{
if(nbContacts)
{
PxVec3 mn(0.0f), mx(0.0f);
for(PxU32 i=0; i<nbContacts; i++)
{
const ContactPoint& ct = contacts[i];
PxVec3 depenetration = ct.separation * ct.normal;
mn = mn.minimum(depenetration);
mx = mx.maximum(depenetration);
}
// even if we are already moving in separation direction, we should still depenetrate
// so no dot velocity test
// here we attempt to equalize the separations pushing in opposing directions along each axis
PxVec3 mn1, mx1;
mn1.x = (mn.x == 0.0f) ? mx.x : mn.x;
mn1.y = (mn.y == 0.0f) ? mx.y : mn.y;
mn1.z = (mn.z == 0.0f) ? mx.z : mn.z;
mx1.x = (mx.x == 0.0f) ? mn.x : mx.x;
mx1.y = (mx.y == 0.0f) ? mn.y : mx.y;
mx1.z = (mx.z == 0.0f) ? mn.z : mx.z;
PxVec3 sepDir((mn1 + mx1)*0.5f);
if(sepDir.magnitudeSquared() < 1e-10f)
{
return false;
}
mtd = -sepDir.getNormalized();
depth = sepDir.magnitude();
}
return true;
}
static bool computeMTD_SphereMesh(PxVec3& mtd, PxF32& depth, const Sphere& sphere, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshPose)
{
GeometryUnion shape0;
shape0.set(PxSphereGeometry(sphere.radius));
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactSphereMesh(shape0, shape1, PxTransform(sphere.center), meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_CapsuleMesh(PxVec3& mtd, PxF32& depth, const Capsule& capsule, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshPose)
{
PxReal halfHeight;
const PxTransform capsuleTransform = PxTransformFromSegment(capsule.p0, capsule.p1, &halfHeight);
GeometryUnion shape0;
shape0.set(PxCapsuleGeometry(capsule.radius, halfHeight));
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactCapsuleMesh(shape0, shape1, capsuleTransform, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_BoxMesh(PxVec3& mtd, PxF32& depth, const Box& box, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshPose)
{
const PxTransform boxPose(box.center, PxQuat(box.rot));
GeometryUnion shape0;
shape0.set(PxBoxGeometry(box.extents));
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactBoxMesh(shape0, shape1, boxPose, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_ConvexMesh(PxVec3& mtd, PxF32& depth, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, const PxTriangleMeshGeometry& meshGeom, const PxTransform& meshPose)
{
GeometryUnion shape0;
shape0.set(convexGeom);
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactConvexMesh(shape0, shape1, convexPose, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_SphereHeightField(PxVec3& mtd, PxF32& depth, const Sphere& sphere, const PxHeightFieldGeometry& meshGeom, const PxTransform& meshPose)
{
GeometryUnion shape0;
shape0.set(PxSphereGeometry(sphere.radius));
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
const PxTransform spherePose(sphere.center);
if(!contactSphereHeightfield(shape0, shape1, spherePose, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_CapsuleHeightField(PxVec3& mtd, PxF32& depth, const Capsule& capsule, const PxHeightFieldGeometry& meshGeom, const PxTransform& meshPose)
{
PxReal halfHeight;
const PxTransform capsuleTransform = PxTransformFromSegment(capsule.p0, capsule.p1, &halfHeight);
GeometryUnion shape0;
shape0.set(PxCapsuleGeometry(capsule.radius, halfHeight));
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactCapsuleHeightfield(shape0, shape1, capsuleTransform, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_BoxHeightField(PxVec3& mtd, PxF32& depth, const Box& box, const PxHeightFieldGeometry& meshGeom, const PxTransform& meshPose)
{
const PxTransform boxPose(box.center, PxQuat(box.rot));
GeometryUnion shape0;
shape0.set(PxBoxGeometry(box.extents));
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactBoxHeightfield(shape0, shape1, boxPose, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool computeMTD_ConvexHeightField(PxVec3& mtd, PxF32& depth, const PxConvexMeshGeometry& convexGeom, const PxTransform& convexPose, const PxHeightFieldGeometry& meshGeom, const PxTransform& meshPose)
{
GeometryUnion shape0;
shape0.set(convexGeom);
GeometryUnion shape1;
shape1.set(meshGeom);
Cache cache;
ContactBuffer contactBuffer;
contactBuffer.reset();
if(!contactConvexHeightfield(shape0, shape1, convexPose, meshPose, NarrowPhaseParams(0.0f, 0.0f, 1.0f), cache, contactBuffer, NULL))
return false;
if(!processContacts(mtd, depth, contactBuffer.count, contactBuffer.contacts))
return false;
return contactBuffer.count!=0;
}
static bool GeomMTDCallback_NotSupported(GU_MTD_FUNC_PARAMS)
{
PX_ALWAYS_ASSERT_MESSAGE("NOT SUPPORTED");
PX_UNUSED(mtd); PX_UNUSED(depth); PX_UNUSED(geom0); PX_UNUSED(geom1); PX_UNUSED(pose0); PX_UNUSED(pose1);
return false;
}
static bool GeomMTDCallback_SphereSphere(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::eSPHERE);
const PxSphereGeometry& sphereGeom0 = static_cast<const PxSphereGeometry&>(geom0);
const PxSphereGeometry& sphereGeom1 = static_cast<const PxSphereGeometry&>(geom1);
return computeMTD_SphereSphere(mtd, depth, Sphere(pose0.p, sphereGeom0.radius), Sphere(pose1.p, sphereGeom1.radius));
}
static bool GeomMTDCallback_SpherePlane(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::ePLANE);
PX_UNUSED(geom1);
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
return computeMTD_SpherePlane(mtd, depth, Sphere(pose0.p, sphereGeom.radius), getPlane(pose1));
}
static bool GeomMTDCallback_SphereCapsule(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::eCAPSULE);
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom1);
Capsule capsule;
getCapsuleSegment(pose1, capsuleGeom, capsule);
capsule.radius = capsuleGeom.radius;
return computeMTD_SphereCapsule(mtd, depth, Sphere(pose0.p, sphereGeom.radius), capsule);
}
static bool GeomMTDCallback_SphereBox(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::eBOX);
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom1);
Box obb;
buildFrom(obb, pose1.p, boxGeom.halfExtents, pose1.q);
return computeMTD_SphereBox(mtd, depth, Sphere(pose0.p, sphereGeom.radius), obb);
}
static bool GeomMTDCallback_SphereConvex(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::eCONVEXMESH);
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom1);
return computeMTD_SphereConvex(mtd, depth, Sphere(pose0.p, sphereGeom.radius), convexGeom, pose1);
}
static bool GeomMTDCallback_SphereMesh(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
return computeMTD_SphereMesh(mtd, depth, Sphere(pose0.p, sphereGeom.radius), meshGeom, pose1);
}
static bool GeomMTDCallback_PlaneCapsule(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::ePLANE);
PX_ASSERT(geom1.getType()==PxGeometryType::eCAPSULE);
PX_UNUSED(geom0);
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom1);
Capsule capsule;
getCapsuleSegment(pose1, capsuleGeom, capsule);
capsule.radius = capsuleGeom.radius;
return computeMTD_PlaneCapsule(mtd, depth, getPlane(pose0), capsule);
}
static bool GeomMTDCallback_PlaneBox(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::ePLANE);
PX_ASSERT(geom1.getType()==PxGeometryType::eBOX);
PX_UNUSED(geom0);
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom1);
Box obb;
buildFrom(obb, pose1.p, boxGeom.halfExtents, pose1.q);
return computeMTD_PlaneBox(mtd, depth, getPlane(pose0), obb);
}
static bool GeomMTDCallback_PlaneConvex(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::ePLANE);
PX_ASSERT(geom1.getType()==PxGeometryType::eCONVEXMESH);
PX_UNUSED(geom0);
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom1);
return computeMTD_PlaneConvex(mtd, depth, getPlane(pose0), convexGeom, pose1);
}
static bool GeomMTDCallback_CapsuleCapsule(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCAPSULE);
PX_ASSERT(geom1.getType()==PxGeometryType::eCAPSULE);
const PxCapsuleGeometry& capsuleGeom0 = static_cast<const PxCapsuleGeometry&>(geom0);
const PxCapsuleGeometry& capsuleGeom1 = static_cast<const PxCapsuleGeometry&>(geom1);
Capsule capsule0;
getCapsuleSegment(pose0, capsuleGeom0, capsule0);
capsule0.radius = capsuleGeom0.radius;
Capsule capsule1;
getCapsuleSegment(pose1, capsuleGeom1, capsule1);
capsule1.radius = capsuleGeom1.radius;
return computeMTD_CapsuleCapsule(mtd, depth, capsule0, capsule1);
}
static bool GeomMTDCallback_CapsuleBox(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCAPSULE);
PX_ASSERT(geom1.getType()==PxGeometryType::eBOX);
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom0);
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom1);
Capsule capsule;
getCapsuleSegment(pose0, capsuleGeom, capsule);
capsule.radius = capsuleGeom.radius;
Box obb;
buildFrom(obb, pose1.p, boxGeom.halfExtents, pose1.q);
return computeMTD_CapsuleBox(mtd, depth, capsule, obb);
}
static bool GeomMTDCallback_CapsuleConvex(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCAPSULE);
PX_ASSERT(geom1.getType()==PxGeometryType::eCONVEXMESH);
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom0);
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom1);
Capsule capsule;
getCapsuleSegment(pose0, capsuleGeom, capsule);
capsule.radius = capsuleGeom.radius;
return computeMTD_CapsuleConvex(mtd, depth, capsule, pose0, convexGeom, pose1);
}
static bool GeomMTDCallback_CapsuleMesh(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCAPSULE);
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom0);
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
Capsule capsule;
getCapsuleSegment(pose0, capsuleGeom, capsule);
capsule.radius = capsuleGeom.radius;
return computeMTD_CapsuleMesh(mtd, depth, capsule, meshGeom, pose1);
}
static bool GeomMTDCallback_BoxBox(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eBOX);
PX_ASSERT(geom1.getType()==PxGeometryType::eBOX);
const PxBoxGeometry& boxGeom0 = static_cast<const PxBoxGeometry&>(geom0);
const PxBoxGeometry& boxGeom1 = static_cast<const PxBoxGeometry&>(geom1);
Box obb0;
buildFrom(obb0, pose0.p, boxGeom0.halfExtents, pose0.q);
Box obb1;
buildFrom(obb1, pose1.p, boxGeom1.halfExtents, pose1.q);
return computeMTD_BoxBox(mtd, depth, obb0, obb1);
}
static bool GeomMTDCallback_BoxConvex(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eBOX);
PX_ASSERT(geom1.getType()==PxGeometryType::eCONVEXMESH);
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom0);
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom1);
Box obb;
buildFrom(obb, pose0.p, boxGeom.halfExtents, pose0.q);
return computeMTD_BoxConvex(mtd, depth, obb, convexGeom, pose1);
}
static bool GeomMTDCallback_BoxMesh(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eBOX);
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom0);
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
Box obb;
buildFrom(obb, pose0.p, boxGeom.halfExtents, pose0.q);
return computeMTD_BoxMesh(mtd, depth, obb, meshGeom, pose1);
}
static bool GeomMTDCallback_ConvexConvex(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCONVEXMESH);
PX_ASSERT(geom1.getType()==PxGeometryType::eCONVEXMESH);
const PxConvexMeshGeometry& convexGeom0 = static_cast<const PxConvexMeshGeometry&>(geom0);
const PxConvexMeshGeometry& convexGeom1 = static_cast<const PxConvexMeshGeometry&>(geom1);
return computeMTD_ConvexConvex(mtd, depth, convexGeom0, pose0, convexGeom1, pose1);
}
static bool GeomMTDCallback_ConvexMesh(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCONVEXMESH);
PX_ASSERT(geom1.getType()==PxGeometryType::eTRIANGLEMESH);
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom0);
const PxTriangleMeshGeometry& meshGeom = static_cast<const PxTriangleMeshGeometry&>(geom1);
return computeMTD_ConvexMesh(mtd, depth, convexGeom, pose0, meshGeom, pose1);
}
static bool GeomMTDCallback_SphereHeightField(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eSPHERE);
PX_ASSERT(geom1.getType()==PxGeometryType::eHEIGHTFIELD);
const PxSphereGeometry& sphereGeom = static_cast<const PxSphereGeometry&>(geom0);
const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom1);
const Sphere sphere(pose0.p, sphereGeom.radius);
return computeMTD_SphereHeightField(mtd, depth, sphere, meshGeom, pose1);
}
static bool GeomMTDCallback_CapsuleHeightField(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCAPSULE);
PX_ASSERT(geom1.getType()==PxGeometryType::eHEIGHTFIELD);
const PxCapsuleGeometry& capsuleGeom = static_cast<const PxCapsuleGeometry&>(geom0);
const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom1);
Capsule capsule;
getCapsuleSegment(pose0, capsuleGeom, capsule);
capsule.radius = capsuleGeom.radius;
return computeMTD_CapsuleHeightField(mtd, depth, capsule, meshGeom, pose1);
}
static bool GeomMTDCallback_BoxHeightField(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eBOX);
PX_ASSERT(geom1.getType()==PxGeometryType::eHEIGHTFIELD);
const PxBoxGeometry& boxGeom = static_cast<const PxBoxGeometry&>(geom0);
const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom1);
Box obb;
buildFrom(obb, pose0.p, boxGeom.halfExtents, pose0.q);
return computeMTD_BoxHeightField(mtd, depth, obb, meshGeom, pose1);
}
static bool GeomMTDCallback_ConvexHeightField(GU_MTD_FUNC_PARAMS)
{
PX_ASSERT(geom0.getType()==PxGeometryType::eCONVEXMESH);
PX_ASSERT(geom1.getType()==PxGeometryType::eHEIGHTFIELD);
const PxConvexMeshGeometry& convexGeom = static_cast<const PxConvexMeshGeometry&>(geom0);
const PxHeightFieldGeometry& meshGeom = static_cast<const PxHeightFieldGeometry&>(geom1);
return computeMTD_ConvexHeightField(mtd, depth, convexGeom, pose0, meshGeom, pose1);
}
Gu::GeomMTDFunc gGeomMTDMethodTable[][PxGeometryType::eGEOMETRY_COUNT] =
{
//PxGeometryType::eSPHERE
{
GeomMTDCallback_SphereSphere, //PxGeometryType::eSPHERE
GeomMTDCallback_SpherePlane, //PxGeometryType::ePLANE
GeomMTDCallback_SphereCapsule, //PxGeometryType::eCAPSULE
GeomMTDCallback_SphereBox, //PxGeometryType::eBOX
GeomMTDCallback_SphereConvex, //PxGeometryType::eCONVEXMESH
GeomMTDCallback_SphereMesh, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_SphereHeightField, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::ePLANE
{
0, //PxGeometryType::eSPHERE
GeomMTDCallback_NotSupported, //PxGeometryType::ePLANE
GeomMTDCallback_PlaneCapsule, //PxGeometryType::eCAPSULE
GeomMTDCallback_PlaneBox, //PxGeometryType::eBOX
GeomMTDCallback_PlaneConvex, //PxGeometryType::eCONVEXMESH
GeomMTDCallback_NotSupported, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_NotSupported, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eCAPSULE
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
GeomMTDCallback_CapsuleCapsule, //PxGeometryType::eCAPSULE
GeomMTDCallback_CapsuleBox, //PxGeometryType::eBOX
GeomMTDCallback_CapsuleConvex, //PxGeometryType::eCONVEXMESH
GeomMTDCallback_CapsuleMesh, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_CapsuleHeightField, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eBOX
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
GeomMTDCallback_BoxBox, //PxGeometryType::eBOX
GeomMTDCallback_BoxConvex, //PxGeometryType::eCONVEXMESH
GeomMTDCallback_BoxMesh, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_BoxHeightField, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eCONVEXMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
GeomMTDCallback_ConvexConvex, //PxGeometryType::eCONVEXMESH
GeomMTDCallback_ConvexMesh, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_ConvexHeightField, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eTRIANGLEMESH
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
GeomMTDCallback_NotSupported, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_NotSupported, //PxGeometryType::eHEIGHTFIELD
},
//PxGeometryType::eHEIGHTFIELD
{
0, //PxGeometryType::eSPHERE
0, //PxGeometryType::ePLANE
0, //PxGeometryType::eCAPSULE
0, //PxGeometryType::eBOX
0, //PxGeometryType::eCONVEXMESH
0, //PxGeometryType::eTRIANGLEMESH
GeomMTDCallback_NotSupported, //PxGeometryType::eHEIGHTFIELD
},
};