// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2018 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_PREP_SHARED_H #define DY_CONTACT_PREP_SHARED_H #include "foundation/PxPreprocessor.h" #include "PxSceneDesc.h" #include "PsVecMath.h" #include "PsMathUtils.h" #include "DyContactPrep.h" #include "DyCorrelationBuffer.h" #include "DyArticulationContactPrep.h" #include "PxsContactManager.h" #include "PxsContactManagerState.h" namespace physx { namespace Dy { PX_FORCE_INLINE bool pointsAreClose(const PxTransform& body1ToBody0, const PxVec3& localAnchor0, const PxVec3& localAnchor1, const PxVec3& axis, float correlDist) { const PxVec3 body0PatchPoint1 = body1ToBody0.transform(localAnchor1); return PxAbs((localAnchor0 - body0PatchPoint1).dot(axis))(frictionCookie); //Try working out relative transforms! TODO - can we compute this lazily for the first friction patch bool evaluated = false; PxTransform body1ToBody0; while(frictionPatchCount--) { Ps::prefetchLine(patches,128); const FrictionPatch& patch = *patches++; PX_ASSERT (patch.broken == 0 || patch.broken == 1); if(!patch.broken) { // if the eDISABLE_STRONG_FRICTION flag is there we need to blow away the previous frame's friction correlation, so // that we can associate each friction anchor with a target velocity. So we lose strong friction. if(patch.anchorCount != 0 && !(patch.materialFlags & PxMaterialFlag::eDISABLE_STRONG_FRICTION)) { PX_ASSERT(patch.anchorCount <= 2); if(!evaluated) { body1ToBody0 = bodyFrame0.transformInv(bodyFrame1); evaluated = true; } if(patch.body0Normal.dot(body1ToBody0.rotate(patch.body1Normal)) > PXC_SAME_NORMAL) { if(!isSeparated(patch, body1ToBody0, correlationDistance)) { if(c.frictionPatchCount == CorrelationBuffer::MAX_FRICTION_PATCHES) return false; { c.contactID[c.frictionPatchCount][0] = 0xffff; c.contactID[c.frictionPatchCount][1] = 0xffff; //Rotate the contact normal into world space c.frictionPatchWorldNormal[c.frictionPatchCount] = bodyFrame0.rotate(patch.body0Normal); c.frictionPatchContactCounts[c.frictionPatchCount] = 0; c.patchBounds[c.frictionPatchCount].setEmpty(); c.correlationListHeads[c.frictionPatchCount] = CorrelationBuffer::LIST_END; PxMemCopy(&c.frictionPatches[c.frictionPatchCount++], &patch, sizeof(FrictionPatch)); } } } } } } return true; } PX_FORCE_INLINE PxU32 extractContacts(Gu::ContactBuffer& buffer, PxsContactManagerOutput& npOutput, bool& hasMaxImpulse, bool& hasTargetVelocity, PxReal& invMassScale0, PxReal& invMassScale1, PxReal& invInertiaScale0, PxReal& invInertiaScale1, PxReal defaultMaxImpulse) { PxContactStreamIterator iter(npOutput.contactPatches, npOutput.contactPoints, npOutput.getInternalFaceIndice(), npOutput.nbPatches, npOutput.nbContacts); PxU32 numContacts = buffer.count, origContactCount = buffer.count; if(!iter.forceNoResponse) { invMassScale0 = iter.getInvMassScale0(); invMassScale1 = iter.getInvMassScale1(); invInertiaScale0 = iter.getInvInertiaScale0(); invInertiaScale1 = iter.getInvInertiaScale1(); hasMaxImpulse = (iter.patch->internalFlags & PxContactPatch::eHAS_MAX_IMPULSE) != 0; hasTargetVelocity = (iter.patch->internalFlags & PxContactPatch::eHAS_TARGET_VELOCITY) != 0; while(iter.hasNextPatch()) { iter.nextPatch(); while(iter.hasNextContact()) { iter.nextContact(); Ps::prefetchLine(iter.contact, 128); Ps::prefetchLine(&buffer.contacts[numContacts], 128); PxReal maxImpulse = hasMaxImpulse ? iter.getMaxImpulse() : defaultMaxImpulse; if(maxImpulse != 0.f) { PX_ASSERT(numContacts < Gu::ContactBuffer::MAX_CONTACTS); buffer.contacts[numContacts].normal = iter.getContactNormal(); buffer.contacts[numContacts].point = iter.getContactPoint(); buffer.contacts[numContacts].separation = iter.getSeparation(); //KS - we use the face indices to cache the material indices and flags - avoids bloating the PxContact structure buffer.contacts[numContacts].materialFlags = PxU8(iter.getMaterialFlags()); buffer.contacts[numContacts].maxImpulse = maxImpulse; buffer.contacts[numContacts].staticFriction = iter.getStaticFriction(); buffer.contacts[numContacts].dynamicFriction = iter.getDynamicFriction(); buffer.contacts[numContacts].restitution = iter.getRestitution(); const PxVec3& targetVel = iter.getTargetVel(); buffer.contacts[numContacts].targetVel = targetVel; ++numContacts; } } } } const PxU32 contactCount = numContacts - origContactCount; buffer.count = numContacts; return contactCount; } struct CorrelationListIterator { CorrelationBuffer& buffer; PxU32 currPatch; PxU32 currContact; CorrelationListIterator(CorrelationBuffer& correlationBuffer, PxU32 startPatch) : buffer(correlationBuffer) { //We need to force us to advance the correlation buffer to the first available contact (if one exists) PxU32 newPatch = startPatch, newContact = 0; while(newPatch != CorrelationBuffer::LIST_END && newContact == buffer.contactPatches[newPatch].count) { newPatch = buffer.contactPatches[newPatch].next; newContact = 0; } currPatch = newPatch; currContact = newContact; } //Returns true if it has another contact pre-loaded. Returns false otherwise PX_FORCE_INLINE bool hasNextContact() { return (currPatch != CorrelationBuffer::LIST_END && currContact < buffer.contactPatches[currPatch].count); } inline void nextContact(PxU32& patch, PxU32& contact) { PX_ASSERT(currPatch != CorrelationBuffer::LIST_END); PX_ASSERT(currContact < buffer.contactPatches[currPatch].count); patch = currPatch; contact = currContact; PxU32 newPatch = currPatch, newContact = currContact + 1; while(newPatch != CorrelationBuffer::LIST_END && newContact == buffer.contactPatches[newPatch].count) { newPatch = buffer.contactPatches[newPatch].next; newContact = 0; } currPatch = newPatch; currContact = newContact; } private: CorrelationListIterator& operator=(const CorrelationListIterator&); }; PX_FORCE_INLINE void constructContactConstraint(const Mat33V& invSqrtInertia0, const Mat33V& invSqrtInertia1, const FloatVArg invMassNorLenSq0, const FloatVArg invMassNorLenSq1, const FloatVArg angD0, const FloatVArg angD1, const Vec3VArg bodyFrame0p, const Vec3VArg bodyFrame1p, const Vec3VArg normal, const FloatVArg norVel, const VecCrossV& norCross, const Vec3VArg angVel0, const Vec3VArg angVel1, const FloatVArg invDt, const FloatVArg invDtp8, const FloatVArg restDistance, const FloatVArg maxPenBias, const FloatVArg restitution, const FloatVArg bounceThreshold, const Gu::ContactPoint& contact, SolverContactPoint& solverContact, const FloatVArg ccdMaxSeparation, const Vec3VArg solverOffsetSlop) { const FloatV zero = FZero(); const Vec3V point = V3LoadA(contact.point); const FloatV separation = FLoad(contact.separation); const FloatV cTargetVel = V3Dot(normal, V3LoadA(contact.targetVel)); const Vec3V ra = V3Sub(point, bodyFrame0p); const Vec3V rb = V3Sub(point, bodyFrame1p); //ra = V3Sel(V3IsGrtr(solverOffsetSlop, V3Abs(ra)), V3Zero(), ra); //rb = V3Sel(V3IsGrtr(solverOffsetSlop, V3Abs(rb)), V3Zero(), rb); Vec3V raXn = V3Cross(ra, norCross); Vec3V rbXn = V3Cross(rb, norCross); raXn = V3Sel(V3IsGrtr(solverOffsetSlop, V3Abs(raXn)), V3Zero(), raXn); rbXn = V3Sel(V3IsGrtr(solverOffsetSlop, V3Abs(rbXn)), V3Zero(), rbXn); const Vec3V raXnSqrtInertia = M33MulV3(invSqrtInertia0, raXn); const Vec3V rbXnSqrtInertia = M33MulV3(invSqrtInertia1, rbXn); const FloatV resp0 = FAdd(invMassNorLenSq0, FMul(V3Dot(raXnSqrtInertia, raXnSqrtInertia), angD0)); const FloatV resp1 = FSub(FMul(V3Dot(rbXnSqrtInertia, rbXnSqrtInertia), angD1), invMassNorLenSq1); const FloatV unitResponse = FAdd(resp0, resp1); const FloatV vrel1 = FAdd(norVel, V3Dot(raXn, angVel0)); const FloatV vrel2 = V3Dot(rbXn, angVel1); const FloatV vrel = FSub(vrel1, vrel2); const FloatV velMultiplier = FSel(FIsGrtr(unitResponse, zero), FRecip(unitResponse), zero); const FloatV penetration = FSub(separation, restDistance); const FloatV penetrationInvDt = FMul(penetration, invDt); const FloatV penetrationInvDtPt8 = FMax(maxPenBias, FMul(penetration, invDtp8)); FloatV scaledBias = FMul(velMultiplier, penetrationInvDtPt8); const BoolV isGreater2 = BAnd(BAnd(FIsGrtr(restitution, zero), FIsGrtr(bounceThreshold, vrel)), FIsGrtr(FNeg(vrel), penetrationInvDt)); const BoolV ccdSeparationCondition = FIsGrtrOrEq(ccdMaxSeparation, penetration); scaledBias = FSel(BAnd(ccdSeparationCondition, isGreater2), zero, scaledBias); const FloatV sumVRel(vrel); FloatV targetVelocity = FAdd(cTargetVel, FSel(isGreater2, FMul(FNeg(sumVRel), restitution), zero)); //Note - we add on the initial target velocity targetVelocity = FSub(targetVelocity, vrel); const FloatV biasedErr = FScaleAdd(targetVelocity, velMultiplier, FNeg(scaledBias)); const FloatV unbiasedErr = FScaleAdd(targetVelocity, velMultiplier, FSel(isGreater2, zero, FNeg(FMax(scaledBias, zero)))); //const FloatV unbiasedErr = FScaleAdd(targetVelocity, velMultiplier, FNeg(FMax(scaledBias, zero))); FStore(velMultiplier, &solverContact.velMultiplier); FStore(biasedErr, &solverContact.biasedErr); FStore(unbiasedErr, &solverContact.unbiasedErr); solverContact.maxImpulse = contact.maxImpulse; solverContact.raXn = raXnSqrtInertia; solverContact.rbXn = rbXnSqrtInertia; } } } #endif //DY_CONTACT_PREP_SHARED_H