This document is about: QUANTUM 3
SWITCH TO

Unityアニメーションカーブのベイク

QuantumのFPAnimationCurveは、UnityのCurve Editorを通して、非決定論的な型の変換を内部的に行っています。エディター内の自動的な変換が利用できない場合には、AnimationCurveから変換を行うと便利なことがあります。

一例として、Unityのアニメーションクリップから得られるカーブを変換して、シミュレーションで使用できる決定論的なバージョンを作成できます。

AnimationCurveからFPAnimationCurveを作成するために必要なスニペットは次の通りです。

C#

public FPAnimationCurve ConvertAnimationCurve(AnimationCurve animationCurve)
{
    // Unityのキーフレームを取得する
    Keyframe[] unityKeys = animationCurve.keys;

    // 情報を受け取るためのQuantumカーブとキーフレームを用意する
    FPAnimationCurve fpCurve = new FPAnimationCurve();
    fpCurve.Keys = new FPAnimationCurve.Keyframe[unityKeys.Length];

    // 対象カーブにおけるUnityの開始/終了時間を取得する
    float startTime = animationCurve.keys.Length == 0 ? 0.0f : float.MaxValue;
    float endTime = animationCurve.keys.Length == 0 ? 1.0f : float.MinValue;

    // カーブの分解能(どの程度細かいか)を設定する
    fpCurve.Resolution = 32;

    for (int i = 0; i < unityKeys.Length; i++)
    {
        fpCurve.Keys[i].Time = FP.FromFloat_UNSAFE(unityKeys[i].time);
        fpCurve.Keys[i].Value = FP.FromFloat_UNSAFE(unityKeys[i].value);

        if (float.IsInfinity(unityKeys[i].inTangent) == false)
        {
            fpCurve.Keys[i].InTangent = FP.FromFloat_UNSAFE(unityKeys[i].inTangent);
        }
        else
        {
            fpCurve.Keys[i].InTangent = FP.SmallestNonZero;
        }

        if (float.IsInfinity(unityKeys[i].outTangent) == false)
        {
            fpCurve.Keys[i].OutTangent = FP.FromFloat_UNSAFE(unityKeys[i].outTangent);
        }
        else
        {
            fpCurve.Keys[i].OutTangent = FP.SmallestNonZero;
        }

        fpCurve.Keys[i].TangentModeLeft = (byte)AnimationUtility.GetKeyLeftTangentMode(animationCurve, i);
        fpCurve.Keys[i].TangentModeRight = (byte)AnimationUtility.GetKeyRightTangentMode(animationCurve, i);

        startTime = Mathf.Min(startTime, animationCurve[i].time);
        endTime = Mathf.Max(endTime, animationCurve[i].time);
    }

    fpCurve.StartTime = FP.FromFloat_UNSAFE(startTime);
    fpCurve.EndTime = FP.FromFloat_UNSAFE(endTime);

    fpCurve.PreWrapMode = (int)animationCurve.preWrapMode;
    fpCurve.PostWrapMode = (int)animationCurve.postWrapMode;

    // UnityカーブをQuantumカーブに保存する
    SaveQuantumCurve(animationCurve, 32, ref fpCurve, startTime, endTime);
    return fpCurve;
}

private void SaveQuantumCurve(AnimationCurve animationCurve, int resolution, ref FPAnimationCurve fpCurve, float startTime, float endTime)
        {
            if (resolution <= 0)
                return;
            fpCurve.Samples = new FP[resolution + 1];
            var deltaTime = (endTime - startTime) / (float)resolution;
            for (int i = 0; i < resolution + 1; i++)
            {
                var time = startTime + deltaTime * i;
                var fp = FP.FromFloat_UNSAFE(animationCurve.Evaluate(time));
                fpCurve.Samples[i].RawValue = fp.RawValue;
            }
        }
Back to top