mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 00:03:50 +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
|
// Global sequence: always use sub-array 0, wrap time at global duration
|
||||||
outSeqIdx = 0;
|
outSeqIdx = 0;
|
||||||
float dur = static_cast<float>(globalSeqDurations[track.globalSequence]);
|
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 {
|
} else {
|
||||||
outSeqIdx = seqIdx;
|
outSeqIdx = seqIdx;
|
||||||
outTime = time;
|
outTime = time;
|
||||||
|
|
@ -2070,8 +2078,9 @@ void M2Renderer::update(float deltaTime, const glm::vec3& cameraPos, const glm::
|
||||||
for (size_t idx : particleOnlyInstanceIndices_) {
|
for (size_t idx : particleOnlyInstanceIndices_) {
|
||||||
if (idx >= instances.size()) continue;
|
if (idx >= instances.size()) continue;
|
||||||
auto& instance = instances[idx];
|
auto& instance = instances[idx];
|
||||||
if (instance.animTime > 3333.0f) {
|
// Use iterative subtraction instead of fmod() to preserve precision
|
||||||
instance.animTime = std::fmod(instance.animTime, 3333.0f);
|
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.animTime = 0.0f;
|
||||||
instance.variationTimer = 4000.0f + static_cast<float>(rand() % 6000);
|
instance.variationTimer = 4000.0f + static_cast<float>(rand() % 6000);
|
||||||
} else {
|
} 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) {
|
if ((em.flags & kParticleFlagTiled) && totalTiles > 1) {
|
||||||
float animSeconds = inst.animTime / 1000.0f;
|
float animSeconds = inst.animTime / 1000.0f;
|
||||||
uint32_t animFrame = static_cast<uint32_t>(std::floor(animSeconds * totalTiles)) % totalTiles;
|
uint32_t animFrame = static_cast<uint32_t>(std::floor(animSeconds * totalTiles)) % totalTiles;
|
||||||
tileIndex = std::fmod(p.tileIndex + static_cast<float>(animFrame),
|
tileIndex = p.tileIndex + static_cast<float>(animFrame);
|
||||||
static_cast<float>(totalTiles));
|
float tilesFloat = static_cast<float>(totalTiles);
|
||||||
|
// Wrap tile index within totalTiles range
|
||||||
|
while (tileIndex >= tilesFloat) {
|
||||||
|
tileIndex -= tilesFloat;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
group.vertexData.push_back(tileIndex);
|
group.vertexData.push_back(tileIndex);
|
||||||
totalParticles++;
|
totalParticles++;
|
||||||
|
|
|
||||||
|
|
@ -2008,7 +2008,12 @@ void Renderer::updateCharacterAnimation() {
|
||||||
// Rider bob: sinusoidal motion synced to mount's run animation (only used in fallback positioning)
|
// Rider bob: sinusoidal motion synced to mount's run animation (only used in fallback positioning)
|
||||||
mountBob = 0.0f;
|
mountBob = 0.0f;
|
||||||
if (moving && haveMountState && curMountDur > 1.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
|
// One bounce per stride cycle
|
||||||
float bobSpeed = taxiFlight_ ? 2.0f : 1.0f;
|
float bobSpeed = taxiFlight_ ? 2.0f : 1.0f;
|
||||||
mountBob = std::sin(norm * 2.0f * 3.14159f * bobSpeed) * 0.12f;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float norm = std::fmod(animationTimeMs, animationDurationMs) / animationDurationMs;
|
// Wrap animation time preserving precision via subtraction instead of fmod
|
||||||
if (norm < 0.0f) norm += 1.0f;
|
float wrappedTime = animationTimeMs;
|
||||||
|
while (wrappedTime >= animationDurationMs) {
|
||||||
|
wrappedTime -= animationDurationMs;
|
||||||
|
}
|
||||||
|
if (wrappedTime < 0.0f) wrappedTime += animationDurationMs;
|
||||||
|
float norm = wrappedTime / animationDurationMs;
|
||||||
|
|
||||||
if (animationId != footstepLastAnimationId) {
|
if (animationId != footstepLastAnimationId) {
|
||||||
footstepLastAnimationId = animationId;
|
footstepLastAnimationId = animationId;
|
||||||
|
|
@ -2875,8 +2885,13 @@ void Renderer::update(float deltaTime) {
|
||||||
float animTimeMs = 0.0f, animDurationMs = 0.0f;
|
float animTimeMs = 0.0f, animDurationMs = 0.0f;
|
||||||
if (characterRenderer->getAnimationState(mountInstanceId_, animId, animTimeMs, animDurationMs) &&
|
if (characterRenderer->getAnimationState(mountInstanceId_, animId, animTimeMs, animDurationMs) &&
|
||||||
animDurationMs > 1.0f && cameraController->isMoving()) {
|
animDurationMs > 1.0f && cameraController->isMoving()) {
|
||||||
float norm = std::fmod(animTimeMs, animDurationMs) / animDurationMs;
|
// Wrap animation time preserving precision via subtraction instead of fmod
|
||||||
if (norm < 0.0f) norm += 1.0f;
|
float wrappedTime = animTimeMs;
|
||||||
|
while (wrappedTime >= animDurationMs) {
|
||||||
|
wrappedTime -= animDurationMs;
|
||||||
|
}
|
||||||
|
if (wrappedTime < 0.0f) wrappedTime += animDurationMs;
|
||||||
|
float norm = wrappedTime / animDurationMs;
|
||||||
|
|
||||||
if (animId != mountFootstepLastAnimId) {
|
if (animId != mountFootstepLastAnimId) {
|
||||||
mountFootstepLastAnimId = animId;
|
mountFootstepLastAnimId = animId;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue