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/GuLegacyContactSphereHeightField.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/GuLegacyContactSphereHeightField.cpp')
| -rw-r--r-- | PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactSphereHeightField.cpp | 290 |
1 files changed, 290 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactSphereHeightField.cpp b/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactSphereHeightField.cpp new file mode 100644 index 00000000..5c9ba896 --- /dev/null +++ b/PhysX_3.4/Source/GeomUtils/src/contact/GuLegacyContactSphereHeightField.cpp @@ -0,0 +1,290 @@ +// 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 "GuGeometryUnion.h" +#include "GuHeightFieldData.h" +#include "GuHeightFieldUtil.h" +#include "GuContactMethodImpl.h" +#include "GuContactBuffer.h" + +#define DEBUG_RENDER_HFCONTACTS 0 +#if DEBUG_RENDER_HFCONTACTS +#include "PxPhysics.h" +#include "PxScene.h" +#endif + +using namespace physx; +using namespace Gu; + +// Sphere-heightfield contact generation + +// this code is shared between capsule vertices and sphere +bool GuContactSphereHeightFieldShared(GU_CONTACT_METHOD_ARGS, bool isCapsule) +{ +#if 1 + PX_UNUSED(cache); + PX_UNUSED(renderOutput); + + // Get actual shape data + const PxSphereGeometry& shapeSphere = shape0.get<const PxSphereGeometry>(); + const PxHeightFieldGeometryLL& hfGeom = shape1.get<const PxHeightFieldGeometryLL>(); + + const Gu::HeightField& hf = *static_cast<Gu::HeightField*>(hfGeom.heightField); + const Gu::HeightFieldUtil hfUtil(hfGeom, hf); + + const PxReal radius = shapeSphere.radius; + const PxReal eps = PxReal(0.1) * radius; + + const PxVec3 sphereInHfShape = transform1.transformInv(transform0.p); + + PX_ASSERT(isCapsule || contactBuffer.count==0); + + const PxReal oneOverRowScale = hfUtil.getOneOverRowScale(); + const PxReal oneOverColumnScale = hfUtil.getOneOverColumnScale(); + + // check if the sphere is below the HF surface + if (hfUtil.isShapePointOnHeightField(sphereInHfShape.x, sphereInHfShape.z)) + { + + PxReal fracX, fracZ; + const PxU32 vertexIndex = hfUtil.getHeightField().computeCellCoordinates(sphereInHfShape.x * oneOverRowScale, sphereInHfShape.z * oneOverColumnScale, fracX, fracZ); + + // The sphere origin projects within the bounds of the heightfield in the X-Z plane +// const PxReal sampleHeight = hfShape.getHeightAtShapePoint(sphereInHfShape.x, sphereInHfShape.z); + const PxReal sampleHeight = hfUtil.getHeightAtShapePoint2(vertexIndex, fracX, fracZ); + + const PxReal deltaHeight = sphereInHfShape.y - sampleHeight; + //if (hfShape.isDeltaHeightInsideExtent(deltaHeight, eps)) + if (hf.isDeltaHeightInsideExtent(deltaHeight, eps)) + { + // The sphere origin is 'below' the heightfield surface + // Actually there is an epsilon involved to make sure the + // 'above' surface calculations can deliver a good normal + const PxU32 faceIndex = hfUtil.getFaceIndexAtShapePointNoTest2(vertexIndex, fracX, fracZ); + if (faceIndex != 0xffffffff) + { + + //hfShape.getAbsPoseFast().M.getColumn(1, hfShapeUp); + const PxVec3 hfShapeUp = transform1.q.getBasisVector1(); + + if (hf.getThicknessFast() <= 0) + contactBuffer.contact(transform0.p, hfShapeUp, deltaHeight-radius, faceIndex); + else + contactBuffer.contact(transform0.p, -hfShapeUp, -deltaHeight-radius, faceIndex); + + return true; + } + + return false; + } + + } + + const PxReal epsSqr = eps * eps; + + const PxReal inflatedRadius = radius + params.mContactDistance; + const PxReal inflatedRadiusSquared = inflatedRadius * inflatedRadius; + + const PxVec3 sphereInHF = hfUtil.shape2hfp(sphereInHfShape); + + const PxReal radiusOverRowScale = inflatedRadius * PxAbs(oneOverRowScale); + const PxReal radiusOverColumnScale = inflatedRadius * PxAbs(oneOverColumnScale); + + const PxU32 minRow = hf.getMinRow(sphereInHF.x - radiusOverRowScale); + const PxU32 maxRow = hf.getMaxRow(sphereInHF.x + radiusOverRowScale); + const PxU32 minColumn = hf.getMinColumn(sphereInHF.z - radiusOverColumnScale); + const PxU32 maxColumn = hf.getMaxColumn(sphereInHF.z + radiusOverColumnScale); + + // this assert is here because the following code depends on it for reasonable performance for high-count situations + PX_COMPILE_TIME_ASSERT(ContactBuffer::MAX_CONTACTS == 64); + + const PxU32 nbColumns = hf.getNbColumnsFast(); + +#define HFU Gu::HeightFieldUtil + PxU32 numFaceContacts = 0; + for (PxU32 i = 0; i<2; i++) + { + const bool facesOnly = (i == 0); + // first we go over faces-only meaning only contacts directly in Voronoi regions of faces + // at second pass we consider edges and vertices and clamp the normals to adjacent feature's normal + // if there was a prior contact. it is equivalent to clipping the normal to it's feature's Voronoi region + + for (PxU32 r = minRow; r < maxRow; r++) + { + for (PxU32 c = minColumn; c < maxColumn; c++) + { + + // x--x--x + // | x | + // x x x + // | x | + // x--x--x + PxVec3 closestPoints[11]; + PxU32 closestFeatures[11]; + PxU32 npcp = hfUtil.findClosestPointsOnCell( + r, c, sphereInHfShape, closestPoints, closestFeatures, facesOnly, !facesOnly, true); + + for(PxU32 pi = 0; pi < npcp; pi++) + { + PX_ASSERT(closestFeatures[pi] != 0xffffffff); + const PxVec3 d = sphereInHfShape - closestPoints[pi]; + + if (hf.isDeltaHeightOppositeExtent(d.y)) // See if we are 'above' the heightfield + { + const PxReal dMagSq = d.magnitudeSquared(); + + if (dMagSq > inflatedRadiusSquared) + // Too far above + continue; + + PxReal dMag = -1.0f; // dMag is sqrt(sMadSq) and comes up as a byproduct of other calculations in computePointNormal + PxVec3 n; // n is in world space, rotated by transform1 + PxU32 featureType = HFU::getFeatureType(closestFeatures[pi]); + if (featureType == HFU::eEDGE) + { + PxU32 edgeIndex = HFU::getFeatureIndex(closestFeatures[pi]); + PxU32 adjFaceIndices[2]; + const PxU32 adjFaceCount = hf.getEdgeTriangleIndices(edgeIndex, adjFaceIndices); + PxVec3 origin; + PxVec3 direction; + const PxU32 vertexIndex = edgeIndex / 3; + const PxU32 row = vertexIndex / nbColumns; + const PxU32 col = vertexIndex % nbColumns; + hfUtil.getEdge(edgeIndex, vertexIndex, row, col, origin, direction); + n = hfUtil.computePointNormal( + hfGeom.heightFieldFlags, d, transform1, dMagSq, + closestPoints[pi].x, closestPoints[pi].z, epsSqr, dMag); + PxVec3 localN = transform1.rotateInv(n); + // clamp the edge's normal to its Voronoi region + 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; + } + } + } else if(featureType == HFU::eVERTEX) + { + // AP: these contacts are rare so hopefully it's ok + const PxU32 bufferCount = contactBuffer.count; + const PxU32 vertIndex = HFU::getFeatureIndex(closestFeatures[pi]); + EdgeData adjEdges[8]; + const PxU32 row = vertIndex / nbColumns; + const PxU32 col = vertIndex % nbColumns; + const PxU32 numAdjEdges = ::getVertexEdgeIndices(hf, vertIndex, row, col, adjEdges); + for (PxU32 iPrevEdgeContact = numFaceContacts; iPrevEdgeContact < bufferCount; iPrevEdgeContact++) + { + if (contactBuffer.contacts[iPrevEdgeContact].forInternalUse != HFU::eEDGE) + continue; // skip non-edge contacts (can be other vertex contacts) + + for (PxU32 iAdjEdge = 0; iAdjEdge < numAdjEdges; iAdjEdge++) + // does adjacent edge index for this vertex match a previously encountered edge index? + if (adjEdges[iAdjEdge].edgeIndex == contactBuffer.contacts[iPrevEdgeContact].internalFaceIndex1) + { + // if so, clamp the normal for this vertex to that edge's normal + n = contactBuffer.contacts[iPrevEdgeContact].normal; + dMag = PxSqrt(dMagSq); + break; + } + } + } + + if (dMag == -1.0f) + n = hfUtil.computePointNormal(hfGeom.heightFieldFlags, d, transform1, + dMagSq, closestPoints[pi].x, closestPoints[pi].z, epsSqr, dMag); + + PxVec3 p = transform0.p - n * radius; + #if DEBUG_RENDER_HFCONTACTS + printf("n=%.5f %.5f %.5f; ", n.x, n.y, n.z); + if (n.y < 0.8f) + int a = 1; + 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 + + // temporarily use the internalFaceIndex0 slot in the contact buffer for featureType + contactBuffer.contact( + p, n, dMag - radius, PxU16(featureType), HFU::getFeatureIndex(closestFeatures[pi])); + } + } + } + } + if (facesOnly) + numFaceContacts = contactBuffer.count; + } // for facesOnly = true to false + + if (!isCapsule) // keep the face labels as internalFaceIndex0 if this function is called from inside capsule/HF function + for (PxU32 k = 0; k < numFaceContacts; k++) + contactBuffer.contacts[k].forInternalUse = 0xFFFF; + + for (PxU32 k = numFaceContacts; k < contactBuffer.count; k++) + { + PX_ASSERT(contactBuffer.contacts[k].forInternalUse != HFU::eFACE); + PX_ASSERT(contactBuffer.contacts[k].forInternalUse <= HFU::eVERTEX); + PxU32 featureIndex = contactBuffer.contacts[k].internalFaceIndex1; + if (contactBuffer.contacts[k].forInternalUse == HFU::eEDGE) + contactBuffer.contacts[k].internalFaceIndex1 = hfUtil.getEdgeFaceIndex(featureIndex); + else if (contactBuffer.contacts[k].forInternalUse == HFU::eVERTEX) + { + PxU32 row = featureIndex/hf.getNbColumnsFast(); + PxU32 col = featureIndex%hf.getNbColumnsFast(); + contactBuffer.contacts[k].internalFaceIndex1 = hfUtil.getVertexFaceIndex(featureIndex, row, col); + } + } +#undef HFU + + return contactBuffer.count>0; +#endif +} + +namespace physx +{ +namespace Gu +{ +bool legacyContactSphereHeightfield(GU_CONTACT_METHOD_ARGS) +{ + return GuContactSphereHeightFieldShared(shape0, shape1, transform0, transform1, params, cache, contactBuffer, renderOutput, false); +} + +}//Gu +}//physx |