543 lines
20 KiB
C++
543 lines
20 KiB
C++
|
//
|
||
|
// 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-2019 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 "foundation/PxPreprocessor.h"
|
||
|
#include "PsVecMath.h"
|
||
|
#include "DyArticulationContactPrep.h"
|
||
|
#include "DySolverConstraintDesc.h"
|
||
|
#include "DySolverConstraint1D.h"
|
||
|
#include "DyArticulationHelper.h"
|
||
|
#include "PxcNpWorkUnit.h"
|
||
|
#include "PxsMaterialManager.h"
|
||
|
#include "PxsMaterialCombiner.h"
|
||
|
#include "DyCorrelationBuffer.h"
|
||
|
#include "DySolverConstraintExtShared.h"
|
||
|
#include "DyConstraintPrep.h"
|
||
|
|
||
|
using namespace physx::Gu;
|
||
|
|
||
|
namespace physx
|
||
|
{
|
||
|
|
||
|
namespace Dy
|
||
|
{
|
||
|
|
||
|
// constraint-gen only, since these use getVelocity methods
|
||
|
// which aren't valid during the solver phase
|
||
|
|
||
|
//PX_INLINE void computeFrictionTangents(const Ps::aos::Vec3V& vrel,const Ps::aos::Vec3V& unitNormal, Ps::aos::Vec3V& t0, Ps::aos::Vec3V& t1)
|
||
|
//{
|
||
|
// using namespace Ps::aos;
|
||
|
// //PX_ASSERT(PxAbs(unitNormal.magnitude()-1)<1e-3f);
|
||
|
//
|
||
|
// t0 = V3Sub(vrel, V3Scale(unitNormal, V3Dot(unitNormal, vrel)));
|
||
|
// const FloatV ll = V3Dot(t0, t0);
|
||
|
//
|
||
|
// if (FAllGrtr(ll, FLoad(1e10f))) //can set as low as 0.
|
||
|
// {
|
||
|
// t0 = V3Scale(t0, FRsqrt(ll));
|
||
|
// t1 = V3Cross(unitNormal, t0);
|
||
|
// }
|
||
|
// else
|
||
|
// Ps::normalToTangents(unitNormal, t0, t1); //fallback
|
||
|
//}
|
||
|
|
||
|
PxReal SolverExtBody::projectVelocity(const PxVec3& linear, const PxVec3& angular) const
|
||
|
{
|
||
|
if(mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return mBodyData->projectVelocity(linear, angular);
|
||
|
else
|
||
|
{
|
||
|
const Cm::SpatialVectorV velocity = mArticulation->getLinkVelocity(mLinkIndex);
|
||
|
|
||
|
const FloatV fv = velocity.dot(Cm::SpatialVector(linear, angular));
|
||
|
|
||
|
PxF32 f;
|
||
|
FStore(fv, &f);
|
||
|
return f;
|
||
|
/*PxF32 f;
|
||
|
FStore(getVelocity(*mFsData)[mLinkIndex].dot(Cm::SpatialVector(linear, angular)), &f);
|
||
|
return f;*/
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ps::aos::FloatV SolverExtBody::projectVelocity(const Ps::aos::Vec3V& linear, const Ps::aos::Vec3V& angular) const
|
||
|
{
|
||
|
if (mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
{
|
||
|
return V3SumElems(V3Add(V3Mul(V3LoadA(mBodyData->linearVelocity), linear), V3Mul(V3LoadA(mBodyData->angularVelocity), angular)));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const Cm::SpatialVectorV velocity = mArticulation->getLinkVelocity(mLinkIndex);
|
||
|
|
||
|
return velocity.dot(Cm::SpatialVectorV(linear, angular));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
PxVec3 SolverExtBody::getLinVel() const
|
||
|
{
|
||
|
if(mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return mBodyData->linearVelocity;
|
||
|
else
|
||
|
{
|
||
|
const Vec3V linear = mArticulation->getLinkVelocity(mLinkIndex).linear;
|
||
|
|
||
|
PxVec3 result;
|
||
|
V3StoreU(linear, result);
|
||
|
/*PxVec3 result;
|
||
|
V3StoreU(getVelocity(*mFsData)[mLinkIndex].linear, result);*/
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PxVec3 SolverExtBody::getAngVel() const
|
||
|
{
|
||
|
if(mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return mBodyData->angularVelocity;
|
||
|
else
|
||
|
{
|
||
|
const Vec3V angular = mArticulation->getLinkVelocity(mLinkIndex).angular;
|
||
|
|
||
|
PxVec3 result;
|
||
|
V3StoreU(angular, result);
|
||
|
/*PxVec3 result;
|
||
|
V3StoreU(getVelocity(*mFsData)[mLinkIndex].angular, result);*/
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Ps::aos::Vec3V SolverExtBody::getLinVelV() const
|
||
|
{
|
||
|
if (mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return V3LoadA(mBodyData->linearVelocity);
|
||
|
else
|
||
|
{
|
||
|
return mArticulation->getLinkVelocity(mLinkIndex).linear;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
Vec3V SolverExtBody::getAngVelV() const
|
||
|
{
|
||
|
if (mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return V3LoadA(mBodyData->angularVelocity);
|
||
|
else
|
||
|
{
|
||
|
|
||
|
return mArticulation->getLinkVelocity(mLinkIndex).angular;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Cm::SpatialVectorV SolverExtBody::getVelocity() const
|
||
|
{
|
||
|
if(mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return Cm::SpatialVectorV(V3LoadA(mBodyData->linearVelocity), V3LoadA(mBodyData->angularVelocity));
|
||
|
else
|
||
|
return mArticulation->getLinkVelocity(mLinkIndex);
|
||
|
}
|
||
|
|
||
|
Cm::SpatialVector createImpulseResponseVector(const PxVec3& linear, const PxVec3& angular, const SolverExtBody& body)
|
||
|
{
|
||
|
if(body.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
return Cm::SpatialVector(linear, body.mBodyData->sqrtInvInertia * angular);
|
||
|
|
||
|
return Cm::SpatialVector(linear, angular);
|
||
|
}
|
||
|
|
||
|
Cm::SpatialVectorV createImpulseResponseVector(const Ps::aos::Vec3V& linear, const Ps::aos::Vec3V& angular, const SolverExtBody& body)
|
||
|
{
|
||
|
if (body.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
{
|
||
|
return Cm::SpatialVectorV(linear, M33MulV3(M33Load(body.mBodyData->sqrtInvInertia), angular));
|
||
|
}
|
||
|
return Cm::SpatialVectorV(linear, angular);
|
||
|
}
|
||
|
|
||
|
PxReal getImpulseResponse(const SolverExtBody& b0, const Cm::SpatialVector& impulse0, Cm::SpatialVector& deltaV0, PxReal dom0, PxReal angDom0,
|
||
|
const SolverExtBody& b1, const Cm::SpatialVector& impulse1, Cm::SpatialVector& deltaV1, PxReal dom1, PxReal angDom1,
|
||
|
Cm::SpatialVectorF* Z, bool allowSelfCollision)
|
||
|
{
|
||
|
PxReal response;
|
||
|
allowSelfCollision = false;
|
||
|
// right now self-collision with contacts crashes the solver
|
||
|
|
||
|
//KS - knocked this out to save some space on SPU
|
||
|
if(allowSelfCollision && b0.mLinkIndex!=PxSolverConstraintDesc::NO_LINK && b0.mArticulation == b1.mArticulation && 0)
|
||
|
{
|
||
|
/*ArticulationHelper::getImpulseSelfResponse(*b0.mFsData,b0.mLinkIndex, impulse0, deltaV0,
|
||
|
b1.mLinkIndex, impulse1, deltaV1);*/
|
||
|
|
||
|
b0.mArticulation->getImpulseSelfResponse(b0.mLinkIndex, b1.mLinkIndex, Z, impulse0.scale(dom0, angDom0), impulse1.scale(dom1, angDom1),
|
||
|
deltaV0, deltaV1);
|
||
|
|
||
|
response = impulse0.dot(deltaV0) + impulse1.dot(deltaV1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(b0.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
{
|
||
|
deltaV0.linear = impulse0.linear * b0.mBodyData->invMass * dom0;
|
||
|
deltaV0.angular = impulse0.angular * angDom0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b0.mArticulation->getImpulseResponse(b0.mLinkIndex, Z, impulse0.scale(dom0, angDom0), deltaV0);
|
||
|
}
|
||
|
|
||
|
response = impulse0.dot(deltaV0);
|
||
|
if(b1.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
{
|
||
|
deltaV1.linear = impulse1.linear * b1.mBodyData->invMass * dom1;
|
||
|
deltaV1.angular = impulse1.angular * angDom1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b1.mArticulation->getImpulseResponse( b1.mLinkIndex, Z, impulse1.scale(dom1, angDom1), deltaV1);
|
||
|
}
|
||
|
response += impulse1.dot(deltaV1);
|
||
|
}
|
||
|
|
||
|
return response;
|
||
|
}
|
||
|
|
||
|
FloatV getImpulseResponse(const SolverExtBody& b0, const Cm::SpatialVectorV& impulse0, Cm::SpatialVectorV& deltaV0, const FloatV& dom0, const FloatV& angDom0,
|
||
|
const SolverExtBody& b1, const Cm::SpatialVectorV& impulse1, Cm::SpatialVectorV& deltaV1, const FloatV& dom1, const FloatV& angDom1,
|
||
|
Cm::SpatialVectorV* Z, bool /*allowSelfCollision*/)
|
||
|
{
|
||
|
Vec3V response;
|
||
|
{
|
||
|
|
||
|
if (b0.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
{
|
||
|
deltaV0.linear = V3Scale(impulse0.linear, FMul(FLoad(b0.mBodyData->invMass), dom0));
|
||
|
deltaV0.angular = V3Scale(impulse0.angular, angDom0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b0.mArticulation->getImpulseResponse(b0.mLinkIndex, Z, impulse0.scale(dom0, angDom0), deltaV0);
|
||
|
}
|
||
|
|
||
|
response = V3Add(V3Mul(impulse0.linear, deltaV0.linear), V3Mul(impulse0.angular, deltaV0.angular));
|
||
|
if (b1.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
{
|
||
|
deltaV1.linear = V3Scale(impulse1.linear, FMul(FLoad(b1.mBodyData->invMass), dom1));
|
||
|
deltaV1.angular = V3Scale(impulse1.angular, angDom1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
b1.mArticulation->getImpulseResponse(b1.mLinkIndex, Z, impulse1.scale(dom1, angDom1), deltaV1);
|
||
|
}
|
||
|
response = V3Add(response, V3Add(V3Mul(impulse1.linear, deltaV1.linear), V3Mul(impulse1.angular, deltaV1.angular)));
|
||
|
}
|
||
|
|
||
|
return V3SumElems(response);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void setupFinalizeExtSolverContacts(
|
||
|
const ContactPoint* buffer,
|
||
|
const CorrelationBuffer& c,
|
||
|
const PxTransform& bodyFrame0,
|
||
|
const PxTransform& bodyFrame1,
|
||
|
PxU8* workspace,
|
||
|
const SolverExtBody& b0,
|
||
|
const SolverExtBody& b1,
|
||
|
const PxReal invDtF32,
|
||
|
PxReal bounceThresholdF32,
|
||
|
PxReal invMassScale0, PxReal invInertiaScale0,
|
||
|
PxReal invMassScale1, PxReal invInertiaScale1,
|
||
|
const PxReal restDist,
|
||
|
PxU8* frictionDataPtr,
|
||
|
PxReal ccdMaxContactDist,
|
||
|
Cm::SpatialVectorF* Z)
|
||
|
{
|
||
|
// NOTE II: the friction patches are sparse (some of them have no contact patches, and
|
||
|
// therefore did not get written back to the cache) but the patch addresses are dense,
|
||
|
// corresponding to valid patches
|
||
|
|
||
|
/*const bool haveFriction = PX_IR(n.staticFriction) > 0 || PX_IR(n.dynamicFriction) > 0;*/
|
||
|
|
||
|
const FloatV ccdMaxSeparation = FLoad(ccdMaxContactDist);
|
||
|
|
||
|
PxU8* PX_RESTRICT ptr = workspace;
|
||
|
|
||
|
const FloatV zero = FZero();
|
||
|
|
||
|
const PxF32 maxPenBias0 = b0.mLinkIndex == PxSolverConstraintDesc::NO_LINK ? b0.mBodyData->penBiasClamp : b0.mArticulation->getLinkMaxPenBias(b0.mLinkIndex);
|
||
|
const PxF32 maxPenBias1 = b1.mLinkIndex == PxSolverConstraintDesc::NO_LINK ? b1.mBodyData->penBiasClamp : b1.mArticulation->getLinkMaxPenBias(b1.mLinkIndex);
|
||
|
|
||
|
const FloatV maxPenBias = FLoad(PxMax(maxPenBias0, maxPenBias1));
|
||
|
|
||
|
const Vec3V frame0p = V3LoadU(bodyFrame0.p);
|
||
|
const Vec3V frame1p = V3LoadU(bodyFrame1.p);
|
||
|
|
||
|
const Cm::SpatialVectorV vel0 = b0.getVelocity();
|
||
|
const Cm::SpatialVectorV vel1 = b1.getVelocity();
|
||
|
|
||
|
|
||
|
const FloatV d0 = FLoad(invMassScale0);
|
||
|
const FloatV d1 = FLoad(invMassScale1);
|
||
|
|
||
|
const FloatV angD0 = FLoad(invInertiaScale0);
|
||
|
const FloatV angD1 = FLoad(invInertiaScale1);
|
||
|
|
||
|
Vec4V staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W = V4Zero();
|
||
|
staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W=V4SetZ(staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W, d0);
|
||
|
staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W=V4SetW(staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W, d1);
|
||
|
|
||
|
const FloatV restDistance = FLoad(restDist);
|
||
|
|
||
|
PxU32 frictionPatchWritebackAddrIndex = 0;
|
||
|
PxU32 contactWritebackCount = 0;
|
||
|
|
||
|
Ps::prefetchLine(c.contactID);
|
||
|
Ps::prefetchLine(c.contactID, 128);
|
||
|
|
||
|
const FloatV invDt = FLoad(invDtF32);
|
||
|
const FloatV p8 = FLoad(0.8f);
|
||
|
const FloatV bounceThreshold = FLoad(bounceThresholdF32);
|
||
|
|
||
|
const FloatV invDtp8 = FMul(invDt, p8);
|
||
|
|
||
|
PxU8 flags = 0;
|
||
|
|
||
|
for(PxU32 i=0;i<c.frictionPatchCount;i++)
|
||
|
{
|
||
|
PxU32 contactCount = c.frictionPatchContactCounts[i];
|
||
|
if(contactCount == 0)
|
||
|
continue;
|
||
|
|
||
|
const FrictionPatch& frictionPatch = c.frictionPatches[i];
|
||
|
PX_ASSERT(frictionPatch.anchorCount <= 2); //0==anchorCount is allowed if all the contacts in the manifold have a large offset.
|
||
|
|
||
|
const Gu::ContactPoint* contactBase0 = buffer + c.contactPatches[c.correlationListHeads[i]].start;
|
||
|
const PxReal combinedRestitution = contactBase0->restitution;
|
||
|
|
||
|
const PxReal coefficient = (contactBase0->materialFlags & PxMaterialFlag::eIMPROVED_PATCH_FRICTION && frictionPatch.anchorCount == 2) ? 0.5f : 1.f;
|
||
|
|
||
|
const PxReal staticFriction = contactBase0->staticFriction * coefficient;
|
||
|
const PxReal dynamicFriction = contactBase0->dynamicFriction * coefficient;
|
||
|
const bool disableStrongFriction = !!(contactBase0->materialFlags & PxMaterialFlag::eDISABLE_FRICTION);
|
||
|
staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W=V4SetX(staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W, FLoad(staticFriction));
|
||
|
staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W=V4SetY(staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W, FLoad(dynamicFriction));
|
||
|
|
||
|
SolverContactHeader* PX_RESTRICT header = reinterpret_cast<SolverContactHeader*>(ptr);
|
||
|
ptr += sizeof(SolverContactHeader);
|
||
|
|
||
|
Ps::prefetchLine(ptr + 128);
|
||
|
Ps::prefetchLine(ptr + 256);
|
||
|
Ps::prefetchLine(ptr + 384);
|
||
|
|
||
|
const bool haveFriction = (disableStrongFriction == 0) ;//PX_IR(n.staticFriction) > 0 || PX_IR(n.dynamicFriction) > 0;
|
||
|
header->numNormalConstr = Ps::to8(contactCount);
|
||
|
header->numFrictionConstr = Ps::to8(haveFriction ? frictionPatch.anchorCount*2 : 0);
|
||
|
|
||
|
header->type = Ps::to8(DY_SC_TYPE_EXT_CONTACT);
|
||
|
|
||
|
header->flags = flags;
|
||
|
|
||
|
const FloatV restitution = FLoad(combinedRestitution);
|
||
|
|
||
|
header->staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W = staticFrictionX_dynamicFrictionY_dominance0Z_dominance1W;
|
||
|
|
||
|
header->angDom0 = invInertiaScale0;
|
||
|
header->angDom1 = invInertiaScale1;
|
||
|
|
||
|
const PxU32 pointStride = sizeof(SolverContactPointExt);
|
||
|
const PxU32 frictionStride = sizeof(SolverContactFrictionExt);
|
||
|
|
||
|
const Vec3V normal = V3LoadU(buffer[c.contactPatches[c.correlationListHeads[i]].start].normal);
|
||
|
|
||
|
FloatV accumImpulse = FZero();
|
||
|
|
||
|
for(PxU32 patch=c.correlationListHeads[i];
|
||
|
patch!=CorrelationBuffer::LIST_END;
|
||
|
patch = c.contactPatches[patch].next)
|
||
|
{
|
||
|
const PxU32 count = c.contactPatches[patch].count;
|
||
|
const Gu::ContactPoint* contactBase = buffer + c.contactPatches[patch].start;
|
||
|
|
||
|
PxU8* p = ptr;
|
||
|
|
||
|
for(PxU32 j=0;j<count;j++)
|
||
|
{
|
||
|
const Gu::ContactPoint& contact = contactBase[j];
|
||
|
|
||
|
SolverContactPointExt* PX_RESTRICT solverContact = reinterpret_cast<SolverContactPointExt*>(p);
|
||
|
p += pointStride;
|
||
|
|
||
|
accumImpulse = FAdd(accumImpulse, setupExtSolverContact(b0, b1, d0, d1, angD0, angD1, frame0p, frame1p, normal, invDt, invDtp8, restDistance, maxPenBias, restitution,
|
||
|
bounceThreshold, contact, *solverContact, ccdMaxSeparation, Z, vel0, vel1));
|
||
|
|
||
|
}
|
||
|
|
||
|
ptr = p;
|
||
|
}
|
||
|
contactWritebackCount += contactCount;
|
||
|
|
||
|
accumImpulse = FDiv(accumImpulse, FLoad(PxF32(contactCount)));
|
||
|
|
||
|
header->normal_minAppliedImpulseForFrictionW = V4SetW(Vec4V_From_Vec3V(normal), accumImpulse);
|
||
|
|
||
|
PxF32* forceBuffer = reinterpret_cast<PxF32*>(ptr);
|
||
|
PxMemZero(forceBuffer, sizeof(PxF32) * contactCount);
|
||
|
ptr += sizeof(PxF32) * ((contactCount + 3) & (~3));
|
||
|
|
||
|
header->broken = 0;
|
||
|
|
||
|
if(haveFriction)
|
||
|
{
|
||
|
//const Vec3V normal = Vec3V_From_PxVec3(buffer.contacts[c.contactPatches[c.correlationListHeads[i]].start].normal);
|
||
|
//Vec3V normalS = V3LoadA(buffer[c.contactPatches[c.correlationListHeads[i]].start].normal);
|
||
|
|
||
|
|
||
|
const Vec3V linVrel = V3Sub(vel0.linear, vel1.linear);
|
||
|
//const Vec3V normal = Vec3V_From_PxVec3_Aligned(buffer.contacts[c.contactPatches[c.correlationListHeads[i]].start].normal);
|
||
|
|
||
|
const FloatV orthoThreshold = FLoad(0.70710678f);
|
||
|
const FloatV p1 = FLoad(0.0001f);
|
||
|
// fallback: normal.cross((1,0,0)) or normal.cross((0,0,1))
|
||
|
const FloatV normalX = V3GetX(normal);
|
||
|
const FloatV normalY = V3GetY(normal);
|
||
|
const FloatV normalZ = V3GetZ(normal);
|
||
|
|
||
|
Vec3V t0Fallback1 = V3Merge(zero, FNeg(normalZ), normalY);
|
||
|
Vec3V t0Fallback2 = V3Merge(FNeg(normalY), normalX, zero);
|
||
|
Vec3V t0Fallback = V3Sel(FIsGrtr(orthoThreshold, FAbs(normalX)), t0Fallback1, t0Fallback2);
|
||
|
|
||
|
Vec3V t0 = V3Sub(linVrel, V3Scale(normal, V3Dot(normal, linVrel)));
|
||
|
t0 = V3Sel(FIsGrtr(V3LengthSq(t0), p1), t0, t0Fallback);
|
||
|
t0 = V3Normalize(t0);
|
||
|
|
||
|
const VecCrossV t0Cross = V3PrepareCross(t0);
|
||
|
|
||
|
const Vec3V t1 = V3Cross(normal, t0Cross);
|
||
|
const VecCrossV t1Cross = V3PrepareCross(t1);
|
||
|
|
||
|
//We want to set the writeBack ptr to point to the broken flag of the friction patch.
|
||
|
//On spu we have a slight problem here because the friction patch array is
|
||
|
//in local store rather than in main memory. The good news is that the address of the friction
|
||
|
//patch array in main memory is stored in the work unit. These two addresses will be equal
|
||
|
//except on spu where one is local store memory and the other is the effective address in main memory.
|
||
|
//Using the value stored in the work unit guarantees that the main memory address is used on all platforms.
|
||
|
PxU8* PX_RESTRICT writeback = frictionDataPtr + frictionPatchWritebackAddrIndex*sizeof(FrictionPatch);
|
||
|
|
||
|
header->frictionBrokenWritebackByte = writeback;
|
||
|
|
||
|
for(PxU32 j = 0; j < frictionPatch.anchorCount; j++)
|
||
|
{
|
||
|
SolverContactFrictionExt* PX_RESTRICT f0 = reinterpret_cast<SolverContactFrictionExt*>(ptr);
|
||
|
ptr += frictionStride;
|
||
|
SolverContactFrictionExt* PX_RESTRICT f1 = reinterpret_cast<SolverContactFrictionExt*>(ptr);
|
||
|
ptr += frictionStride;
|
||
|
|
||
|
Vec3V ra = V3LoadU(bodyFrame0.q.rotate(frictionPatch.body0Anchors[j]));
|
||
|
Vec3V rb = V3LoadU(bodyFrame1.q.rotate(frictionPatch.body1Anchors[j]));
|
||
|
Vec3V error = V3Sub(V3Add(ra, frame0p), V3Add(rb, frame1p));
|
||
|
|
||
|
{
|
||
|
const Vec3V raXn = V3Cross(ra, t0Cross);
|
||
|
const Vec3V rbXn = V3Cross(rb, t0Cross);
|
||
|
|
||
|
Cm::SpatialVectorV deltaV0, deltaV1;
|
||
|
|
||
|
const Cm::SpatialVectorV resp0 = createImpulseResponseVector(t0, raXn, b0);
|
||
|
const Cm::SpatialVectorV resp1 = createImpulseResponseVector(V3Neg(t0), V3Neg(rbXn), b1);
|
||
|
FloatV resp = getImpulseResponse(b0, resp0, deltaV0, d0, angD0,
|
||
|
b1, resp1, deltaV1, d1, angD1, reinterpret_cast<Cm::SpatialVectorV*>(Z));
|
||
|
|
||
|
const FloatV velMultiplier = FSel(FIsGrtr(resp, FLoad(DY_ARTICULATION_MIN_RESPONSE)), FDiv(p8, resp), zero);
|
||
|
|
||
|
const PxU32 index = c.contactPatches[c.correlationListHeads[i]].start;
|
||
|
FloatV targetVel = V3Dot(V3LoadA(buffer[index].targetVel), t0);
|
||
|
|
||
|
if(b0.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
targetVel = FSub(targetVel, b0.projectVelocity(t0, raXn));
|
||
|
else if(b1.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
targetVel = FAdd(targetVel, b1.projectVelocity(t0, rbXn));
|
||
|
|
||
|
f0->normalXYZ_appliedForceW = V4SetW(t0, zero);
|
||
|
f0->raXnXYZ_velMultiplierW = V4SetW(Vec4V_From_Vec3V(resp0.angular), velMultiplier);
|
||
|
f0->rbXnXYZ_biasW = V4SetW(V4Neg(Vec4V_From_Vec3V(resp1.angular)), FMul(V3Dot(t0, error), invDt));
|
||
|
f0->linDeltaVA = deltaV0.linear;
|
||
|
f0->angDeltaVA = deltaV0.angular;
|
||
|
f0->linDeltaVB = deltaV1.linear;
|
||
|
f0->angDeltaVB = deltaV1.angular;
|
||
|
FStore(targetVel, &f0->targetVel);
|
||
|
}
|
||
|
|
||
|
{
|
||
|
const Vec3V raXn = V3Cross(ra, t1Cross);
|
||
|
const Vec3V rbXn = V3Cross(rb, t1Cross);
|
||
|
|
||
|
Cm::SpatialVectorV deltaV0, deltaV1;
|
||
|
|
||
|
const Cm::SpatialVectorV resp0 = createImpulseResponseVector(t1, raXn, b0);
|
||
|
const Cm::SpatialVectorV resp1 = createImpulseResponseVector(V3Neg(t1), V3Neg(rbXn), b1);
|
||
|
|
||
|
FloatV resp = getImpulseResponse(b0, resp0, deltaV0, d0, angD0,
|
||
|
b1, resp1, deltaV1, d1, angD1, reinterpret_cast<Cm::SpatialVectorV*>(Z));
|
||
|
|
||
|
//const FloatV velMultiplier = FSel(FIsGrtr(resp, FLoad(DY_ARTICULATION_MIN_RESPONSE)), FMul(p8, FRecip(resp)), zero);
|
||
|
|
||
|
const FloatV velMultiplier = FSel(FIsGrtr(resp, FLoad(DY_ARTICULATION_MIN_RESPONSE)), FDiv(p8, resp), zero);
|
||
|
|
||
|
const PxU32 index = c.contactPatches[c.correlationListHeads[i]].start;
|
||
|
FloatV targetVel = V3Dot(V3LoadA(buffer[index].targetVel), t1);
|
||
|
|
||
|
if(b0.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
targetVel = FSub(targetVel, b0.projectVelocity(t1, raXn));
|
||
|
else if(b1.mLinkIndex == PxSolverConstraintDesc::NO_LINK)
|
||
|
targetVel = FAdd(targetVel, b1.projectVelocity(t1, rbXn));
|
||
|
|
||
|
f1->normalXYZ_appliedForceW = V4SetW(t1, zero);
|
||
|
f1->raXnXYZ_velMultiplierW = V4SetW(Vec4V_From_Vec3V(resp0.angular), velMultiplier);
|
||
|
f1->rbXnXYZ_biasW = V4SetW(V4Neg(Vec4V_From_Vec3V(resp1.angular)), FMul(V3Dot(t1, error), invDt));
|
||
|
f1->linDeltaVA = deltaV0.linear;
|
||
|
f1->angDeltaVA = deltaV0.angular;
|
||
|
f1->linDeltaVB = deltaV1.linear;
|
||
|
f1->angDeltaVB = deltaV1.angular;
|
||
|
FStore(targetVel, &f1->targetVel);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
frictionPatchWritebackAddrIndex++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|