aboutsummaryrefslogtreecommitdiff
path: root/APEX_1.4/common/src/ApexCollision.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 /APEX_1.4/common/src/ApexCollision.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 'APEX_1.4/common/src/ApexCollision.cpp')
-rw-r--r--APEX_1.4/common/src/ApexCollision.cpp750
1 files changed, 750 insertions, 0 deletions
diff --git a/APEX_1.4/common/src/ApexCollision.cpp b/APEX_1.4/common/src/ApexCollision.cpp
new file mode 100644
index 00000000..2e16a714
--- /dev/null
+++ b/APEX_1.4/common/src/ApexCollision.cpp
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2008-2015, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, 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.
+ */
+
+
+#include "ApexDefs.h"
+#include "ApexCollision.h"
+
+namespace nvidia
+{
+namespace apex
+{
+
+bool capsuleCapsuleIntersection(const Capsule& worldCaps0, const Capsule& worldCaps1, float tolerance)
+{
+ float s, t;
+ float squareDist = APEX_segmentSegmentSqrDist(worldCaps0, worldCaps1, &s, &t);
+
+ float totRad = (worldCaps0.radius * tolerance) + (worldCaps1.radius * tolerance); //incl a bit of tolerance.
+ return squareDist < totRad * totRad;
+}
+
+//----------------------------------------------------------------------------//
+
+/// \todo replace this hack
+bool boxBoxIntersection(const Box& worldBox0, const Box& worldBox1)
+{
+ Capsule worldCaps0, worldCaps1;
+ worldCaps0.p0 = worldBox0.center - worldBox0.rot * PxVec3(0, worldBox0.extents.y, 0);
+ worldCaps0.p1 = worldBox0.center + worldBox0.rot * PxVec3(0, worldBox0.extents.y, 0);
+ worldCaps0.radius = worldBox0.extents.x / 0.7f;
+ worldCaps1.p0 = worldBox1.center - worldBox1.rot * PxVec3(0, worldBox1.extents.y, 0);
+ worldCaps1.p1 = worldBox1.center + worldBox1.rot * PxVec3(0, worldBox1.extents.y, 0);
+ worldCaps1.radius = worldBox1.extents.x / 0.7f;
+
+ float s, t;
+ float squareDist = APEX_segmentSegmentSqrDist(worldCaps0, worldCaps1, &s, &t);
+
+ float totRad = (worldCaps0.radius * 1.2f) + (worldCaps1.radius * 1.2f); //incl a bit of tolerance.
+ return squareDist < totRad * totRad;
+}
+
+//----------------------------------------------------------------------------//
+
+float APEX_pointTriangleSqrDst(const Triangle& triangle, const PxVec3& position)
+{
+ PxVec3 d1 = triangle.v1 - triangle.v0;
+ PxVec3 d2 = triangle.v2 - triangle.v0;
+ PxVec3 pp1 = position - triangle.v0;
+ float a = d1.dot(d1);
+ float b = d2.dot(d1);
+ float c = pp1.dot(d1);
+ float d = b;
+ float e = d2.dot(d2);
+ float f = pp1.dot(d2);
+ float det = a * e - b * d;
+ if (det != 0.0f)
+ {
+ float s = (c * e - b * f) / det;
+ float t = (a * f - c * d) / det;
+ if (s > 0.0f && t > 0.0f && (s + t) < 1.0f)
+ {
+ PxVec3 q = triangle.v0 + d1 * s + d2 * t;
+ return (q - position).magnitudeSquared();
+ }
+ }
+ Segment segment;
+ segment.p0 = triangle.v0;
+ segment.p1 = triangle.v1;
+ float dist = APEX_pointSegmentSqrDist(segment , position, NULL);
+ segment.p0 = triangle.v1;
+ segment.p1 = triangle.v2;
+ dist = PxMin(dist, APEX_pointSegmentSqrDist(segment, position, NULL));
+ segment.p0 = triangle.v2;
+ segment.p1 = triangle.v0;
+ dist = PxMin(dist, APEX_pointSegmentSqrDist(segment, position, NULL));
+ return dist;
+
+}
+
+//----------------------------------------------------------------------------//
+
+#define PARALLEL_TOLERANCE 1e-02f
+
+float APEX_segmentSegmentSqrDist(const Segment& seg0, const Segment& seg1, float* s, float* t)
+{
+ PxVec3 rkSeg0Direction = seg0.p1 - seg0.p0;
+ PxVec3 rkSeg1Direction = seg1.p1 - seg1.p0;
+
+ PxVec3 kDiff = seg0.p0 - seg1.p0;
+ float fA00 = rkSeg0Direction.magnitudeSquared();
+ float fA01 = -rkSeg0Direction.dot(rkSeg1Direction);
+ float fA11 = rkSeg1Direction.magnitudeSquared();
+ float fB0 = kDiff.dot(rkSeg0Direction);
+ float fC = kDiff.magnitudeSquared();
+ float fDet = PxAbs(fA00 * fA11 - fA01 * fA01);
+
+ float fB1, fS, fT, fSqrDist, fTmp;
+
+ if (fDet >= PARALLEL_TOLERANCE)
+ {
+ // line segments are not parallel
+ fB1 = -kDiff.dot(rkSeg1Direction);
+ fS = fA01 * fB1 - fA11 * fB0;
+ fT = fA01 * fB0 - fA00 * fB1;
+
+ if (fS >= 0.0f)
+ {
+ if (fS <= fDet)
+ {
+ if (fT >= 0.0f)
+ {
+ if (fT <= fDet) // region 0 (interior)
+ {
+ // minimum at two interior points of 3D lines
+ float fInvDet = 1.0f / fDet;
+ fS *= fInvDet;
+ fT *= fInvDet;
+ fSqrDist = fS * (fA00 * fS + fA01 * fT + 2.0f * fB0) +
+ fT * (fA01 * fS + fA11 * fT + 2.0f * fB1) + fC;
+ }
+ else // region 3 (side)
+ {
+ fT = 1.0f;
+ fTmp = fA01 + fB0;
+ if (fTmp >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else if (-fTmp >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB1 + fTmp);
+ }
+ else
+ {
+ fS = -fTmp / fA00;
+ fSqrDist = fTmp * fS + fA11 + 2.0f * fB1 + fC;
+ }
+ }
+ }
+ else // region 7 (side)
+ {
+ fT = 0.0f;
+ if (fB0 >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB0 >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else
+ {
+ fS = -fB0 / fA00;
+ fSqrDist = fB0 * fS + fC;
+ }
+ }
+ }
+ else
+ {
+ if (fT >= 0.0)
+ {
+ if (fT <= fDet) // region 1 (side)
+ {
+ fS = 1.0f;
+ fTmp = fA01 + fB1;
+ if (fTmp >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (-fTmp >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB0 + fTmp);
+ }
+ else
+ {
+ fT = -fTmp / fA11;
+ fSqrDist = fTmp * fT + fA00 + 2.0f * fB0 + fC;
+ }
+ }
+ else // region 2 (corner)
+ {
+ fTmp = fA01 + fB0;
+ if (-fTmp <= fA00)
+ {
+ fT = 1.0f;
+ if (fTmp >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fS = -fTmp / fA00;
+ fSqrDist = fTmp * fS + fA11 + 2.0f * fB1 + fC;
+ }
+ }
+ else
+ {
+ fS = 1.0f;
+ fTmp = fA01 + fB1;
+ if (fTmp >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (-fTmp >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB0 + fTmp);
+ }
+ else
+ {
+ fT = -fTmp / fA11;
+ fSqrDist = fTmp * fT + fA00 + 2.0f * fB0 + fC;
+ }
+ }
+ }
+ }
+ else // region 8 (corner)
+ {
+ if (-fB0 < fA00)
+ {
+ fT = 0.0f;
+ if (fB0 >= 0.0f)
+ {
+ fS = 0.0f;
+ fSqrDist = fC;
+ }
+ else
+ {
+ fS = -fB0 / fA00;
+ fSqrDist = fB0 * fS + fC;
+ }
+ }
+ else
+ {
+ fS = 1.0f;
+ fTmp = fA01 + fB1;
+ if (fTmp >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (-fTmp >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB0 + fTmp);
+ }
+ else
+ {
+ fT = -fTmp / fA11;
+ fSqrDist = fTmp * fT + fA00 + 2.0f * fB0 + fC;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (fT >= 0.0f)
+ {
+ if (fT <= fDet) // region 5 (side)
+ {
+ fS = 0.0f;
+ if (fB1 >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB1 >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB1 / fA11;
+ fSqrDist = fB1 * fT + fC;
+ }
+ }
+ else // region 4 (corner)
+ {
+ fTmp = fA01 + fB0;
+ if (fTmp < 0.0f)
+ {
+ fT = 1.0f;
+ if (-fTmp >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fB1 + fTmp);
+ }
+ else
+ {
+ fS = -fTmp / fA00;
+ fSqrDist = fTmp * fS + fA11 + 2.0f * fB1 + fC;
+ }
+ }
+ else
+ {
+ fS = 0.0f;
+ if (fB1 >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB1 >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB1 / fA11;
+ fSqrDist = fB1 * fT + fC;
+ }
+ }
+ }
+ }
+ else // region 6 (corner)
+ {
+ if (fB0 < 0.0f)
+ {
+ fT = 0.0f;
+ if (-fB0 >= fA00)
+ {
+ fS = 1.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else
+ {
+ fS = -fB0 / fA00;
+ fSqrDist = fB0 * fS + fC;
+ }
+ }
+ else
+ {
+ fS = 0.0f;
+ if (fB1 >= 0.0f)
+ {
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB1 >= fA11)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB1 / fA11;
+ fSqrDist = fB1 * fT + fC;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // line segments are parallel
+ if (fA01 > 0.0f)
+ {
+ // direction vectors form an obtuse angle
+ if (fB0 >= 0.0f)
+ {
+ fS = 0.0f;
+ fT = 0.0f;
+ fSqrDist = fC;
+ }
+ else if (-fB0 <= fA00)
+ {
+ fS = -fB0 / fA00;
+ fT = 0.0f;
+ fSqrDist = fB0 * fS + fC;
+ }
+ else
+ {
+ fB1 = -kDiff.dot(rkSeg1Direction);
+ fS = 1.0f;
+ fTmp = fA00 + fB0;
+ if (-fTmp >= fA01)
+ {
+ fT = 1.0f;
+ fSqrDist = fA00 + fA11 + fC + 2.0f * (fA01 + fB0 + fB1);
+ }
+ else
+ {
+ fT = -fTmp / fA01;
+ fSqrDist = fA00 + 2.0f * fB0 + fC + fT * (fA11 * fT + 2.0f * (fA01 + fB1));
+ }
+ }
+ }
+ else
+ {
+ // direction vectors form an acute angle
+ if (-fB0 >= fA00)
+ {
+ fS = 1.0f;
+ fT = 0.0f;
+ fSqrDist = fA00 + 2.0f * fB0 + fC;
+ }
+ else if (fB0 <= 0.0f)
+ {
+ fS = -fB0 / fA00;
+ fT = 0.0f;
+ fSqrDist = fB0 * fS + fC;
+ }
+ else
+ {
+ fB1 = -kDiff.dot(rkSeg1Direction);
+ fS = 0.0f;
+ if (fB0 >= -fA01)
+ {
+ fT = 1.0f;
+ fSqrDist = fA11 + 2.0f * fB1 + fC;
+ }
+ else
+ {
+ fT = -fB0 / fA01;
+ fSqrDist = fC + fT * (2.0f * fB1 + fA11 * fT);
+ }
+ }
+ }
+ }
+
+ if (s)
+ {
+ *s = fS;
+ }
+ if (t)
+ {
+ *t = fT;
+ }
+
+ return PxAbs(fSqrDist);
+
+}
+
+//----------------------------------------------------------------------------//
+
+float APEX_pointSegmentSqrDist(const Segment& seg, const PxVec3& point, float* param)
+{
+ PxVec3 Diff = point - seg.p0;
+ PxVec3 segExtent = seg.p1 - seg.p0;
+ float fT = Diff.dot(segExtent);
+
+ if (fT <= 0.0f)
+ {
+ fT = 0.0f;
+ }
+ else
+ {
+ float SqrLen = (seg.p1 - seg.p0).magnitudeSquared();
+ if (fT >= SqrLen)
+ {
+ fT = 1.0f;
+ Diff -= segExtent;
+ }
+ else
+ {
+ fT /= SqrLen;
+ Diff -= fT * segExtent;
+ }
+ }
+
+ if (param)
+ {
+ *param = fT;
+ }
+
+ return Diff.magnitudeSquared();
+}
+
+//----------------------------------------------------------------------------//
+
+uint32_t APEX_RayCapsuleIntersect(const PxVec3& origin, const PxVec3& dir, const Capsule& capsule, float s[2])
+{
+ // set up quadratic Q(t) = a*t^2 + 2*b*t + c
+
+ PxVec3 kU, kV, kW;
+ const PxVec3 capsDir = capsule.p1 - capsule.p0;
+ kW = capsDir;
+
+ float fWLength = kW.normalize();
+
+ // generate orthonormal basis
+
+ float fInvLength;
+ if (PxAbs(kW.x) >= PxAbs(kW.y))
+ {
+ // W.x or W.z is the largest magnitude component, swap them
+ fInvLength = 1.0f / PxSqrt(kW.x * kW.x + kW.z * kW.z);
+ kU.x = -kW.z * fInvLength;
+ kU.y = 0.0f;
+ kU.z = +kW.x * fInvLength;
+ }
+ else
+ {
+ // W.y or W.z is the largest magnitude component, swap them
+ fInvLength = 1.0f / PxSqrt(kW.y * kW.y + kW.z * kW.z);
+ kU.x = 0.0f;
+ kU.y = +kW.z * fInvLength;
+ kU.z = -kW.y * fInvLength;
+ }
+ kV = kW.cross(kU);
+ kV.normalize(); // PT: fixed november, 24, 2004. This is a bug in Magic.
+
+ // compute intersection
+
+ PxVec3 kD(kU.dot(dir), kV.dot(dir), kW.dot(dir));
+ float fDLength = kD.normalize();
+
+ float fInvDLength = 1.0f / fDLength;
+ PxVec3 kDiff = origin - capsule.p0;
+ PxVec3 kP(kU.dot(kDiff), kV.dot(kDiff), kW.dot(kDiff));
+ float fRadiusSqr = capsule.radius * capsule.radius;
+
+ float fInv, fA, fB, fC, fDiscr, fRoot, fT, fTmp;
+
+ // Is the velocity parallel to the capsule direction? (or zero)
+ if (PxAbs(kD.z) >= 1.0f - PX_EPS_F32 || fDLength < PX_EPS_F32)
+ {
+
+ float fAxisDir = dir.dot(capsDir);
+
+ fDiscr = fRadiusSqr - kP.x * kP.x - kP.y * kP.y;
+ if (fAxisDir < 0 && fDiscr >= 0.0f)
+ {
+ // Velocity anti-parallel to the capsule direction
+ fRoot = PxSqrt(fDiscr);
+ s[0] = (kP.z + fRoot) * fInvDLength;
+ s[1] = -(fWLength - kP.z + fRoot) * fInvDLength;
+ return 2;
+ }
+ else if (fAxisDir > 0 && fDiscr >= 0.0f)
+ {
+ // Velocity parallel to the capsule direction
+ fRoot = PxSqrt(fDiscr);
+ s[0] = -(kP.z + fRoot) * fInvDLength;
+ s[1] = (fWLength - kP.z + fRoot) * fInvDLength;
+ return 2;
+ }
+ else
+ {
+ // sphere heading wrong direction, or no velocity at all
+ return 0;
+ }
+ }
+
+ // test intersection with infinite cylinder
+ fA = kD.x * kD.x + kD.y * kD.y;
+ fB = kP.x * kD.x + kP.y * kD.y;
+ fC = kP.x * kP.x + kP.y * kP.y - fRadiusSqr;
+ fDiscr = fB * fB - fA * fC;
+ if (fDiscr < 0.0f)
+ {
+ // line does not intersect infinite cylinder
+ return 0;
+ }
+
+ int iQuantity = 0;
+
+ if (fDiscr > 0.0f)
+ {
+ // line intersects infinite cylinder in two places
+ fRoot = PxSqrt(fDiscr);
+ fInv = 1.0f / fA;
+ fT = (-fB - fRoot) * fInv;
+ fTmp = kP.z + fT * kD.z;
+ if (0.0f <= fTmp && fTmp <= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ }
+
+ fT = (-fB + fRoot) * fInv;
+ fTmp = kP.z + fT * kD.z;
+ if (0.0f <= fTmp && fTmp <= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ }
+
+ if (iQuantity == 2)
+ {
+ // line intersects capsule wall in two places
+ return 2;
+ }
+ }
+ else
+ {
+ // line is tangent to infinite cylinder
+ fT = -fB / fA;
+ fTmp = kP.z + fT * kD.z;
+ if (0.0f <= fTmp && fTmp <= fWLength)
+ {
+ s[0] = fT * fInvDLength;
+ return 1;
+ }
+ }
+
+ // test intersection with bottom hemisphere
+ // fA = 1
+ fB += kP.z * kD.z;
+ fC += kP.z * kP.z;
+ fDiscr = fB * fB - fC;
+ if (fDiscr > 0.0f)
+ {
+ fRoot = PxSqrt(fDiscr);
+ fT = -fB - fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp <= 0.0f)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+
+ fT = -fB + fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp <= 0.0f)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+ else if (fDiscr == 0.0f)
+ {
+ fT = -fB;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp <= 0.0f)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+
+ // test intersection with top hemisphere
+ // fA = 1
+ fB -= kD.z * fWLength;
+ fC += fWLength * (fWLength - 2.0f * kP.z);
+
+ fDiscr = fB * fB - fC;
+ if (fDiscr > 0.0f)
+ {
+ fRoot = PxSqrt(fDiscr);
+ fT = -fB - fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp >= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+
+ fT = -fB + fRoot;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp >= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+ else if (fDiscr == 0.0f)
+ {
+ fT = -fB;
+ fTmp = kP.z + fT * kD.z;
+ if (fTmp >= fWLength)
+ {
+ s[iQuantity++] = fT * fInvDLength;
+ if (iQuantity == 2)
+ {
+ return 2;
+ }
+ }
+ }
+
+ return (uint32_t)iQuantity;
+}
+
+
+//----------------------------------------------------------------------------//
+
+bool APEX_RayTriangleIntersect(const PxVec3& orig, const PxVec3& dir, const PxVec3& a, const PxVec3& b, const PxVec3& c, float& t, float& u, float& v)
+{
+ PxVec3 edge1 = b - a;
+ PxVec3 edge2 = c - a;
+ PxVec3 pvec = dir.cross(edge2);
+
+ // if determinant is near zero, ray lies in plane of triangle
+ float det = edge1.dot(pvec);
+
+ if (det == 0.0f)
+ {
+ return false;
+ }
+
+ float iPX_det = 1.0f / det;
+
+ // calculate distance from vert0 to ray origin
+ PxVec3 tvec = orig - a;
+
+ // calculate U parameter and test bounds
+ u = tvec.dot(pvec) * iPX_det;
+ if (u < 0.0f || u > 1.0f)
+ {
+ return false;
+ }
+
+ // prepare to test V parameter
+ PxVec3 qvec = tvec.cross(edge1);
+
+ // calculate V parameter and test bounds
+ v = dir.dot(qvec) * iPX_det;
+ if (v < 0.0f || u + v > 1.0f)
+ {
+ return false;
+ }
+
+ // calculate t, ray intersects triangle
+ t = edge2.dot(qvec) * iPX_det;
+
+ return true;
+}
+
+} // namespace apex
+} // namespace nvidia