前提
アニメーションのキーリダクションを行うスクリプトを作っているのですが、以下のコードでキーリダクションを行うと、Rotationだけ正しく行われません。
正確には、xはうまくいっているのですが、y、zは一部の値が変わってしまっているようです。
実現したいこと
Rotationのキーリダクションが正しく動作する
該当のソースコード
c#
1using System.IO; 2using System.Linq; 3using UnityEngine; 4using UnityEditor; 5using System.Collections.Generic; 6using System; 7 8public class KeyReductionTest : AssetPostprocessor 9{ 10 [MenuItem("Assets/Key Reduction Test")] 11 static void KeyReduction() 12 { 13 Debug.Log("Key Reduction Test..."); 14 foreach (UnityEngine.Object obj in Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Editable)) 15 { 16 string path = AssetDatabase.GetAssetPath(obj); 17 AnimationClip anim_clip = (AnimationClip)AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)); 18 19 foreach (var binding in AnimationUtility.GetCurveBindings(anim_clip).ToArray()) 20 { 21 AnimationCurve curve = AnimationUtility.GetEditorCurve(anim_clip, binding); 22 AnimationCurveKeyReduction(curve, binding.propertyName, 0.001f); 23 AnimationUtility.SetEditorCurve(anim_clip, binding, curve); 24 } 25 string anim_clip_name = Path.GetDirectoryName(path) + "/" + Path.GetFileNameWithoutExtension(path); 26 WriteAnimationCurve(anim_clip, anim_clip_name); 27 } 28 } 29 30 static private void WriteAnimationCurve(AnimationClip anim_clip, string anim_clip_name) 31 { 32 string tmp_name = anim_clip_name + "_tmp.anim"; 33 var copyClip = UnityEngine.Object.Instantiate(anim_clip); 34 AssetDatabase.CreateAsset(copyClip, tmp_name); 35 FileUtil.ReplaceFile(tmp_name, anim_clip_name + ".anim"); 36 AssetDatabase.DeleteAsset(tmp_name); 37 AssetDatabase.Refresh(); 38 } 39 40 static private float GetValueFromTime(Keyframe key1, Keyframe key2, float time) 41 { 42 float t; 43 float a, b, c; 44 float kd, vd; 45 46 if (key1.outTangent == Mathf.Infinity) return key1.value; 47 48 kd = key2.time - key1.time; 49 vd = key2.value - key1.value; 50 t = (time - key1.time) / kd; 51 52 a = -2 * vd + kd * (key1.outTangent + key2.inTangent); 53 b = 3 * vd - kd * (2 * key1.outTangent + key2.inTangent); 54 c = kd * key1.outTangent; 55 56 return key1.value + t * (t * (a * t + b) + c); 57 } 58 59 static private bool IsInterpolationValue(Keyframe key1, Keyframe key2, Keyframe comp, float eps) 60 { 61 var val1 = GetValueFromTime(key1, key2, comp.time); 62 63 if (eps < System.Math.Abs(comp.value - val1)) return false; 64 65 var time = key1.time + (comp.time - key1.time) * 0.5f; 66 val1 = GetValueFromTime(key1, comp, time); 67 var val2 = GetValueFromTime(key1, key2, time); 68 69 return (System.Math.Abs(val2 - val1) <= eps) ? true : false; 70 } 71 72 static public IEnumerable<int> GetDeleteKeyIndex(Keyframe[] keys, float eps) 73 { 74 for (int s_idx = 0, i = 1; i < keys.Length - 1; i++) 75 { 76 if (IsInterpolationValue(keys[s_idx], keys[i + 1], keys[i], eps)) 77 { 78 yield return i; 79 } 80 else 81 { 82 s_idx = i; 83 } 84 } 85 } 86 87 static public void AnimationCurveKeyReduction(AnimationCurve in_curve, string propertyName, float eps = 0.0001f) 88 { 89 if (in_curve.keys.Length <= 2) return; 90 var del_indexes = GetDeleteKeyIndex(in_curve.keys, eps).ToArray(); 91 foreach (var del_idx in del_indexes.Reverse()) in_curve.RemoveKey(del_idx); 92 } 93}
補足情報(FW/ツールのバージョンなど)
Unity 2020.3.19f1
Animationビュー上のSpotLightBase_B_y_03 : Rotationを右クリックするとコンテキストメニュー上に「Interpolation」という項目があるかと思いますが、それの設定はどうなっているでしょうかね(https://docs.unity3d.com/ja/2020.3/Manual/animeditor-AnimationCurves.html#:~:text=%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82-,%E5%9B%9E%E8%BB%A2%E3%81%AE%E8%A3%9C%E9%96%93%E6%96%B9%E6%B3%95%E3%81%AE%E7%A8%AE%E9%A1%9E,-Unity%20%E3%81%A7%E3%81%AF%E5%9B%9E%E8%BB%A2 )?
あれが「Quaternion」だと、Animationビュー上では回転がオイラー角で表示されていても、内部的にはQuaternion方式でデータが保存されるようです。スクリーンショットを拝見しますにX軸回転90°付近で特にズレが大きくなっているように見えますが、もしかするとQuaternionからAnimationビュー上のオイラー角へ変換する際に起こる致し方ない現象なのかもしれませんね。Animationビュー上の見た目が少々おかしくても、実際にアニメーションを再生したときに不自然な動きがないようでしたらお気になさる必要はないかもしれません。
キーリダクション前のアニメーションクリップファイルをどこかにアップロードしていただくことは可能でしょうか?それがあれば挙動を調べやすくなるんじゃないかと思います。
キーリダクション前のアニメーションクリップファイルをアップロードしましたので、本文にリンクを追加しました。
スクリーンショットのすぐ下に追加しています。
「Interpolation」の設定ですが「Quaternion」になっていることを確認しました。
「Interpolation」を「Euler Angles」に変更してキーリダクションを行ったところ、正しく動くことを確認できました。
ご協力ありがとうございました。
回答1件
あなたの回答
tips
プレビュー