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/GuLegacyContactConvexHeightField.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/GuLegacyContactConvexHeightField.cpp')
| -rw-r--r-- | PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactConvexHeightField.cpp | 430 |
1 files changed, 430 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactConvexHeightField.cpp b/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactConvexHeightField.cpp new file mode 100644 index 00000000..4103714c --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactConvexHeightField.cpp @@ -0,0 +1,430 @@ +// 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 "GuLegacyTraceLineCallback.h" +#include "GuConvexMeshData.h" +#include "GuEdgeCache.h" +#include "GuConvexHelper.h" +#include "GuContactMethodImpl.h" +#include "GuContactBuffer.h" + +using namespace physx; +using namespace Gu; +using namespace shdfnd::aos; + +#define DISTANCE_BASED_TEST + +// ptchernev TODO: make sure these are ok before shipping +static const bool gCompileConvexVertex = true; +static const bool gCompileEdgeEdge = true; +static const bool gCompileHeightFieldVertex = true; + +/** +\param point vertex tested for penetration (in local hull space) +\param safeNormal if none of the faces are good this becomes the normal +\param normal the direction to translate vertex to depenetrate +\param distance the distance along normal to translate vertex to depenetrate +*/ +static bool GuDepenetrateConvex( const PxVec3& point, + const PxVec3& safeNormal, + const Gu::ConvexHullData& hull, + float contactDistance, + PxVec3& normal, + PxReal& distance, + const Cm::FastVertex2ShapeScaling& scaling, + bool isConvexScaleIdentity) +{ + PxVec3 faceNormal(PxReal(0)); + PxReal distance1 = -PX_MAX_REAL; // cant be more + PxReal distance2 = -PX_MAX_REAL; // cant be more + PxI32 poly1 = -1; + PxI32 poly2 = -2; + +// const Cm::FastVertex2ShapeScaling& scaling = context.mVertex2ShapeSkew[0]; + + for (PxU32 poly = 0; poly < hull.mNbPolygons; poly++) + { + PX_ALIGN(16, PxPlane) shapeSpacePlane; + if(isConvexScaleIdentity) + { + V4StoreA(V4LoadU(&hull.mPolygons[poly].mPlane.n.x), &shapeSpacePlane.n.x); + } + else + { + const PxPlane& vertSpacePlane = hull.mPolygons[poly].mPlane; + scaling.transformPlaneToShapeSpace(vertSpacePlane.n, vertSpacePlane.d, shapeSpacePlane.n, shapeSpacePlane.d);//transform plane into shape space + } + +#ifdef DISTANCE_BASED_TEST + // PT: I'm not really sure about contactDistance here + const PxReal d = shapeSpacePlane.distance(point) - contactDistance; +#else + const PxReal d = shapeSpacePlane.distance(point); +#endif + + if (d >= 0) + { + // no penetration at all + return false; + } + + //const PxVec3& n = plane.normal; + const PxReal proj = shapeSpacePlane.n.dot(safeNormal); + if (proj > 0) + { + if (d > distance1) // less penetration + { + distance1 = d; + faceNormal = shapeSpacePlane.n; + poly1 = PxI32(poly); + } + + // distance2 / d = 1 / proj + const PxReal tmp = d / proj; + if (tmp > distance2) + { + distance2 = tmp; + poly2 = PxI32(poly); + } + } + } + + if (poly1 == poly2) + { + PX_ASSERT(faceNormal.magnitudeSquared() != 0.0f); + normal = faceNormal; + distance = -distance1; + } + else + { + normal = safeNormal; + distance = -distance2; + } + + return true; +} + +//Box-Heightfield and Convex-Heightfield do not support positive values for contactDistance, +//and if in this case we would emit contacts normally, we'd cause things to jitter. +//as a workaround we add contactDistance to the distance values that we emit in contacts. +//this has the effect that the biasing will work exactly as if we had specified a legacy skinWidth of (contactDistance - restDistance) + +#include "GuContactMethodImpl.h" + +namespace physx +{ +namespace Gu +{ +bool legacyContactConvexHeightfield(GU_CONTACT_METHOD_ARGS) +{ + PX_UNUSED(cache); + PX_UNUSED(renderOutput); + +#ifndef DISTANCE_BASED_TEST + PX_WARN_ONCE(contactDistance > 0.0f, "PxcContactConvexHeightField: Convex-Heightfield does not support distance based contact generation! Ignoring contactOffset > 0!"); +#endif + + // Get actual shape data + const PxConvexMeshGeometryLL& shapeConvex = shape0.get<const PxConvexMeshGeometryLL>(); + const PxHeightFieldGeometryLL& hfGeom = shape1.get<const PxHeightFieldGeometryLL>(); + + Cm::Matrix34 convexShapeAbsPose(transform0); + Cm::Matrix34 hfShapeAbsPose(transform1); + + PX_ASSERT(contactBuffer.count==0); + + const Gu::HeightField& hf = *static_cast<Gu::HeightField*>(hfGeom.heightField); + const Gu::HeightFieldUtil hfUtil(hfGeom, hf); + + const bool isConvexScaleIdentity = shapeConvex.scale.isIdentity(); + Cm::FastVertex2ShapeScaling convexScaling; // PT: TODO: remove default ctor + if(!isConvexScaleIdentity) + convexScaling.init(shapeConvex.scale); + + const PxMat33& left = hfShapeAbsPose.m; + const PxMat33& right = convexShapeAbsPose.m; + + Cm::Matrix34 convexShape2HfShape(left.getInverse()* right, left.getInverse()*(convexShapeAbsPose.p - hfShapeAbsPose.p)); + Cm::Matrix34 convexVertex2World( right * convexScaling.getVertex2ShapeSkew(),convexShapeAbsPose.p ); + + // Allocate space for transformed vertices. + const Gu::ConvexHullData* PX_RESTRICT hull = shapeConvex.hullData; + PxVec3* PX_RESTRICT convexVerticesInHfShape = reinterpret_cast<PxVec3*>(PxAlloca(hull->mNbHullVertices*sizeof(PxVec3))); + + // Transform vertices to height field shape + PxMat33 convexShape2HfShape_rot(convexShape2HfShape[0],convexShape2HfShape[1],convexShape2HfShape[2]); + Cm::Matrix34 convexVertices2HfShape(convexShape2HfShape_rot*convexScaling.getVertex2ShapeSkew(), convexShape2HfShape[3]); + const PxVec3* const PX_RESTRICT hullVerts = hull->getHullVertices(); + for(PxU32 i = 0; i<hull->mNbHullVertices; i++) + convexVerticesInHfShape[i] = convexVertices2HfShape.transform(hullVerts[i]); + + PxVec3 convexBoundsInHfShapeMin( PX_MAX_REAL, PX_MAX_REAL, PX_MAX_REAL); + PxVec3 convexBoundsInHfShapeMax(-PX_MAX_REAL, -PX_MAX_REAL, -PX_MAX_REAL); + + // Compute bounds of convex in hf space + for(PxU32 i = 0; i<hull->mNbHullVertices; i++) + { + const PxVec3& v = convexVerticesInHfShape[i]; + + convexBoundsInHfShapeMin.x = PxMin(convexBoundsInHfShapeMin.x, v.x); + convexBoundsInHfShapeMin.y = PxMin(convexBoundsInHfShapeMin.y, v.y); + convexBoundsInHfShapeMin.z = PxMin(convexBoundsInHfShapeMin.z, v.z); + + convexBoundsInHfShapeMax.x = PxMax(convexBoundsInHfShapeMax.x, v.x); + convexBoundsInHfShapeMax.y = PxMax(convexBoundsInHfShapeMax.y, v.y); + convexBoundsInHfShapeMax.z = PxMax(convexBoundsInHfShapeMax.z, v.z); + } + + const bool thicknessNegOrNull = (hf.getThicknessFast() <= 0.0f); // PT: don't do this each time! FCMPs are slow. + + // Compute the height field extreme over the bounds area. + const PxReal oneOverRowScale = hfUtil.getOneOverRowScale(); + const PxReal oneOverColumnScale = hfUtil.getOneOverColumnScale(); + + PxU32 minRow; + PxU32 maxRow; + PxU32 minColumn; + PxU32 maxColumn; + + minRow = hf.getMinRow(convexBoundsInHfShapeMin.x * oneOverRowScale); + maxRow = hf.getMaxRow(convexBoundsInHfShapeMax.x * oneOverRowScale); + + minColumn = hf.getMinColumn(convexBoundsInHfShapeMin.z * oneOverColumnScale); + maxColumn = hf.getMaxColumn(convexBoundsInHfShapeMax.z * oneOverColumnScale); + + PxReal hfExtreme = hf.computeExtreme(minRow, maxRow, minColumn, maxColumn); + + hfExtreme *= hfGeom.heightScale; + + + // Return if convex is on the wrong side of the extreme. + if (thicknessNegOrNull) + { + if (convexBoundsInHfShapeMin.y > hfExtreme) return false; + } + else + { + if (convexBoundsInHfShapeMax.y < hfExtreme) return false; + } + + // Test convex vertices + if (gCompileConvexVertex) + { + for(PxU32 i=0; i<hull->mNbHullVertices; i++) + { + const PxVec3& convexVertexInHfShape = convexVerticesInHfShape[i]; + + //////// SAME CODE AS IN BOX-HF + const bool insideExtreme = thicknessNegOrNull ? (convexVertexInHfShape.y < hfExtreme) : (convexVertexInHfShape.y > hfExtreme); + + if (insideExtreme && hfUtil.isShapePointOnHeightField(convexVertexInHfShape.x, convexVertexInHfShape.z)) + { + // PT: compute this once, reuse results (3 times!) + // PT: TODO: also reuse this in EE tests + PxReal fracX, fracZ; + const PxU32 vertexIndex = hfUtil.getHeightField().computeCellCoordinates(convexVertexInHfShape.x * oneOverRowScale, convexVertexInHfShape.z * oneOverColumnScale, fracX, fracZ); + + const PxReal y = hfUtil.getHeightAtShapePoint2(vertexIndex, fracX, fracZ); + + const PxReal dy = convexVertexInHfShape.y - y; + #ifdef DISTANCE_BASED_TEST + if (hf.isDeltaHeightInsideExtent(dy, params.mContactDistance/**2.0f*/)) + #else + if (hf.isDeltaHeightInsideExtent(dy)) + #endif + { + const PxU32 faceIndex = hfUtil.getFaceIndexAtShapePointNoTest2(vertexIndex, fracX, fracZ); + if (faceIndex != 0xffffffff) + { + PxVec3 n; + n = hfUtil.getNormalAtShapePoint2(vertexIndex, fracX, fracZ); + n = n.getNormalized(); + + contactBuffer + #ifdef DISTANCE_BASED_TEST + .contact(convexVertex2World.transform(hullVerts[i]), hfShapeAbsPose.rotate(n), n.y*dy/* - contactDistance*/, faceIndex); + #else + .contact(convexVertex2World.transform(hullVerts[i]), hfShapeAbsPose.rotate(n), n.y*dy + contactDistance, faceIndex);//add contactDistance to compensate for fact that we don't support dist based contacts! See comment at start of funct. + #endif + } + } + } + ////////~SAME CODE AS IN BOX-HF + } + } + + // Test convex edges + if (gCompileEdgeEdge) + { + // create helper class for the trace segment + GuContactHeightfieldTraceSegmentHelper traceSegmentHelper(hfUtil); + + if(1) + { + PxU32 numPolygons = hull->mNbPolygons; + const Gu::HullPolygonData* polygons = hull->mPolygons; + const PxU8* vertexData = hull->getVertexData8(); + + ConvexEdge edges[512]; + PxU32 nbEdges = findUniqueConvexEdges(512, edges, numPolygons, polygons, vertexData); + + for(PxU32 i=0;i<nbEdges;i++) + { + const PxVec3 convexNormalInHfShape = convexVertices2HfShape.rotate(edges[i].normal); + if(convexNormalInHfShape.y>0.0f) + continue; + + const PxU8 vi0 = edges[i].vref0; + const PxU8 vi1 = edges[i].vref1; + + const PxVec3& sv0 = convexVerticesInHfShape[vi0]; + const PxVec3& sv1 = convexVerticesInHfShape[vi1]; + + if (thicknessNegOrNull) + { + if ((sv0.y > hfExtreme) && (sv1.y > hfExtreme)) continue; + } + else + { + if ((sv0.y < hfExtreme) && (sv1.y < hfExtreme)) continue; + } + GuContactTraceSegmentCallback cb(sv1 - sv0, contactBuffer, hfShapeAbsPose, params.mContactDistance); + traceSegmentHelper.traceSegment(sv0, sv1, &cb); + } + } + else + { + Gu::EdgeCache edgeCache; + PxU32 numPolygons = hull->mNbPolygons; + const Gu::HullPolygonData* polygons = hull->mPolygons; + const PxU8* vertexData = hull->getVertexData8(); + while (numPolygons--) + { + const Gu::HullPolygonData& polygon = *polygons++; + const PxU8* vRefBase = vertexData + polygon.mVRef8; + + PxU32 numEdges = polygon.mNbVerts; + + PxU32 a = numEdges - 1; + PxU32 b = 0; + while(numEdges--) + { + PxU8 vi0 = vRefBase[a]; + PxU8 vi1 = vRefBase[b]; + + + if(vi1 < vi0) + { + PxU8 tmp = vi0; + vi0 = vi1; + vi1 = tmp; + } + + a = b; + b++; + + // avoid processing edges 2x if possible (this will typically have cache misses about 5% of the time + // leading to 5% redundant work). + if (edgeCache.isInCache(vi0, vi1)) + continue; + + const PxVec3& sv0 = convexVerticesInHfShape[vi0]; + const PxVec3& sv1 = convexVerticesInHfShape[vi1]; + + if (thicknessNegOrNull) + { + if ((sv0.y > hfExtreme) && (sv1.y > hfExtreme)) + continue; + } + else + { + if ((sv0.y < hfExtreme) && (sv1.y < hfExtreme)) + continue; + } + GuContactTraceSegmentCallback cb(sv1 - sv0, contactBuffer, hfShapeAbsPose, params.mContactDistance); + traceSegmentHelper.traceSegment(sv0, sv1, &cb); + } + } + } + } + + // Test height field vertices + if (gCompileHeightFieldVertex) + { + // Iterate over HeightField vertices inside the projected box bounds. + for(PxU32 row = minRow; row <= maxRow; row++) + { + for(PxU32 column = minColumn; column <= maxColumn; column++) + { + const PxU32 vertexIndex = row * hf.getNbColumnsFast() + column; + + if (!hfUtil.isCollisionVertex(vertexIndex, row, column)) + continue; + + const PxVec3 hfVertex(hfGeom.rowScale * row, hfGeom.heightScale * hf.getHeight(vertexIndex), hfGeom.columnScale * column); + + const PxVec3 nrm = hfUtil.getVertexNormal(vertexIndex, row, column); + PxVec3 hfVertexNormal = thicknessNegOrNull ? nrm : -nrm; + hfVertexNormal = hfVertexNormal.getNormalized(); + const PxVec3 hfVertexNormalInConvexShape = convexShape2HfShape.rotateTranspose(hfVertexNormal); + PxVec3 hfVertexInConvexShape = convexShape2HfShape.transformTranspose(hfVertex); + PxReal depth; + PxVec3 normal; + if (!GuDepenetrateConvex(hfVertexInConvexShape, -hfVertexNormalInConvexShape, *hull, params.mContactDistance, normal, depth, + convexScaling, + isConvexScaleIdentity)) + { + continue; + } + PxVec3 normalInHfShape = convexShape2HfShape.rotate(-normal); + hfUtil.clipShapeNormalToVertexVoronoi(normalInHfShape, vertexIndex, row, column); + if (normalInHfShape.dot(hfVertexNormal) < PX_EPS_REAL) // AP scaffold: verify this is impossible + continue; + + normalInHfShape = normalInHfShape.getNormalized(); + PxU32 faceIndex = hfUtil.getVertexFaceIndex(vertexIndex, row, column); + contactBuffer + .contact(hfShapeAbsPose.transform(hfVertex), hfShapeAbsPose.rotate(normalInHfShape), + #ifdef DISTANCE_BASED_TEST + -depth, + #else + //add contactDistance to compensate for fact that we don't support dist based contacts! + // See comment at start of funct. + -depth + contactDistance, + #endif + faceIndex); + } + } + } + + return contactBuffer.count>0; +} +}//Gu +}//physx |