diff options
| author | git perforce import user <a@b> | 2016-10-25 12:29:14 -0600 |
|---|---|---|
| committer | Sheikh Dawood Abdul Ajees <Sheikh Dawood Abdul Ajees> | 2016-10-25 18:56:37 -0500 |
| commit | 3dfe2108cfab31ba3ee5527e217d0d8e99a51162 (patch) | |
| tree | fa6485c169e50d7415a651bf838f5bcd0fd3bfbd /PhysX_3.4/Source/GeomUtils/src/sweep/GuSweepTriangleUtils.cpp | |
| download | physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.tar.xz physx-3.4-3dfe2108cfab31ba3ee5527e217d0d8e99a51162.zip | |
Initial commit:
PhysX 3.4.0 Update @ 21294896
APEX 1.4.0 Update @ 21275617
[CL 21300167]
Diffstat (limited to 'PhysX_3.4/Source/GeomUtils/src/sweep/GuSweepTriangleUtils.cpp')
| -rw-r--r-- | PhysX_3.4/Source/GeomUtils/src/sweep/GuSweepTriangleUtils.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/sweep/GuSweepTriangleUtils.cpp b/PhysX_3.4/Source/GeomUtils/src/sweep/GuSweepTriangleUtils.cpp new file mode 100644 index 00000000..a69ae54d --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/sweep/GuSweepTriangleUtils.cpp @@ -0,0 +1,223 @@ +// 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 "foundation/PxBounds3.h" +#include "GuSweepTriangleUtils.h" +#include "GuDistancePointTriangle.h" +#include "GuVecTriangle.h" +#include "GuVecBox.h" +#include "GuSweepBoxTriangle_FeatureBased.h" +#include "GuInternal.h" +#include "GuGJK.h" + +using namespace physx; +using namespace Gu; +using namespace physx::shdfnd::aos; + +#define GU_SAFE_DISTANCE_FOR_NORMAL_COMPUTATION 0.1f + +void Gu::computeSphereTriImpactData(PxVec3& hit, PxVec3& normal, const PxVec3& center, const PxVec3& dir, float t, const PxTriangle& tri) +{ + const PxVec3 newSphereCenter = center + dir*t; + + // We need the impact point, not computed by the new code + PxReal u_unused, v_unused; + const PxVec3 localHit = closestPtPointTriangle(newSphereCenter, tri.verts[0], tri.verts[1], tri.verts[2], u_unused, v_unused); + PX_UNUSED(u_unused); + PX_UNUSED(v_unused); + + // This is responsible for the cap-vs-box stuck while jumping. However it's needed to slide on box corners! + // PT: this one is also dubious since the sphere/capsule center can be far away from the hit point when the radius is big! + PxVec3 localNormal = newSphereCenter - localHit; + const PxReal m = localNormal.normalize(); + if(m<1e-3f) + tri.normal(localNormal); + + hit = localHit; + normal = localNormal; +} + +// PT: not inlining this rarely-run function makes the benchmark ~500.000 cycles faster... +// PT: using this version all the time makes the benchmark ~300.000 cycles slower. So we just use it as a backup. +static bool runBackupProcedure(PxVec3& hit, PxVec3& normal, const PxVec3& localMotion, const PxVec3& boxExtents, const PxTriangle& triInBoxSpace) +{ + const Vec3V v0 = V3LoadU(triInBoxSpace.verts[0]); + const Vec3V v1 = V3LoadU(triInBoxSpace.verts[1]); + const Vec3V v2 = V3LoadU(triInBoxSpace.verts[2]); + + const TriangleV triangleV(v0, v1, v2); + + // PT: the box is in the triangle's space already + //BoxV boxV(V3LoadU(PxVec3(0.0f)), V3LoadU(boxExtents), + // V3LoadU(PxVec3(1.0f, 0.0f, 0.0f)), V3LoadU(PxVec3(0.0f, 1.0f, 0.0f)), V3LoadU(PxVec3(0.0f, 0.0f, 1.0f))); + + const BoxV boxV(V3Zero(), V3LoadU(boxExtents)); + + Vec3V closestA; + Vec3V closestB; + Vec3V normalV; + FloatV distV; + LocalConvex<TriangleV> convexA(triangleV); + LocalConvex<BoxV> convexB(boxV); + const Vec3V initialSearchDir = V3Sub(triangleV.getCenter(), boxV.getCenter()); + const FloatV contactDist = FMax(); + GjkStatus status_ = gjk<LocalConvex<TriangleV>, LocalConvex<BoxV> >(convexA, convexB, initialSearchDir, contactDist, closestA, closestB, normalV, distV); + + if(status_==GJK_CONTACT) + return false; + + PxVec3 ml_closestB; + PxVec3 ml_normal; + V3StoreU(closestB, ml_closestB); + V3StoreU(normalV, ml_normal); + + hit = ml_closestB + localMotion; +// normal = -ml_normal; + if((ml_normal.dot(localMotion))>0.0f) + ml_normal = -ml_normal; + normal = ml_normal; + return true; +} + +void Gu::computeBoxTriImpactData(PxVec3& hit, PxVec3& normal, const PxVec3& boxExtents, const PxVec3& localDir, const PxTriangle& triInBoxSpace, PxReal impactDist) +{ + // PT: the triangle is in "box space", i.e. the box can be seen as an AABB centered around the origin. + + // PT: compute impact point/normal in a second pass. Here we simply re-sweep the box against the best triangle, + // using the feature-based code (which computes impact point and normal). This is not great because: + // - we know there's an impact so why do all tests again? + // - the SAT test & the feature-based tests could return different results because of FPU accuracy. + // The backup procedure makes sure we compute a proper answer even when the SAT and feature-based versions differ. + const PxBounds3 aabb(-boxExtents, boxExtents); + + const PxVec3 oneOverDir( + localDir.x!=0.0f ? 1.0f/localDir.x : 0.0f, + localDir.y!=0.0f ? 1.0f/localDir.y : 0.0f, + localDir.z!=0.0f ? 1.0f/localDir.z : 0.0f); + + // PT: TODO: this is the only place left using sweepBoxTriangle() + // Backface culling could be removed here since we know we want a hit no matter what. Plus, it's sometimes + // incorrectly culled and we hit the backup procedure for no reason. On Win32Modern for unknown reasons + // returned normal is sometimes (0,0,0). In these cases we also switch to the backup procedure. + float t = PX_MAX_F32; // PT: no need to initialize with best dist here since we want a hit no matter what + if(!sweepBoxTriangle(triInBoxSpace, aabb, localDir, oneOverDir, hit, normal, t) || normal.isZero()) + { + // PT: move triangle close to box + const PxVec3 localMotion = localDir*impactDist; + + const PxVec3 delta = localMotion - localDir*GU_SAFE_DISTANCE_FOR_NORMAL_COMPUTATION; + const PxTriangle movedTriangle( + triInBoxSpace.verts[0] - delta, + triInBoxSpace.verts[1] - delta, + triInBoxSpace.verts[2] - delta); + + if(!runBackupProcedure(hit, normal, localMotion, boxExtents, movedTriangle)) + { + // PT: if the backup procedure fails, we give up + hit = PxVec3(0.0f); + normal = -localDir; + } + } +} + +// PT: copy where we know that input vectors are not zero +static PX_FORCE_INLINE void edgeEdgeDistNoZeroVector( PxVec3& x, PxVec3& y, // closest points + const PxVec3& p, const PxVec3& a, // seg 1 origin, vector + const PxVec3& q, const PxVec3& b) // seg 2 origin, vector +{ + const PxVec3 T = q - p; + const PxReal ADotA = a.dot(a); + const PxReal BDotB = b.dot(b); + PX_ASSERT(ADotA!=0.0f); + PX_ASSERT(BDotB!=0.0f); + const PxReal ADotB = a.dot(b); + const PxReal ADotT = a.dot(T); + const PxReal BDotT = b.dot(T); + + // t parameterizes ray (p, a) + // u parameterizes ray (q, b) + + // Compute t for the closest point on ray (p, a) to ray (q, b) + const PxReal Denom = ADotA*BDotB - ADotB*ADotB; + + PxReal t; + if(Denom!=0.0f) + { + t = (ADotT*BDotB - BDotT*ADotB) / Denom; + + // Clamp result so t is on the segment (p, a) + if(t<0.0f) t = 0.0f; + else if(t>1.0f) t = 1.0f; + } + else + { + t = 0.0f; + } + + // find u for point on ray (q, b) closest to point at t + PxReal u; + { + u = (t*ADotB - BDotT) / BDotB; + + // if u is on segment (q, b), t and u correspond to closest points, otherwise, clamp u, recompute and clamp t + if(u<0.0f) + { + u = 0.0f; + t = ADotT / ADotA; + + if(t<0.0f) t = 0.0f; + else if(t>1.0f) t = 1.0f; + } + else if(u > 1.0f) + { + u = 1.0f; + t = (ADotB + ADotT) / ADotA; + + if(t<0.0f) t = 0.0f; + else if(t>1.0f) t = 1.0f; + } + } + + x = p + a * t; + y = q + b * u; +} + +void Gu::computeEdgeEdgeNormal(PxVec3& normal, const PxVec3& p1, const PxVec3& p2_p1, const PxVec3& p3, const PxVec3& p4_p3, const PxVec3& dir, float d) +{ + // PT: cross-product doesn't produce nice normals so we use an edge-edge distance function itself + + // PT: move the edges "0.1" units from each other before the computation. If the edges are too far + // away, computed normal tend to align itself with the swept direction. If the edges are too close, + // closest points x and y become identical and we can't compute a proper normal. + const PxVec3 p1s = p1 + dir*(d-GU_SAFE_DISTANCE_FOR_NORMAL_COMPUTATION); + + PxVec3 x, y; + edgeEdgeDistNoZeroVector(x, y, p1s, p2_p1, p3, p4_p3); + normal = x - y; +} |