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/contact/GuLegacyContactCapsuleHeightField.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/contact/GuLegacyContactCapsuleHeightField.cpp')
| -rw-r--r-- | PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactCapsuleHeightField.cpp | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactCapsuleHeightField.cpp b/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactCapsuleHeightField.cpp new file mode 100644 index 00000000..a21a281d --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactCapsuleHeightField.cpp @@ -0,0 +1,279 @@ +// 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 "GuDistancePointSegment.h" +#include "GuDistanceSegmentSegment.h" +#include "GuGeometryUnion.h" +#include "GuHeightFieldData.h" +#include "GuHeightFieldUtil.h" +#include "GuContactMethodImpl.h" +#include "GuContactBuffer.h" +#include "GuContactMethodImpl.h" +#include "GuInternal.h" + +#define DO_EDGE_EDGE 1 +#define DEBUG_HFNORMAL 0 +#define DEBUG_HFNORMALV 0 +#define DEBUG_RENDER_HFCONTACTS 0 + +#if DEBUG_RENDER_HFCONTACTS +#include "PxPhysics.h" +#include "PxScene.h" +#endif + +using namespace physx; +using namespace Gu; + +bool GuContactSphereHeightFieldShared(GU_CONTACT_METHOD_ARGS, bool isCapsule); + +namespace physx +{ +namespace Gu +{ +bool legacyContactCapsuleHeightfield(GU_CONTACT_METHOD_ARGS) +{ + // Get actual shape data + const PxCapsuleGeometry& shapeCapsule = shape0.get<const PxCapsuleGeometry>(); + const PxHeightFieldGeometryLL& hfGeom = shape1.get<const PxHeightFieldGeometryLL>(); + + const HeightField& hf = *static_cast<HeightField*>(hfGeom.heightField); + const HeightFieldUtil hfUtil(hfGeom, hf); + + const PxReal radius = shapeCapsule.radius; + const PxReal inflatedRadius = shapeCapsule.radius + params.mContactDistance; + const PxReal radiusSquared = inflatedRadius * inflatedRadius; + const PxReal halfHeight = shapeCapsule.halfHeight; + const PxReal eps = PxReal(0.1)*radius; + const PxReal epsSqr = eps*eps; + const PxReal oneOverRowScale = hfUtil.getOneOverRowScale(); + const PxReal oneOverColumnScale = hfUtil.getOneOverColumnScale(); + const PxReal radiusOverRowScale = inflatedRadius * PxAbs(oneOverRowScale); + const PxReal radiusOverColumnScale = inflatedRadius * PxAbs(oneOverColumnScale); + const PxTransform capsuleShapeToHfShape = transform1.transformInv(transform0); + + PxVec3 verticesInHfShape[2]; + verticesInHfShape[0] = capsuleShapeToHfShape.transform(PxVec3(-halfHeight, 0, 0)); + verticesInHfShape[1] = capsuleShapeToHfShape.transform(PxVec3(halfHeight, 0, 0)); + + PX_ASSERT(contactBuffer.count==0); + Gu::GeometryUnion u; + u.set(PxSphereGeometry(radius)); + PxTransform ts0(transform1.transform(verticesInHfShape[0])), ts1(transform1.transform(verticesInHfShape[1])); + GuContactSphereHeightFieldShared(u, shape1, ts0, transform1, params, cache, contactBuffer, renderOutput, true); + GuContactSphereHeightFieldShared(u, shape1, ts1, transform1, params, cache, contactBuffer, renderOutput, true); + + Segment worldCapsule; + worldCapsule.p0 = -getCapsuleHalfHeightVector(transform0, shapeCapsule); + worldCapsule.p1 = -worldCapsule.p0; + worldCapsule.p0 += transform0.p; + worldCapsule.p1 += transform0.p; + + const Segment capsuleSegmentInHfShape(verticesInHfShape[0], verticesInHfShape[1]); + + const PxU32 numCapsuleVertexContacts = contactBuffer.count; // remember how many contacts were stored as capsule vertex vs hf + + // test capsule edges vs HF + PxVec3 v0h = hfUtil.shape2hfp(verticesInHfShape[0]), v1h = hfUtil.shape2hfp(verticesInHfShape[1]); + const PxU32 absMinRow = hf.getMinRow(PxMin(v0h.x - radiusOverRowScale, v1h.x - radiusOverRowScale)); + const PxU32 absMaxRow = hf.getMaxRow(PxMax(v0h.x + radiusOverRowScale, v1h.x + radiusOverRowScale)); + const PxU32 absMinCol = hf.getMinColumn(PxMin(v0h.z - radiusOverColumnScale, v1h.z - radiusOverColumnScale)); + const PxU32 absMaxCol = hf.getMaxColumn(PxMax(v0h.z + radiusOverColumnScale, v1h.z + radiusOverColumnScale)); + if (DO_EDGE_EDGE) + for(PxU32 row = absMinRow; row <= absMaxRow; row++) + { + for(PxU32 column = absMinCol; column <= absMaxCol; column++) + { + //PxU32 vertexIndex = row * hfShape.getNbColumnsFast() + column; + const PxU32 vertexIndex = row * hf.getNbColumnsFast() + column; + const PxU32 firstEdge = 3 * vertexIndex; + + // omg I am sorry about this code but I can't find a simpler way: + // last column will only test edge 2 + // last row will only test edge 0 + // and most importantly last row and column will not go inside the for + const PxU32 minEi = PxU32((column == absMaxCol) ? 2 : 0); + const PxU32 maxEi = PxU32((row == absMaxRow) ? 1 : 3); + // perform capsule edge vs HF edge collision + for (PxU32 ei = minEi; ei < maxEi; ei++) + { + const PxU32 edgeIndex = firstEdge + ei; + + PX_ASSERT(vertexIndex == edgeIndex / 3); + PX_ASSERT(row == vertexIndex / hf.getNbColumnsFast()); + PX_ASSERT(column == vertexIndex % hf.getNbColumnsFast()); + + // look up the face indices adjacent to the current edge + PxU32 adjFaceIndices[2]; + const PxU32 adjFaceCount = hf.getEdgeTriangleIndices(edgeIndex, adjFaceIndices); + bool doCollision = false; + if(adjFaceCount == 2) + { + doCollision = hf.getMaterialIndex0(adjFaceIndices[0] >> 1) != PxHeightFieldMaterial::eHOLE + || hf.getMaterialIndex1(adjFaceIndices[1] >> 1) != PxHeightFieldMaterial::eHOLE; + } + else if(adjFaceCount == 1) + { + doCollision = (hf.getMaterialIndex0(adjFaceIndices[0] >> 1) != PxHeightFieldMaterial::eHOLE); + } + + if(doCollision) + { + PxVec3 origin; + PxVec3 direction; + hfUtil.getEdge(edgeIndex, vertexIndex, row, column, origin, direction); + + PxReal s, t; + const PxReal ll = distanceSegmentSegmentSquared( + capsuleSegmentInHfShape.p0, capsuleSegmentInHfShape.computeDirection(), origin, direction, &s, &t); + if ((ll < radiusSquared) && (t >= 0) && (t <= 1)) + { + + // We only want to test the vertices for either rows or columns. + // In this case we have chosen rows (ei == 0). + if (ei != 0 && (t == 0 || t == 1)) + continue; + + const PxVec3 pointOnCapsuleInHfShape = capsuleSegmentInHfShape.getPointAt(s); + const PxVec3 pointOnEdge = origin + t * direction; + const PxVec3 d = pointOnCapsuleInHfShape - pointOnEdge; + //if (hfShape.isDeltaHeightOppositeExtent(d.y)) + if (hf.isDeltaHeightOppositeExtent(d.y)) + { + + // Check if the current edge's normal is within any of it's 2 adjacent faces' Voronoi regions + // If it is, force the normal to that region's face normal + PxReal l; + PxVec3 n = hfUtil.computePointNormal(hfGeom.heightFieldFlags, d, transform1, ll, pointOnEdge.x, pointOnEdge.z, epsSqr, l); + PxVec3 localN = transform1.rotateInv(n); + for (PxU32 j = 0; j < adjFaceCount; j++) + { + const PxVec3 adjNormal = hfUtil.hf2shapen(hf.getTriangleNormalInternal(adjFaceIndices[j])).getNormalized(); + PxU32 triCell = adjFaceIndices[j] >> 1; + PxU32 triRow = triCell/hf.getNbColumnsFast(); + PxU32 triCol = triCell%hf.getNbColumnsFast(); + PxVec3 tv0, tv1, tv2, tvc; + hf.getTriangleVertices(adjFaceIndices[j], triRow, triCol, tv0, tv1, tv2); + tvc = hfUtil.hf2shapep((tv0+tv1+tv2)/3.0f); // compute adjacent triangle center + PxVec3 perp = adjNormal.cross(direction).getNormalized(); // adj face normal cross edge dir + if (perp.dot(tvc-origin) < 0.0f) // make sure perp is pointing toward the center of the triangle + perp = -perp; + // perp is now a vector sticking out of the edge of the triangle (also the test edge) pointing toward the center + // perpendicular to the normal (in triangle plane) + if (perp.dot(localN) > 0.0f) // if the normal is in perp halfspace, clamp it to Voronoi region + { + n = transform1.rotate(adjNormal); + break; + } + } + + const PxVec3 worldPoint = worldCapsule.getPointAt(s); + const PxVec3 p = worldPoint - n * radius; + PxU32 adjTri = adjFaceIndices[0]; + if(adjFaceCount == 2) + { + const PxU16 m0 = hf.getMaterialIndex0(adjFaceIndices[0] >> 1); + if(m0 == PxHeightFieldMaterial::eHOLE) + adjTri = adjFaceIndices[1]; + } + contactBuffer.contact(p, n, l-radius, adjTri); + #if DEBUG_HFNORMAL + printf("n=%.5f %.5f %.5f; d=%.5f\n", n.x, n.y, n.z, l-radius); + #if DEBUG_RENDER_HFCONTACTS + PxScene *s; PxGetPhysics().getScenes(&s, 1, 0); + Cm::RenderOutput((Cm::RenderBuffer&)s->getRenderBuffer()) << Cm::RenderOutput::LINES << PxDebugColor::eARGB_BLUE // red + << p << (p + n * 10.0f); + #endif + #endif + } + } + } + } + + // also perform capsule edge vs HF vertex collision + if (hfUtil.isCollisionVertex(vertexIndex, row, column)) + { + PxVec3 vertex(row * hfGeom.rowScale, hfGeom.heightScale * hf.getHeight(vertexIndex), column * hfGeom.columnScale); + PxReal s; + const PxReal ll = distancePointSegmentSquared(capsuleSegmentInHfShape, vertex, &s); + if (ll < radiusSquared) + { + const PxVec3 pointOnCapsuleInHfShape = capsuleSegmentInHfShape.getPointAt(s); + const PxVec3 d = pointOnCapsuleInHfShape - vertex; + //if (hfShape.isDeltaHeightOppositeExtent(d.y)) + if (hf.isDeltaHeightOppositeExtent(d.y)) + { + // we look through all prior capsule vertex vs HF face contacts and see + // if any of those share a face with hf_edge for the currently considered capsule_edge/hf_vertex contact + bool normalFromFace = false; + PxVec3 n; + PxReal l = 1.0f; + for (PxU32 iVertexContact = 0; iVertexContact < numCapsuleVertexContacts; iVertexContact++) + { + const ContactPoint& cp = contactBuffer.contacts[iVertexContact]; + PxU32 vi0, vi1, vi2; + hf.getTriangleVertexIndices(cp.internalFaceIndex1, vi0, vi1, vi2); + + const PxU32 vi = vertexIndex; + if ((cp.forInternalUse == 0) // if this is a face contact + && (vi == vi0 || vi == vi1 || vi == vi2)) // with one of the face's vertices matching this one + { + n = cp.normal; // then copy the normal from this contact + l = PxAbs(d.dot(n)); + normalFromFace = true; + break; + } + } + + if (!normalFromFace) + n = hfUtil.computePointNormal(hfGeom.heightFieldFlags, d, transform1, ll, vertex.x, vertex.z, epsSqr, l); + + const PxVec3 worldPoint = worldCapsule.getPointAt(s); + + const PxU32 faceIndex = hfUtil.getVertexFaceIndex(vertexIndex, row, column); + + const PxVec3 p = worldPoint - n * radius; + contactBuffer.contact(p, n, l-radius, faceIndex); + #if DEBUG_HFNORMAL + printf("n=%.5f %.5f %.5f; d=%.5f\n", n.x, n.y, n.z, l-radius); + #if DEBUG_RENDER_HFCONTACTS + PxScene *s; PxGetPhysics().getScenes(&s, 1, 0); + Cm::RenderOutput((Cm::RenderBuffer&)s->getRenderBuffer()) << Cm::RenderOutput::LINES << PxDebugColor::eARGB_BLUE // red + << p << (p + n * 10.0f); + #endif + #endif + } + } // if ll < radiusSquared + } // if isCollisionVertex + } // forEach HF column intersecting with capsule edge AABB + } // forEach HF row intersecting with capsule edge AABB + + return contactBuffer.count>0; +} +}//Gu +}//physx |