mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 01:23:51 +00:00
Fix animation timing precision loss by replacing fmod with iterative subtraction
Floating-point fmod() loses precision with large accumulated time values, causing subtle jumps/hitches in animation loops. Replace with iterative duration subtraction to keep animationTime bounded and maintain precision, consistent with the fix applied to character_renderer.cpp. Applies to: - M2 creature/object animation loops (main update) - M2 particle-only instance wrapping (3333ms limit) - M2 global sequence timing resolution - M2 animated particle tile indexing - Mount bobbing motion (sinusoidal rider motion) - Character footstep trigger timing - Mount footstep trigger timing All timing computations now use the same precision-preserving approach.
This commit is contained in:
parent
f6f072a957
commit
68a379610e
2 changed files with 43 additions and 11 deletions
|
|
@ -1880,7 +1880,15 @@ static void resolveTrackTime(const pipeline::M2AnimationTrack& track,
|
|||
// Global sequence: always use sub-array 0, wrap time at global duration
|
||||
outSeqIdx = 0;
|
||||
float dur = static_cast<float>(globalSeqDurations[track.globalSequence]);
|
||||
outTime = (dur > 0.0f) ? std::fmod(time, dur) : 0.0f;
|
||||
if (dur > 0.0f) {
|
||||
// Use iterative subtraction instead of fmod() to preserve precision
|
||||
outTime = time;
|
||||
while (outTime >= dur) {
|
||||
outTime -= dur;
|
||||
}
|
||||
} else {
|
||||
outTime = 0.0f;
|
||||
}
|
||||
} else {
|
||||
outSeqIdx = seqIdx;
|
||||
outTime = time;
|
||||
|
|
@ -2070,8 +2078,9 @@ void M2Renderer::update(float deltaTime, const glm::vec3& cameraPos, const glm::
|
|||
for (size_t idx : particleOnlyInstanceIndices_) {
|
||||
if (idx >= instances.size()) continue;
|
||||
auto& instance = instances[idx];
|
||||
if (instance.animTime > 3333.0f) {
|
||||
instance.animTime = std::fmod(instance.animTime, 3333.0f);
|
||||
// Use iterative subtraction instead of fmod() to preserve precision
|
||||
while (instance.animTime > 3333.0f) {
|
||||
instance.animTime -= 3333.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2114,7 +2123,11 @@ void M2Renderer::update(float deltaTime, const glm::vec3& cameraPos, const glm::
|
|||
instance.animTime = 0.0f;
|
||||
instance.variationTimer = 4000.0f + static_cast<float>(rand() % 6000);
|
||||
} else {
|
||||
instance.animTime = std::fmod(instance.animTime, std::max(1.0f, instance.animDuration));
|
||||
// Use iterative subtraction instead of fmod() to preserve precision
|
||||
float duration = std::max(1.0f, instance.animDuration);
|
||||
while (instance.animTime >= duration) {
|
||||
instance.animTime -= duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3452,8 +3465,12 @@ void M2Renderer::renderM2Particles(VkCommandBuffer cmd, VkDescriptorSet perFrame
|
|||
if ((em.flags & kParticleFlagTiled) && totalTiles > 1) {
|
||||
float animSeconds = inst.animTime / 1000.0f;
|
||||
uint32_t animFrame = static_cast<uint32_t>(std::floor(animSeconds * totalTiles)) % totalTiles;
|
||||
tileIndex = std::fmod(p.tileIndex + static_cast<float>(animFrame),
|
||||
static_cast<float>(totalTiles));
|
||||
tileIndex = p.tileIndex + static_cast<float>(animFrame);
|
||||
float tilesFloat = static_cast<float>(totalTiles);
|
||||
// Wrap tile index within totalTiles range
|
||||
while (tileIndex >= tilesFloat) {
|
||||
tileIndex -= tilesFloat;
|
||||
}
|
||||
}
|
||||
group.vertexData.push_back(tileIndex);
|
||||
totalParticles++;
|
||||
|
|
|
|||
|
|
@ -2008,7 +2008,12 @@ void Renderer::updateCharacterAnimation() {
|
|||
// Rider bob: sinusoidal motion synced to mount's run animation (only used in fallback positioning)
|
||||
mountBob = 0.0f;
|
||||
if (moving && haveMountState && curMountDur > 1.0f) {
|
||||
float norm = std::fmod(curMountTime, curMountDur) / curMountDur;
|
||||
// Wrap mount time preserving precision via subtraction instead of fmod
|
||||
float wrappedTime = curMountTime;
|
||||
while (wrappedTime >= curMountDur) {
|
||||
wrappedTime -= curMountDur;
|
||||
}
|
||||
float norm = wrappedTime / curMountDur;
|
||||
// One bounce per stride cycle
|
||||
float bobSpeed = taxiFlight_ ? 2.0f : 1.0f;
|
||||
mountBob = std::sin(norm * 2.0f * 3.14159f * bobSpeed) * 0.12f;
|
||||
|
|
@ -2580,8 +2585,13 @@ bool Renderer::shouldTriggerFootstepEvent(uint32_t animationId, float animationT
|
|||
return false;
|
||||
}
|
||||
|
||||
float norm = std::fmod(animationTimeMs, animationDurationMs) / animationDurationMs;
|
||||
if (norm < 0.0f) norm += 1.0f;
|
||||
// Wrap animation time preserving precision via subtraction instead of fmod
|
||||
float wrappedTime = animationTimeMs;
|
||||
while (wrappedTime >= animationDurationMs) {
|
||||
wrappedTime -= animationDurationMs;
|
||||
}
|
||||
if (wrappedTime < 0.0f) wrappedTime += animationDurationMs;
|
||||
float norm = wrappedTime / animationDurationMs;
|
||||
|
||||
if (animationId != footstepLastAnimationId) {
|
||||
footstepLastAnimationId = animationId;
|
||||
|
|
@ -2875,8 +2885,13 @@ void Renderer::update(float deltaTime) {
|
|||
float animTimeMs = 0.0f, animDurationMs = 0.0f;
|
||||
if (characterRenderer->getAnimationState(mountInstanceId_, animId, animTimeMs, animDurationMs) &&
|
||||
animDurationMs > 1.0f && cameraController->isMoving()) {
|
||||
float norm = std::fmod(animTimeMs, animDurationMs) / animDurationMs;
|
||||
if (norm < 0.0f) norm += 1.0f;
|
||||
// Wrap animation time preserving precision via subtraction instead of fmod
|
||||
float wrappedTime = animTimeMs;
|
||||
while (wrappedTime >= animDurationMs) {
|
||||
wrappedTime -= animDurationMs;
|
||||
}
|
||||
if (wrappedTime < 0.0f) wrappedTime += animDurationMs;
|
||||
float norm = wrappedTime / animDurationMs;
|
||||
|
||||
if (animId != mountFootstepLastAnimId) {
|
||||
mountFootstepLastAnimId = animId;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue