#version 430 #extension GL_ARB_gpu_shader_fp64 : enable #define MAX_SEGMENTS 32 layout (local_size_x=MAX_SEGMENTS, local_size_y=1, local_size_z=1) in; layout(std430, binding = 0) buffer PositionBuffer { dvec2 X[]; }; layout(std430, binding = 1) buffer VelocityBuffer { dvec2 V[]; }; layout(std430, binding = 2) buffer InverseMassBuffer { double W[]; }; layout(std430, binding = 3) buffer LengthBuffer { double L[]; }; layout(std430, binding = 4) buffer IndexBuffer { uint indices[]; }; layout(std430, binding = 5) buffer SegmentCountBuffer { uint segmentCounts[]; }; uniform double h; uniform double gravity; uniform uint substeps; shared dvec2 P[MAX_SEGMENTS]; // distance constraint void solveConstraint(uint segmentId, uint gIndex){ double w1 = segmentId == 0 ? 0.0 : W[gIndex - 1]; double w2 = W[gIndex]; dvec2 s = (segmentId == 0 ? dvec2(0, 0) : P[segmentId - 1]) - P[segmentId]; dvec2 n = normalize(s); double l = length(s); dvec2 deltaP1 = n * -w1 / (w1 + w2) * (l - L[gIndex]); dvec2 deltaP2 = n * w2 / (w1 + w2) * (l - L[gIndex]); if (segmentId > 0) P[segmentId - 1] += deltaP1; P[segmentId] += deltaP2; } // No need for synchronization, because each pendulum gets its own warp void main() { uint pendulumId = gl_WorkGroupID.x; uint i_off = indices[pendulumId]; uint segmentCount = segmentCounts[pendulumId]; uint localId = gl_LocalInvocationID.x; uint gIndex = i_off + localId; // discard unneeded local threads for segments if (localId >= segmentCount) return; // substepping is not parallelizable for (int k = 0; k < substeps; k++){ // explicit integration with gravity as external force V[gIndex] = V[gIndex] + dvec2(0, -gravity * h); P[localId] = X[gIndex] + V[gIndex] * h; // every segment depends on its neighbour, so we can not parallelize all constraints // only parallelize those, who are independent of each other, skipping every second segment if (localId % 2 == 0){ solveConstraint(localId, i_off + localId); if (localId + 1 < segmentCount) solveConstraint(localId + 1, gIndex + 1); } // update position and velocity V[gIndex] = (P[localId] - X[gIndex]) / h; X[gIndex] = P[localId]; } }