Skip to content

Commit d023c18

Browse files
GuoLei1990claude
andcommitted
fix: align TF shader velocity system with correct module interactions
- Fix animatedVelocity composition: only VOL, not FOL/gravity - Fix gravity timing: add to base velocity before dampen/drag - Fix drag math: scale total then subtract animated (not scale base only) - Remove Unity references from comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 2193eb7 commit d023c18

File tree

1 file changed

+24
-14
lines changed

1 file changed

+24
-14
lines changed

packages/core/src/shaderlib/particle/particle_transform_feedback_update.glsl

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,17 @@ void main() {
153153
}
154154
#endif
155155

156-
// Add velocity deltas to local velocity
157-
localVelocity += volDeltaLocal + folDeltaLocal;
156+
// Gravity and FOL contribute to base velocity (persisted, subject to dampen/drag).
157+
vec3 gravityLocal = rotationByQuaternions(gravityDelta, quaternionConjugate(worldRotation));
158+
localVelocity += folDeltaLocal + gravityLocal;
158159

159160
// =====================================================
160161
// Step 2: Dampen (Limit Velocity)
162+
// Two-velocity system:
163+
// base velocity (persisted) = startVelocity + FOL + gravity
164+
// animated velocity (per-frame) = VOL
165+
// Dampen uses total (base + animated) to judge overspeed,
166+
// but only permanently modifies base velocity.
161167
// =====================================================
162168
#ifdef RENDERER_LVL_MODULE_ENABLED
163169
float limitRand = a_Random2.w;
@@ -166,28 +172,29 @@ void main() {
166172
float effectiveDampen = 1.0 - pow(1.0 - dampen, dt * 30.0);
167173

168174
if (renderer_LVLSpace == 0) {
169-
localVelocity = applyLVLSpeedLimitTF(localVelocity, normalizedAge, limitRand, effectiveDampen);
175+
vec3 totalLocal = localVelocity + volDeltaLocal;
176+
vec3 dampenedTotal = applyLVLSpeedLimitTF(totalLocal, normalizedAge, limitRand, effectiveDampen);
177+
localVelocity = dampenedTotal - volDeltaLocal;
170178
} else {
171-
// World space: exclude animatedVelocity from permanent dampen.
172-
vec3 animatedWorld = volDeltaWorld + folDeltaWorld + gravityDelta;
173-
vec3 localWorld = rotationByQuaternions(localVelocity, worldRotation);
174-
vec3 totalWorld = localWorld + animatedWorld;
179+
vec3 animatedWorld = volDeltaWorld;
180+
vec3 baseWorld = rotationByQuaternions(localVelocity, worldRotation);
181+
vec3 totalWorld = baseWorld + animatedWorld;
175182
vec3 dampenedTotal = applyLVLSpeedLimitTF(totalWorld, normalizedAge, limitRand, effectiveDampen);
176-
// Delta applies only to the local velocity portion
177-
vec3 dampenedLocal = dampenedTotal - animatedWorld;
178-
localVelocity = rotationByQuaternions(dampenedLocal, quaternionConjugate(worldRotation));
183+
vec3 dampenedBase = dampenedTotal - animatedWorld;
184+
localVelocity = rotationByQuaternions(dampenedBase, quaternionConjugate(worldRotation));
179185
}
180186
#endif
181187

182188
// =====================================================
183189
// Step 3: Drag
190+
// Drag also uses total velocity (base + animated), only modifies base.
184191
// =====================================================
185192
#ifdef RENDERER_LVL_MODULE_ENABLED
186193
{
187194
float dragCoeff = evaluateLVLDrag(normalizedAge, a_Random0.x);
188195
if (dragCoeff > 0.0) {
189-
vec3 combinedVel = localVelocity;
190-
float velMagSqr = dot(combinedVel, combinedVel);
196+
vec3 totalVel = localVelocity + volDeltaLocal;
197+
float velMagSqr = dot(totalVel, totalVel);
191198
float velMag = sqrt(velMagSqr);
192199

193200
float drag = dragCoeff;
@@ -204,16 +211,19 @@ void main() {
204211

205212
if (velMag > 0.0) {
206213
float newVelMag = max(0.0, velMag - drag * dt);
207-
localVelocity = localVelocity * (newVelMag / velMag);
214+
vec3 dampenedTotal = totalVel * (newVelMag / velMag);
215+
localVelocity = dampenedTotal - volDeltaLocal;
208216
}
209217
}
210218
}
211219
#endif
212220

213221
// =====================================================
214222
// Step 4: Integrate position
223+
// localVelocity (base, includes gravity+FOL) is persisted in TF buffer.
224+
// VOL is added for integration only (not persisted).
215225
// =====================================================
216-
vec3 worldVelocity = rotationByQuaternions(localVelocity, worldRotation) + volDeltaWorld + folDeltaWorld + gravityDelta;
226+
vec3 worldVelocity = rotationByQuaternions(localVelocity + volDeltaLocal, worldRotation) + volDeltaWorld + folDeltaWorld;
217227
worldPosition += worldVelocity * dt;
218228

219229
v_TFPosition = worldPosition;

0 commit comments

Comments
 (0)