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/LowLevelDynamics/src/DyContactReduction.h | |
| 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/LowLevelDynamics/src/DyContactReduction.h')
| -rw-r--r-- | PhysX_3.4/Source/LowLevelDynamics/src/DyContactReduction.h | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/PhysX_3.4/Source/LowLevelDynamics/src/DyContactReduction.h b/PhysX_3.4/Source/LowLevelDynamics/src/DyContactReduction.h new file mode 100644 index 00000000..a02fe8e9 --- /dev/null +++ b/PhysX_3.4/Source/LowLevelDynamics/src/DyContactReduction.h @@ -0,0 +1,409 @@ +// 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. + +#ifndef DY_CONTACT_REDUCTION_H +#define DY_CONTACT_REDUCTION_H + +#include "GuContactPoint.h" +#include "PxsMaterialManager.h" + +namespace physx +{ + + +namespace Dy +{ + +//KS - might be OK with 4 but 5 guarantees the deepest + 4 contacts that contribute to largest surface area +#define CONTACT_REDUCTION_MAX_CONTACTS 6 +#define CONTACT_REDUCTION_MAX_PATCHES 32 +#define PXS_NORMAL_TOLERANCE 0.995f +#define PXS_SEPARATION_TOLERANCE 0.001f + + + //A patch contains a normal, pair of material indices and a list of indices. These indices are + //used to index into the PxContact array that's passed by the user + struct ReducedContactPatch + { + PxU32 numContactPoints; + PxU32 contactPoints[CONTACT_REDUCTION_MAX_CONTACTS]; + }; + + struct ContactPatch + { + PxVec3 rootNormal; + ContactPatch* mNextPatch; + PxReal maxPenetration; + PxU16 startIndex; + PxU16 stride; + PxU16 rootIndex; + PxU16 index; + }; + + struct SortBoundsPredicateManifold + { + bool operator()(const ContactPatch* idx1, const ContactPatch* idx2) const + { + return idx1->maxPenetration < idx2->maxPenetration; + } + }; + + + + template <PxU32 MaxPatches> + class ContactReduction + { + public: + ReducedContactPatch mPatches[MaxPatches]; + PxU32 mNumPatches; + ContactPatch mIntermediatePatches[CONTACT_REDUCTION_MAX_PATCHES]; + ContactPatch* mIntermediatePatchesPtrs[CONTACT_REDUCTION_MAX_PATCHES]; + PxU32 mNumIntermediatePatches; + Gu::ContactPoint* PX_RESTRICT mOriginalContacts; + PxsMaterialInfo* PX_RESTRICT mMaterialInfo; + PxU32 mNumOriginalContacts; + + ContactReduction(Gu::ContactPoint* PX_RESTRICT originalContacts, PxsMaterialInfo* PX_RESTRICT materialInfo, PxU32 numContacts) : + mNumPatches(0), mNumIntermediatePatches(0), mOriginalContacts(originalContacts), mMaterialInfo(materialInfo), mNumOriginalContacts(numContacts) + { + } + + void reduceContacts() + { + //First pass, break up into contact patches, storing the start and stride of the patches + //We will need to have contact patches and then coallesce them + mIntermediatePatches[0].rootNormal = mOriginalContacts[0].normal; + mIntermediatePatches[0].mNextPatch = NULL; + mIntermediatePatches[0].startIndex = 0; + mIntermediatePatches[0].rootIndex = 0; + mIntermediatePatches[0].maxPenetration = mOriginalContacts[0].separation; + mIntermediatePatches[0].index = 0; + PxU16 numPatches = 1; + //PxU32 startIndex = 0; + PxU32 numUniquePatches = 1; + PxU16 m = 1; + for(; m < mNumOriginalContacts; ++m) + { + PxI32 index = -1; + for(PxU32 b = numPatches; b > 0; --b) + { + ContactPatch& patch = mIntermediatePatches[b-1]; + if(mMaterialInfo[patch.startIndex].mMaterialIndex0 == mMaterialInfo[m].mMaterialIndex0 && mMaterialInfo[patch.startIndex].mMaterialIndex1 == mMaterialInfo[m].mMaterialIndex1 && + patch.rootNormal.dot(mOriginalContacts[m].normal) >= PXS_NORMAL_TOLERANCE) + { + index = PxI32(b-1); + break; + } + } + + if(index != numPatches - 1) + { + mIntermediatePatches[numPatches-1].stride = PxU16(m - mIntermediatePatches[numPatches - 1].startIndex); + //Create a new patch... + if(numPatches == CONTACT_REDUCTION_MAX_PATCHES) + { + break; + } + mIntermediatePatches[numPatches].startIndex = m; + mIntermediatePatches[numPatches].mNextPatch = NULL; + if(index == -1) + { + mIntermediatePatches[numPatches].rootIndex = numPatches; + mIntermediatePatches[numPatches].rootNormal = mOriginalContacts[m].normal; + mIntermediatePatches[numPatches].maxPenetration = mOriginalContacts[m].separation; + mIntermediatePatches[numPatches].index = numPatches; + ++numUniquePatches; + } + else + { + //Find last element in the link + PxU16 rootIndex = mIntermediatePatches[index].rootIndex; + mIntermediatePatches[index].mNextPatch = &mIntermediatePatches[numPatches]; + mIntermediatePatches[numPatches].rootNormal = mIntermediatePatches[index].rootNormal; + mIntermediatePatches[rootIndex].maxPenetration = mIntermediatePatches[numPatches].maxPenetration = PxMin(mIntermediatePatches[rootIndex].maxPenetration, mOriginalContacts[m].separation); + mIntermediatePatches[numPatches].rootIndex = rootIndex; + mIntermediatePatches[numPatches].index = numPatches; + } + ++numPatches; + } + } + mIntermediatePatches[numPatches-1].stride = PxU16(m - mIntermediatePatches[numPatches-1].startIndex); + + //OK, we have a list of contact patches so that we can start contact reduction per-patch + + //OK, now we can go and reduce the contacts on a per-patch basis... + + for(PxU32 a = 0; a < numPatches; ++a) + { + mIntermediatePatchesPtrs[a] = &mIntermediatePatches[a]; + } + + + SortBoundsPredicateManifold predicate; + Ps::sort(mIntermediatePatchesPtrs, numPatches, predicate); + + PxU32 numReducedPatches = 0; + for(PxU32 a = 0; a < numPatches; ++a) + { + if(mIntermediatePatchesPtrs[a]->rootIndex == mIntermediatePatchesPtrs[a]->index) + { + //Reduce this patch... + if(numReducedPatches == MaxPatches) + break; + + ReducedContactPatch& reducedPatch = mPatches[numReducedPatches++]; + //OK, now we need to work out if we have to reduce patches... + PxU32 contactCount = 0; + { + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + + while(tmpPatch) + { + contactCount += tmpPatch->stride; + tmpPatch = tmpPatch->mNextPatch; + } + } + + if(contactCount <= CONTACT_REDUCTION_MAX_CONTACTS) + { + //Just add the contacts... + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + + PxU32 ind = 0; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + reducedPatch.contactPoints[ind++] = tmpPatch->startIndex + b; + } + tmpPatch = tmpPatch->mNextPatch; + } + reducedPatch.numContactPoints = contactCount; + } + else + { + //Iterate through and find the most extreme point + + + PxU32 ind = 0; + + { + PxReal dist = 0.f; + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + PxReal magSq = mOriginalContacts[tmpPatch->startIndex + b].point.magnitudeSquared(); + if(dist < magSq) + { + ind = tmpPatch->startIndex + b; + dist = magSq; + } + } + tmpPatch = tmpPatch->mNextPatch; + } + } + reducedPatch.contactPoints[0] = ind; + const PxVec3 p0 = mOriginalContacts[ind].point; + + //Now find the point farthest from this point... + { + PxReal maxDist = 0.f; + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + PxReal magSq = (p0 - mOriginalContacts[tmpPatch->startIndex + b].point).magnitudeSquared(); + if(magSq > maxDist) + { + ind = tmpPatch->startIndex + b; + maxDist = magSq; + } + } + tmpPatch = tmpPatch->mNextPatch; + } + } + reducedPatch.contactPoints[1] = ind; + const PxVec3 p1 = mOriginalContacts[ind].point; + + //Now find the point farthest from the segment + + PxVec3 n = (p0 - p1).cross(mIntermediatePatchesPtrs[a]->rootNormal); + + //PxReal tVal = 0.f; + { + PxReal maxDist = 0.f; + //PxReal tmpTVal; + + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + + //PxReal magSq = tmpDistancePointSegmentSquared(p0, p1, mOriginalContacts[tmpPatch->startIndex + b].point, tmpTVal); + PxReal magSq = (mOriginalContacts[tmpPatch->startIndex + b].point - p0).dot(n); + if(magSq > maxDist) + { + ind = tmpPatch->startIndex + b; + //tVal = tmpTVal; + maxDist = magSq; + } + } + tmpPatch = tmpPatch->mNextPatch; + } + } + reducedPatch.contactPoints[2] = ind; + + //const PxVec3 closest = (p0 + (p1 - p0) * tVal); + + const PxVec3 dir = -n;//closest - p3; + + { + PxReal maxDist = 0.f; + //PxReal tVal = 0.f; + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + PxReal magSq = (mOriginalContacts[tmpPatch->startIndex + b].point - p0).dot(dir); + if(magSq > maxDist) + { + ind = tmpPatch->startIndex + b; + maxDist = magSq; + } + } + tmpPatch = tmpPatch->mNextPatch; + } + } + reducedPatch.contactPoints[3] = ind; + + //Now, we iterate through all the points, and cluster the points. From this, we establish the deepest point that's within a + //tolerance of this point and keep that point + + PxReal separation[CONTACT_REDUCTION_MAX_CONTACTS]; + PxU32 deepestInd[CONTACT_REDUCTION_MAX_CONTACTS]; + for(PxU32 i = 0; i < 4; ++i) + { + PxU32 index = reducedPatch.contactPoints[i]; + separation[i] = mOriginalContacts[index].separation - PXS_SEPARATION_TOLERANCE; + deepestInd[i] = index; + } + + ContactPatch* tmpPatch = mIntermediatePatchesPtrs[a]; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + Gu::ContactPoint& point = mOriginalContacts[tmpPatch->startIndex + b]; + + PxReal distance = PX_MAX_REAL; + PxU32 index = 0; + for(PxU32 c = 0; c < 4; ++c) + { + PxVec3 dif = mOriginalContacts[reducedPatch.contactPoints[c]].point - point.point; + PxReal d = dif.magnitudeSquared(); + if(distance > d) + { + distance = d; + index = c; + } + } + if(separation[index] > point.separation) + { + deepestInd[index] = tmpPatch->startIndex+b; + separation[index] = point.separation; + } + + } + tmpPatch = tmpPatch->mNextPatch; + } + + bool chosen[64]; + PxMemZero(chosen, sizeof(chosen)); + for(PxU32 i = 0; i < 4; ++i) + { + reducedPatch.contactPoints[i] = deepestInd[i]; + chosen[deepestInd[i]] = true; + } + + for(PxU32 i = 4; i < CONTACT_REDUCTION_MAX_CONTACTS; ++i) + { + separation[i] = PX_MAX_REAL; + deepestInd[i] = 0; + } + tmpPatch = mIntermediatePatchesPtrs[a]; + while(tmpPatch) + { + for(PxU32 b = 0; b < tmpPatch->stride; ++b) + { + if(!chosen[tmpPatch->startIndex+b]) + { + Gu::ContactPoint& point = mOriginalContacts[tmpPatch->startIndex + b]; + for(PxU32 j = 4; j < CONTACT_REDUCTION_MAX_CONTACTS; ++j) + { + if(point.separation < separation[j]) + { + for(PxU32 k = CONTACT_REDUCTION_MAX_CONTACTS-1; k > j; --k) + { + separation[k] = separation[k-1]; + deepestInd[k] = deepestInd[k-1]; + } + separation[j] = point.separation; + deepestInd[j] = tmpPatch->startIndex+b; + break; + } + } + } + } + tmpPatch = tmpPatch->mNextPatch; + } + + for(PxU32 i = 4; i < CONTACT_REDUCTION_MAX_CONTACTS; ++i) + { + reducedPatch.contactPoints[i] = deepestInd[i]; + } + + reducedPatch.numContactPoints = CONTACT_REDUCTION_MAX_CONTACTS; + } + } + } + mNumPatches = numReducedPatches; + } + + }; +} + +} + + +#endif //DY_CONTACT_REDUCTION_H |