#pragma kernel Gradients #pragma kernel CalculateVolume #pragma kernel Denominators #pragma kernel Constraint #pragma kernel AccumulateDeltas #pragma kernel Apply //#pragma kernel Project //#pragma kernel Apply #include "MathUtils.cginc" #include "AtomicDeltas.cginc" StructuredBuffer triangles; StructuredBuffer firstTriangle; StructuredBuffer numTriangles; StructuredBuffer restVolumes; StructuredBuffer pressureStiffness; RWStructuredBuffer lambdas; RWStructuredBuffer denominators; RWStructuredBuffer volumes; RWStructuredBuffer gradients; StructuredBuffer particles; StructuredBuffer particleConstraintIndex; StructuredBuffer triangleConstraintIndex; RWStructuredBuffer positions; StructuredBuffer invMasses; // Variables set from the CPU uint activeConstraintCount; uint trianglesCount; uint particlesCount; float deltaTime; float sorFactor; void AccumulateGradient(in int index, in float3 grad) { InterlockedAddFloat(gradients, index, 0, grad.x); InterlockedAddFloat(gradients, index, 1, grad.y); InterlockedAddFloat(gradients, index, 2, grad.z); } [numthreads(128, 1, 1)] void Gradients (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= trianglesCount) return; int v = i * 3; int i1 = triangles[v]; int i2 = triangles[v + 1]; int i3 = triangles[v + 2]; //accumulate gradient for each particle in the triangle: AccumulateGradient(i1,cross(positions[i2].xyz, positions[i3].xyz)); AccumulateGradient(i2,cross(positions[i3].xyz, positions[i1].xyz)); AccumulateGradient(i3,cross(positions[i1].xyz, positions[i2].xyz)); } [numthreads(128, 1, 1)] void CalculateVolume (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= trianglesCount) return; int constraintIndex = triangleConstraintIndex[i]; int v = i * 3; int i1 = triangles[v]; int i2 = triangles[v + 1]; int i3 = triangles[v + 2]; float vol = dot(cross(positions[i1].xyz, positions[i2].xyz), positions[i3].xyz) / 6.0f; InterlockedAddFloat(volumes, triangleConstraintIndex[i],vol); } // One denominator per constraint // each particle in the constraint contributes only once. [numthreads(128, 1, 1)] void Denominators (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= particlesCount) return; int p = particles[i]; float3 grad = asfloat(gradients[p]).xyz; float denom = invMasses[p] * dot(grad, grad); InterlockedAddFloat(denominators, particleConstraintIndex[i], denom); } [numthreads(128, 1, 1)] void Constraint (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= activeConstraintCount) return; float compliance = pressureStiffness[i].y / (deltaTime * deltaTime); // equality constraint: volume - pressure * rest volume = 0 float constraint = asfloat(volumes[i]) - pressureStiffness[i].x * restVolumes[i]; // calculate lagrange multiplier delta: float dlambda = (-constraint - compliance * 0) / (asfloat(denominators[i]) + compliance + EPSILON); lambdas[i] = dlambda;//+= dlambda; volumes[i] = asuint(0); denominators[i] = asuint(0); } [numthreads(128, 1, 1)] void AccumulateDeltas (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= particlesCount) return; int p = particles[i]; int c = particleConstraintIndex[i]; AddPositionDelta(p, lambdas[c] * invMasses[p] * asfloat(gradients[p])); gradients[p] = asuint(FLOAT4_ZERO); } [numthreads(128, 1, 1)] void Apply (uint3 id : SV_DispatchThreadID) { unsigned int i = id.x; if (i >= activeConstraintCount) return; for (int j = 0; j < numTriangles[i]; ++j) { int v = (firstTriangle[i] + j) * 3; int p1 = triangles[v]; int p2 = triangles[v + 1]; int p3 = triangles[v + 2]; ApplyPositionDelta(positions, p1, sorFactor); ApplyPositionDelta(positions, p2, sorFactor); ApplyPositionDelta(positions, p3, sorFactor); } }