Files
Fishing2/Assets/Obi/Scripts/Common/Backends/Burst/DataStructures/Queries/BurstContact.cs
2026-01-22 22:08:21 +08:00

163 lines
6.4 KiB
C#

#if (OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
using Unity.Mathematics;
namespace Obi
{
public struct BurstContact : IConstraint, System.IComparable<BurstContact>
{
public float4 pointA; // point A, expressed as simplex barycentric coords for simplices, as a solver-space position for colliders.
public float4 pointB; // point B, expressed as simplex barycentric coords for simplices, as a solver-space position for colliders.
public float4 normal; // contact normal on bodyB's surface.
public float4 tangent; // contact tangent on bodyB's surface.
public float distance; // distance between bodyA's and bodyB's surface.
public float normalLambda;
public float tangentLambda;
public float bitangentLambda;
public float stickLambda;
public float rollingFrictionImpulse;
public int bodyA;
public int bodyB;
public int GetParticleCount() { return 2; }
public int GetParticle(int index) { return index == 0 ? bodyA : bodyB; }
public float4 bitangent => math.normalizesafe(new float4(math.cross(normal.xyz, tangent.xyz), 0));
public override string ToString()
{
return bodyA + "," + bodyB;
}
public int CompareTo(BurstContact other)
{
int first = bodyA.CompareTo(other.bodyA);
if (first == 0)
return bodyB.CompareTo(other.bodyB);
return first;
}
public void CalculateTangent(float4 relativeVelocity)
{
tangent = math.normalizesafe(relativeVelocity - math.dot(relativeVelocity, normal) * normal);
}
public float SolveAdhesion(float normalMass, float4 posA, float4 posB, float stickDistance, float stickiness, float dt)
{
if (normalMass <= 0 || stickDistance <= 0 || stickiness <= 0 || dt <= 0)
return 0;
distance = math.dot(posA - posB, normal);
// calculate stickiness position correction:
float constraint = stickiness * (1 - math.max(distance / stickDistance, 0)) * dt;
// calculate lambda multiplier:
float dlambda = -constraint / normalMass;
// accumulate lambda:
float newStickinessLambda = math.min(stickLambda + dlambda, 0);
// calculate lambda change and update accumulated lambda:
float lambdaChange = newStickinessLambda - stickLambda;
stickLambda = newStickinessLambda;
return lambdaChange;
}
public float SolvePenetration(float normalMass, float4 posA, float4 posB, float maxDepenetrationDelta)
{
if (normalMass <= 0)
return 0;
//project position delta to normal vector:
distance = math.dot(posA - posB, normal);
// calculate max projection distance based on depenetration velocity:
float maxProjection = math.max(-distance - maxDepenetrationDelta, 0);
// calculate lambda multiplier:
float dlambda = -(distance + maxProjection) / normalMass;
// accumulate lambda:
float newLambda = math.max(normalLambda + dlambda, 0);
// calculate lambda change and update accumulated lambda:
float lambdaChange = newLambda - normalLambda;
normalLambda = newLambda;
return lambdaChange;
}
public float2 SolveFriction(float tangentMass, float bitangentMass, float4 relativeVelocity, float staticFriction, float dynamicFriction, float dt)
{
float2 lambdaChange = float2.zero;
if (tangentMass <= 0 || bitangentMass <= 0 ||
(dynamicFriction <= 0 && staticFriction <= 0) || (normalLambda <= 0 && stickLambda <= 0))
return lambdaChange;
// calculate delta projection on both friction axis:
float tangentPosDelta = math.dot(relativeVelocity, tangent);
float bitangentPosDelta = math.dot(relativeVelocity, bitangent);
// calculate friction pyramid limit:
float dynamicFrictionCone = normalLambda / dt * dynamicFriction;
float staticFrictionCone = normalLambda / dt * staticFriction;
// tangent impulse:
float tangentLambdaDelta = -tangentPosDelta / tangentMass;
float newTangentLambda = tangentLambda + tangentLambdaDelta;
if (math.abs(newTangentLambda) > staticFrictionCone)
newTangentLambda = math.clamp(newTangentLambda, -dynamicFrictionCone, dynamicFrictionCone);
lambdaChange[0] = newTangentLambda - tangentLambda;
tangentLambda = newTangentLambda;
// bitangent impulse:
float bitangentLambdaDelta = -bitangentPosDelta / bitangentMass;
float newBitangentLambda = bitangentLambda + bitangentLambdaDelta;
if (math.abs(newBitangentLambda) > staticFrictionCone)
newBitangentLambda = math.clamp(newBitangentLambda, -dynamicFrictionCone, dynamicFrictionCone);
lambdaChange[1] = newBitangentLambda - bitangentLambda;
bitangentLambda = newBitangentLambda;
return lambdaChange;
}
public float SolveRollingFriction(float4 angularVelocityA,
float4 angularVelocityB,
float rollingFriction,
float invMassA,
float invMassB,
ref float4 rolling_axis)
{
float totalInvMass = invMassA + invMassB;
if (totalInvMass <= 0)
return 0;
rolling_axis = math.normalizesafe(angularVelocityA - angularVelocityB);
float vel1 = math.dot(angularVelocityA,rolling_axis);
float vel2 = math.dot(angularVelocityB,rolling_axis);
float relativeVelocity = vel1 - vel2;
float maxImpulse = normalLambda * rollingFriction;
float newRollingImpulse = math.clamp(rollingFrictionImpulse - relativeVelocity / totalInvMass, -maxImpulse, maxImpulse);
float rolling_impulse_change = newRollingImpulse - rollingFrictionImpulse;
rollingFrictionImpulse = newRollingImpulse;
return rolling_impulse_change;
}
}
}
#endif