_xiaofang/xiaofang/Assets/Obi/Resources/Compute/ColliderFrictionConstraints.compute
杨号敬 bcc74f0465 add
2024-12-18 02:18:45 +08:00

193 lines
7.7 KiB
Plaintext

#include "ContactHandling.cginc"
#include "ColliderDefinitions.cginc"
#include "Rigidbody.cginc"
#include "Simplex.cginc"
#include "CollisionMaterial.cginc"
#include "Integration.cginc"
#include "AtomicDeltas.cginc"
#pragma kernel Project
#pragma kernel Apply
StructuredBuffer<int> particleIndices;
StructuredBuffer<int> simplices;
StructuredBuffer<float> invMasses;
StructuredBuffer<float> invRotationalMasses;
StructuredBuffer<float4> positions;
StructuredBuffer<quaternion> orientations;
StructuredBuffer<float4> prevPositions;
StructuredBuffer<quaternion> prevOrientations;
StructuredBuffer<float4> principalRadii;
StructuredBuffer<transform> transforms;
StructuredBuffer<shape> shapes;
RWStructuredBuffer<float4> RW_positions;
RWStructuredBuffer<quaternion> RW_orientations;
RWStructuredBuffer<contact> contacts;
RWStructuredBuffer<contactMasses> effectiveMasses;
StructuredBuffer<uint> dispatchBuffer;
StructuredBuffer<transform> solverToWorld;
StructuredBuffer<inertialFrame> inertialSolverFrame;
// Variables set from the CPU
uint particleCount;
float substepTime;
float stepTime;
float sorFactor;
[numthreads(128, 1, 1)]
void Project (uint3 id : SV_DispatchThreadID)
{
unsigned int i = id.x;
if (i >= dispatchBuffer[3]) return;
// Skip contacts involving triggers:
if (shapes[contacts[i].bodyB].isTrigger())
return;
int simplexSize;
int simplexStart = GetSimplexStartAndSize(contacts[i].bodyA, simplexSize);
int colliderIndex = contacts[i].bodyB;
int rigidbodyIndex = shapes[colliderIndex].rigidbodyIndex;
// Combine collision materials (use material from first particle in simplex)
collisionMaterial material = CombineCollisionMaterials(collisionMaterialIndices[simplices[simplexStart]], shapes[colliderIndex].materialIndex);
// Calculate relative velocity:
float4 rA = float4(0,0,0,0), rB = float4(0,0,0,0);
float4 prevPositionA = float4(0,0,0,0);
float4 linearVelocityA = float4(0,0,0,0);
float4 angularVelocityA = float4(0,0,0,0);
float invRotationalMassA = 0;
quaternion orientationA = quaternion(0, 0, 0, 0);
float simplexRadiusA = 0;
int j = 0;
for (j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
prevPositionA += prevPositions[particleIndex] * contacts[i].pointA[j];
linearVelocityA += DifferentiateLinear(positions[particleIndex], prevPositions[particleIndex], substepTime) * contacts[i].pointA[j];
angularVelocityA += DifferentiateAngular(orientations[particleIndex], prevOrientations[particleIndex], substepTime) * contacts[i].pointA[j];
invRotationalMassA += invRotationalMasses[particleIndex] * contacts[i].pointA[j];
orientationA += orientations[particleIndex] * contacts[i].pointA[j];
simplexRadiusA += EllipsoidRadius(contacts[i].normal, prevOrientations[particleIndex], principalRadii[particleIndex].xyz) * contacts[i].pointA[j];
}
float4 relativeVelocity = linearVelocityA;
// Add particle angular velocity if rolling contacts are enabled:
if (material.rollingContacts > 0)
{
rA = -contacts[i].normal * simplexRadiusA;
relativeVelocity += float4(cross(angularVelocityA.xyz, rA.xyz), 0);
}
// Subtract rigidbody velocity:
int rbContacts = 1;
if (rigidbodyIndex >= 0)
{
// Note: unlike rA, that is expressed in solver space, rB is expressed in world space.
rB = solverToWorld[0].TransformPoint(contacts[i].pointB) - rigidbodies[rigidbodyIndex].com;
relativeVelocity -= GetRigidbodyVelocityAtPoint(rigidbodies[rigidbodyIndex], contacts[i].pointB,
asfloat(linearDeltasAsInt[rigidbodyIndex]),
asfloat(angularDeltasAsInt[rigidbodyIndex]), inertialSolverFrame[0]);
rbContacts = rigidbodies[rigidbodyIndex].constraintCount;
}
// Determine impulse magnitude:
float tangentMass = effectiveMasses[i].tangentInvMassA + effectiveMasses[i].tangentInvMassB * rbContacts;
float bitangentMass = effectiveMasses[i].bitangentInvMassA + effectiveMasses[i].bitangentInvMassB * rbContacts;
float2 impulses = SolveFriction(contacts[i], tangentMass, bitangentMass, relativeVelocity, material.staticFriction, material.dynamicFriction, stepTime);
if (abs(impulses.x) > EPSILON || abs(impulses.y) > EPSILON)
{
float4 tangentImpulse = impulses.x * contacts[i].tangent;
float4 bitangentImpulse = impulses.y * GetBitangent(contacts[i]);
float4 totalImpulse = tangentImpulse + bitangentImpulse;
float baryScale = BaryScale(contacts[i].pointA);
for (j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
float4 delta1 = (tangentImpulse * effectiveMasses[i].tangentInvMassA + bitangentImpulse * effectiveMasses[i].bitangentInvMassA) * substepTime * contacts[i].pointA[j] * baryScale;
AtomicAddPositionDelta(particleIndex, delta1);
}
if (rigidbodyIndex >= 0)
{
ApplyImpulse(rigidbodyIndex, -totalImpulse, contacts[i].pointB, inertialSolverFrame[0].frame);
}
// Rolling contacts:
if (material.rollingContacts > 0)
{
// Calculate angular velocity deltas due to friction impulse:
float4 invInertiaTensor = 1.0/(GetParticleInertiaTensor(simplexRadiusA, invRotationalMassA) + FLOAT4_EPSILON);
float4x4 solverInertiaA = TransformInertiaTensor(invInertiaTensor, orientationA);
float4 angVelDeltaA = mul(solverInertiaA, float4(cross(rA.xyz, totalImpulse.xyz), 0));
float4 angVelDeltaB = FLOAT4_ZERO;
// Final angular velocities, after adding the deltas:
angularVelocityA += angVelDeltaA;
float4 angularVelocityB = FLOAT4_ZERO;
// Calculate weights (inverse masses):
float invMassA = length(mul(solverInertiaA, normalizesafe(angularVelocityA)));
float invMassB = 0;
if (rigidbodyIndex >= 0)
{
angVelDeltaB = mul(-rigidbodies[rigidbodyIndex].inverseInertiaTensor, float4(cross(rB.xyz, totalImpulse.xyz), 0));
angularVelocityB = rigidbodies[rigidbodyIndex].angularVelocity + angVelDeltaB;
invMassB = length(mul(rigidbodies[rigidbodyIndex].inverseInertiaTensor, normalizesafe(angularVelocityB))) * rbContacts;
}
// Calculate rolling axis and angular velocity deltas:
float4 rollAxis = FLOAT4_ZERO;
float rollingImpulse = SolveRollingFriction(contacts[i], angularVelocityA, angularVelocityB, material.rollingFriction, invMassA, invMassB, rollAxis);
angVelDeltaA += rollAxis * rollingImpulse * invMassA;
angVelDeltaB -= rollAxis * rollingImpulse * invMassB;
// Apply orientation delta to particles:
quaternion orientationDelta = AngularVelocityToSpinQuaternion(orientationA, angVelDeltaA, substepTime);
for (j = 0; j < simplexSize; ++j)
{
int particleIndex = simplices[simplexStart + j];
AtomicAddOrientationDelta(particleIndex, orientationDelta);
}
// Apply angular velocity delta to rigidbody:
if (rigidbodyIndex >= 0)
{
AtomicAddAngularDelta(rigidbodyIndex, angVelDeltaB);
}
}
}
}
[numthreads(128, 1, 1)]
void Apply (uint3 id : SV_DispatchThreadID)
{
unsigned int threadIndex = id.x;
if (threadIndex >= particleCount) return;
int p = particleIndices[threadIndex];
ApplyPositionDelta(RW_positions, p, sorFactor);
ApplyOrientationDelta(RW_orientations, p, sorFactor);
}