1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Unity】3DモデルのScaleFactorをAnimationClipに適用する

Last updated at Posted at 2021-04-20

#3DモデルのScaleFactor変更 → アニメーションがおかしくなる問題
Unityに3Dモデルを読み込んだ後、Unity上でサイズを1/2にしました。
ScaleFactorを 1.0 → 0.5 に変更。メッシュは問題なさそう。
ただ、よーく見るとアニメーションがおかしい…。
noScale_12.gif
左のローポリモデル がScaleFactor変更モデル。右が変更なしモデル。
同じアニメーションのはずが、ローポリの方のステップがキレキレ過ぎる。

実は、アニメーションにはScaleFactorが適用されない仕様でした。
そのため、AnimationClipのPosition値が相対的に大きくなることに。ちなみに、Rotation値はスケールの影響を受けないので元の動きのまま。

#AnimationClipをEditorスクリプトで変更する
対処としては、AnimationClipをスケール変換するツールを自作しました。
ソースは記事の下にあります。

指定されたAnimationClipを読み込み、全てのキーフレームの値にScaleFactorをかけています。
今回はScaleFactorの影響を受けるPositionのみに適用しています。
最終的に、「ファイル名_scaled.anim」というAnimationClipを生成します。

ScalerAnimationEditorWindow.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

namespace ScalerAnimation
{
    public class ScalerAnimationEditorWindow : EditorWindow
    {
        private AnimationClip m_animationClip;
        private float m_scaleFactor = 1.0f;

        [MenuItem("Tools/ScalerAnimation")]
        static void Window()
        {
            var window = GetWindow<ScalerAnimationEditorWindow>("ScalerAnimation");
            window.Show();
        }

        private void Update()
        {
        }

        private void OnGUI()
        {
            EditorGUILayout.Space();
            EditorGUILayout.LabelField("AnimationClip");
            m_animationClip = (AnimationClip)EditorGUILayout.ObjectField(m_animationClip, typeof(AnimationClip), true);
            m_scaleFactor = EditorGUILayout.FloatField("Scale Factor", m_scaleFactor);

            if (m_animationClip != null)
            {
                if (GUILayout.Button("Apply"))
                {
                    ScalerAnimation(m_animationClip);
                }
            }
        }

        private void ScalerAnimation(AnimationClip animationClip)
        {
            // Copy Clip
            var copyAnimationClip = CopyAnimationClip(animationClip);
            // Get Properties
            var animationProperties = GetAnimationProperties(copyAnimationClip);
            // Apply Scale Factor
            ApplyScalerAnimation(copyAnimationClip, animationProperties);
        }

        private AnimationClip CopyAnimationClip(AnimationClip animationClip)
        {
            var copyAnimationClip = Instantiate(animationClip) as AnimationClip;
            var path = AssetDatabase.GetAssetPath(animationClip);
            var directoryName = System.IO.Path.GetDirectoryName(path);
            AssetDatabase.CreateAsset(copyAnimationClip, $"{directoryName}/{animationClip.name}_scaled.anim");
            return copyAnimationClip;
        }

        private void ApplyScalerAnimation(AnimationClip animationClip, Dictionary<string, AnimationProperty> animationProperties)
        {
            var bindings = AnimationUtility.GetCurveBindings(animationClip);
            foreach (var binding in bindings)
            {
                var curve = AnimationUtility.GetEditorCurve(animationClip, binding);
                var boneName = System.IO.Path.GetFileName(binding.path);
                var animationProperty = animationProperties[boneName];
                switch (binding.propertyName)
                {
                    case "m_LocalPosition.x":
                        curve.keys = animationProperty.GetScalerLocalPositionX(m_scaleFactor);
                        AnimationUtility.SetEditorCurve(animationClip, binding, curve);
                        break;
                    case "m_LocalPosition.y":
                        curve.keys = animationProperty.GetScalerLocalPositionY(m_scaleFactor);
                        AnimationUtility.SetEditorCurve(animationClip, binding, curve);
                        break;
                    case "m_LocalPosition.z":
                        curve.keys = animationProperty.GetScalerLocalPositionZ(m_scaleFactor);
                        AnimationUtility.SetEditorCurve(animationClip, binding, curve);
                        break;
                }
            }
        }

        private Dictionary<string, AnimationProperty> GetAnimationProperties(AnimationClip animationClip)
        {
            var animationProperties = new Dictionary<string, AnimationProperty>();

            var bindings = AnimationUtility.GetCurveBindings(animationClip);
            foreach (var binding in bindings)
            {
                var curve = AnimationUtility.GetEditorCurve(animationClip, binding);
                var boneName = System.IO.Path.GetFileName(binding.path);
                if (!animationProperties.ContainsKey(boneName))
                {
                    animationProperties.Add(boneName, new AnimationProperty());
                }
                switch (binding.propertyName)
                {
                    case "m_LocalPosition.x":
                        animationProperties[boneName].localPositionX.AddRange(curve.keys);
                        break;
                    case "m_LocalPosition.y":
                        animationProperties[boneName].localPositionY.AddRange(curve.keys);
                        break;
                    case "m_LocalPosition.z":
                        animationProperties[boneName].localPositionZ.AddRange(curve.keys);
                        break;
                }
            }
            return animationProperties;
        }
    }
}

###使い方
Tools > ScalerAnimationから実行できます。
toolWindow.png

アニメーションに適用できました。
scale_3.gif

###AnimationClip スケール変換ツール
githubに置いています。

#参考
こちらのミラー変換ツールを参考にしました。
https://github.com/hisakataIsm/MirrorAnimation

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?