#pragma kernel Project #pragma kernel Apply #include "MathUtils.cginc" #include "AtomicDeltas.cginc" StructuredBuffer particleIndices; StructuredBuffer skinPoints; StructuredBuffer skinNormals; StructuredBuffer skinRadiiBackstop; StructuredBuffer skinCompliance; RWStructuredBuffer lambdas; RWStructuredBuffer positions; StructuredBuffer invMasses; // Variables set from the CPU uint activeConstraintCount; float deltaTime; float sorFactor; [numthreads(128, 1, 1)] void Project (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= activeConstraintCount) return; float radius = skinRadiiBackstop[i].x; float collisionRadius = skinRadiiBackstop[i].y; float backstopDistance = collisionRadius + skinRadiiBackstop[i].z; float compliance = skinCompliance[i] / (deltaTime * deltaTime); int p = particleIndices[i]; if (invMasses[p] > 0) { float4 toSkin = positions[p] - skinPoints[i]; float4 toBackstop = positions[p] - (skinPoints[i] - skinNormals[i] * backstopDistance); // distance to skin and backstop sphere centers: float d = length(toSkin); float b = length(toBackstop); // constrain particle within skin radius. // ignore mass in the equations (use 1), as we don't want particle mass to interfere with skin compliance. // We should be able to adjust skin properties and particle mass (for collisions) independently. float constraint = max(0,d - radius); float dlambda = (-constraint - compliance * lambdas[i]) / (1 + compliance); lambdas[i] += dlambda; float4 skinCorrection = dlambda * toSkin / (d + EPSILON); // constrain particle outside the backstop sphere (0 compliance): constraint = min(0, b - collisionRadius); float4 backstopCorrection = - constraint * toBackstop / (b + EPSILON); AddPositionDelta(p, skinCorrection + backstopCorrection); } } [numthreads(128, 1, 1)] void Apply (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= activeConstraintCount) return; int p1 = particleIndices[i]; ApplyPositionDelta(positions, p1, sorFactor); }