BlendShape と proxy_tpose からアニメーションを生成する

VRChat アバターで使用するために、BlendShape から1フレームのループアニメーションを作りたい。BlendShape のキーのみだと、アニメーションを再生した時にアバターが中腰になってしまうので、proxy_tpose のキーを追加する必要がある。
BlendShape のみを利用してアニメーションを生成する場合は、「BlendShape からアニメーションを生成する」という記事を参照してほしい。

proxy_tpose を複製する

  • proxy_tpose を複製する(Ctrl + D)
  • 複製したものを Assets の適当なフォルダに移動させる

  • 複製した proxy_tpose をダブルクリックして、Animation のタブを開く
  • フレーム 0:00 にあるキーを全てコピーして、フレーム 0:01 に貼り付ける

C# スクリプト

using System.IO;
using UnityEditor;
using UnityEngine;

public class GenerateAnimFromBlendshapeAndTposeAnim : MonoBehaviour
{
    public GameObject avatar;
    public AnimationClip clipTpose;

    [ContextMenu("GenerateAnimatonFromBlendShape")]
    public void GenerateAnimatonFromBlendShape()
    {
        //パスを得る
        var pathAvatar = AssetDatabase.GetAssetPath(avatar);
        var pathClipTpose = AssetDatabase.GetAssetPath(clipTpose);

        //フォルダ(Animations)を作成する
        var pathDirAnims = pathAvatar.Replace(Path.GetFileName(pathAvatar), "") + "/Animations";
        if (!Directory.Exists(pathDirAnims)) Directory.CreateDirectory(pathDirAnims);

        Mesh mesh;
        for (int i = 0; i < avatar.transform.childCount; i++)
        {
            //BlendShapeがあるメッシュを特定する
            var skinnedMesh = avatar.transform.GetChild(i).GetComponent<SkinnedMeshRenderer>();
            if (skinnedMesh != null && skinnedMesh.sharedMesh.blendShapeCount > 0)
            {
                mesh = skinnedMesh.sharedMesh;

                for (int j = 0; j < mesh.blendShapeCount; j++)
                {
                    //BlendShapeの名前を得る
                    var blendshapeName = mesh.GetBlendShapeName(j);

                    //proxy_tposeをフォルダ(Animations)にコピーして、変数にセットする
                    var pathAnimBlendshape = pathDirAnims + "/" + blendshapeName + ".anim";
                    AssetDatabase.CopyAsset(pathClipTpose, pathAnimBlendshape);
                    var clipBlendshape = 
                        (AnimationClip)AssetDatabase.LoadAssetAtPath(pathAnimBlendshape,typeof(AnimationClip));

                    //アニメーションを設定する
                    var serializedClip = new SerializedObject(clipBlendshape);
                    serializedClip.FindProperty("m_AnimationClipSettings.m_LoopTime").boolValue = true;
                    serializedClip.ApplyModifiedProperties();
                    var curve = new AnimationCurve(
                        new Keyframe(0 / 60f, 100f),
                        new Keyframe(1 / 60f, 100f)
                    );
                    clipBlendshape.SetCurve(mesh.name, typeof(SkinnedMeshRenderer), "blendShape." + blendshapeName, curve);
                }
            }
        }
    }
}
  • 「GenerateAnimFromBlendshapeAndTposeAnim」という名前で C# スクリプトを作成する(参考画像内①)
  • スクリプトをダブルクリックで開く(参考画像内①)
    • 上記のスクリプトをコピペして上書き保存する
  • Scene に GameObejct を新規作成する(参考画像内②)
  • スクリプトをドラッグ&ドロップでアタッチする(参考画像内③)
    • Avatar に アバター(FBX ファイル等)をドラッグ&ドロップでセットする(参考画像内④)
    • Clip Tpose に 先に複製した proxy_tpose をドラッグ&ドロップでセットする(参考画像内⑤)

  • 三点リーダをクリックする
  • GenerateAnimationFromBlendShape をクリックする

  • Animations というフォルダが作成されたことを確認する
  • 全ての BlendShape に関して、アニメーションが作成されたことを確認する

  • トラッキング(まばたきやリップシンク)で利用するアニメーションファイルを削除する

所感

  • スクリプトには必要最低限のコードしか書いていないので、適宜修正して使ってほしい。
  • proxy_tpose の複製、および 0:00 から 0:01 へのキーのコピーに関しても、スクリプトに書きたかったが、面倒そうなのでやめた。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です