From 831f6a08b6ffdb27ede5e72e220b19cf8c0af5c8 Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Wed, 4 Feb 2026 17:46:41 +0300 Subject: [PATCH 1/2] Animation: Animator can produce nan for bones. #1255 --- thirdparty/next/src/anim/animationcurve.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/thirdparty/next/src/anim/animationcurve.cpp b/thirdparty/next/src/anim/animationcurve.cpp index 05a37014c..9fb7d6fa2 100644 --- a/thirdparty/next/src/anim/animationcurve.cpp +++ b/thirdparty/next/src/anim/animationcurve.cpp @@ -86,12 +86,16 @@ Quaternion AnimationCurve::valueQuaternion(float pos) const { Quaternion result; if(a != -1 && b != -1) { const KeyFrame &keyA = m_keys[a]; - const KeyFrame &keyB = m_keys[b]; + Quaternion qA(keyA.m_value[0], keyA.m_value[1], keyA.m_value[2], keyA.m_value[3]); - float factor = (pos - keyA.m_position) / (keyB.m_position - keyA.m_position); + if(a == b) { + return qA; + } - Quaternion qA(keyA.m_value[0], keyA.m_value[1], keyA.m_value[2], keyA.m_value[3]); + const KeyFrame &keyB = m_keys[b]; Quaternion qB(keyB.m_value[0], keyB.m_value[1], keyB.m_value[2], keyB.m_value[3]); + + float factor = (pos - keyA.m_position) / (keyB.m_position - keyA.m_position); result.mix(qA, qB, factor); } return result; From e80ac7ee9f73f352b30b012a8303dc3d12ff63c9 Mon Sep 17 00:00:00 2001 From: Evgeny Prikazchikov Date: Wed, 4 Feb 2026 17:50:10 +0300 Subject: [PATCH 2/2] update --- engine/src/components/animator.cpp | 50 ++++++++++++++++++------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/engine/src/components/animator.cpp b/engine/src/components/animator.cpp index 6df0717e3..58f8abea1 100644 --- a/engine/src/components/animator.cpp +++ b/engine/src/components/animator.cpp @@ -75,6 +75,7 @@ void Animator::sampleVector4(float dt, TargetProperties &target) { Vector4 vec4; float factor = 0.0f; + bool updated = false; auto playbackIt = target.playbacks.begin(); while(playbackIt != target.playbacks.end()) { @@ -92,6 +93,7 @@ void Animator::sampleVector4(float dt, TargetProperties &target) { } vec4 += playback.motion->valueVector4(playback.currentPosition) * playback.weight; + updated = true; } if(endOfPlayback) { @@ -101,20 +103,22 @@ void Animator::sampleVector4(float dt, TargetProperties &target) { } } - switch(target.defaultValue.type()) { - case MetaType::BOOLEAN: target.property.write(target.object, (bool)vec4.x); break; - case MetaType::INTEGER: target.property.write(target.object, (int)vec4.x); break; - case MetaType::FLOAT: target.property.write(target.object, vec4.x); break; - case MetaType::VECTOR2: target.property.write(target.object, Vector2(vec4)); break; - case MetaType::VECTOR3: { - switch(target.flag) { - case TransformFlags::Position: static_cast(target.object)->setPosition(vec4); break; - case TransformFlags::Rotation: static_cast(target.object)->setRotation(vec4); break; - case TransformFlags::Scale: static_cast(target.object)->setScale(vec4); break; - default: target.property.write(target.object, Vector3(vec4)); break; - } - } break; - default: target.property.write(target.object, vec4); break; + if(updated) { + switch(target.defaultValue.type()) { + case MetaType::BOOLEAN: target.property.write(target.object, (bool)vec4.x); break; + case MetaType::INTEGER: target.property.write(target.object, (int)vec4.x); break; + case MetaType::FLOAT: target.property.write(target.object, vec4.x); break; + case MetaType::VECTOR2: target.property.write(target.object, Vector2(vec4)); break; + case MetaType::VECTOR3: { + switch(target.flag) { + case TransformFlags::Position: static_cast(target.object)->setPosition(vec4); break; + case TransformFlags::Rotation: static_cast(target.object)->setRotation(vec4); break; + case TransformFlags::Scale: static_cast(target.object)->setScale(vec4); break; + default: target.property.write(target.object, Vector3(vec4)); break; + } + } break; + default: target.property.write(target.object, vec4); break; + } } } @@ -122,6 +126,7 @@ void Animator::sampleQuaternion(float dt, TargetProperties &target) { Quaternion quat; float factor = 0.0f; + bool updated = false; auto playbackIt = target.playbacks.begin(); while(playbackIt != target.playbacks.end()) { @@ -139,6 +144,7 @@ void Animator::sampleQuaternion(float dt, TargetProperties &target) { } quat.mix(quat, playback.motion->valueQuaternion(playback.currentPosition), playback.weight); + updated = true; } if(endOfPlayback) { @@ -148,10 +154,12 @@ void Animator::sampleQuaternion(float dt, TargetProperties &target) { } } - if(target.flag == TransformFlags::Quat) { - static_cast(target.object)->setQuaternion(quat); - } else { - target.property.write(target.object, quat); + if(updated) { + if(target.flag == TransformFlags::Quat) { + static_cast(target.object)->setQuaternion(quat); + } else { + target.property.write(target.object, quat); + } } } @@ -159,6 +167,7 @@ void Animator::sampleString(float dt, TargetProperties &target) { TString str; float factor = 0.0f; + bool updated = false; auto playbackIt = target.playbacks.begin(); while(playbackIt != target.playbacks.end()) { @@ -176,6 +185,7 @@ void Animator::sampleString(float dt, TargetProperties &target) { } str = playback.motion->valueString(playback.currentPosition); + updated = true; } if(endOfPlayback) { @@ -185,7 +195,9 @@ void Animator::sampleString(float dt, TargetProperties &target) { } } - target.property.write(target.object, str); + if(updated) { + target.property.write(target.object, str); + } } /*!