@@ -67,7 +67,6 @@ void main() {
6767 vec2 pos = state.xy;
6868 vec2 vel = state.zw;
6969
70- // === ManyBody (Barnes-Hut repulsion) ===
7170 if (uHasManyBody > 0.5 && uTreeNodeCount > 0 ) {
7271 int stack[128 ];
7372 int top = 0 ;
@@ -79,7 +78,6 @@ void main() {
7978 float w = data.w;
8079
8180 if (w < - 0.5 ) {
82- // Leaf node
8381 int bodyIdx = int (- w - 0.5 );
8482 if (bodyIdx != nodeId) {
8583 vec2 delta = data.xy - pos;
@@ -97,7 +95,6 @@ void main() {
9795 }
9896 }
9997 } else {
100- // Internal node - BH approximation check
10198 vec2 delta = data.xy - pos;
10299 float distSq = dot (delta, delta);
103100
@@ -118,11 +115,8 @@ void main() {
118115 }
119116 }
120117
121- // === Collision (separate tree traversal - always descends to nearby leaves) ===
122118 if (uHasCollision > 0.5 && uCollisionRadius > 0.0 && uTreeNodeCount > 0 ) {
123119 float collisionDiam = uCollisionRadius * 2.0 ;
124- // Use input-state predicted position (not accumulated vel) for symmetry
125- // with the quadtree, which stores positions from the same input state.
126120 vec2 predictedPos = state.xy + state.zw;
127121 int stack[64 ];
128122 int top = 0 ;
@@ -134,23 +128,19 @@ void main() {
134128 float w = data.w;
135129
136130 if (w < - 0.5 ) {
137- // Leaf node - apply collision using predicted positions
138131 int bodyIdx = int (- w - 0.5 );
139132 if (bodyIdx != nodeId && bodyIdx < uNodeCount) {
140133 vec2 delta = data.xy - predictedPos;
141134 float dist = length (delta);
142135
143136 if (dist < collisionDiam && dist > 0.0 ) {
144- // d3's forceCollide: push = overlap * strength, split equally (bias=0.5)
145137 float push = (collisionDiam - dist) * uCollisionStrength;
146138 vel -= (delta / dist) * push * 0.5 ;
147139 }
148140 }
149141 } else {
150- // Internal node - prune using geometric AABB distance.
151142 vec4 geo = texelFetch(uTreeGeometry, texCoord(idx, uTreeTexWidth), 0 );
152143 float cellSize = geo.z;
153- // Compute distance from predicted pos to nearest point on the cell AABB
154144 vec2 nearest = clamp (predictedPos, geo.xy, geo.xy + cellSize);
155145 float distToCell = length (nearest - predictedPos);
156146
@@ -165,7 +155,6 @@ void main() {
165155 }
166156 }
167157
168- // === Link (spring) force ===
169158 if (uHasLinks > 0.5 ) {
170159 vec4 offData = texelFetch(uAdjOffsets, texCoord(nodeId, uAdjOffsetsTexWidth), 0 );
171160 int start = int (offData.x + 0.5 );
@@ -179,11 +168,6 @@ void main() {
179168 float dirBias = edgeData.w;
180169
181170 vec4 targetState = texelFetch(uState, texCoord(targetId, uTexWidth), 0 );
182- // Use input-state predicted positions for BOTH sides to keep the link force
183- // symmetric in parallel execution. Using (pos + vel) here would include
184- // manyBody/collision forces already accumulated in vel for the current node
185- // but not for the target (read from input texture), creating a systematic
186- // inward bias that causes clumping at sustained alpha during drag.
187171 vec2 delta = (targetState.xy + targetState.zw) - (state.xy + state.zw);
188172 float d = length (delta);
189173
@@ -197,12 +181,10 @@ void main() {
197181 }
198182 }
199183
200- // === Centering force ===
201184 if (uHasCentering > 0.5 ) {
202185 vel += (uCenter - pos) * uCenterStrength * uAlpha;
203186 }
204187
205- // === Positioning force ===
206188 if (uHasPositioning > 0.5 ) {
207189 vel.x += (uForceXTarget - pos.x) * uForceXStrength * uAlpha;
208190 vel.y += (uForceYTarget - pos.y) * uForceYStrength * uAlpha;
0 commit comments