FBXに含まれるAnimation Clipの一括変換 (Unity)
以前以下の記事を書いたのだが、一つ一つ同じ設定をしてたら時間が足りないので一括で設定を変更できるコードを書いた qiita.com
使用条件
- MixamoでダウンロードしたアニメーションのFBXであること
Assets/Resources/Avatar/
直下にMixamoでダウンロードしたキャラクターのFBXが存在すること、またファイル名がcharacterであること- characterの設定を以下のように変更すること
今回MixamoのアニメーションをVRMで再生するときに足の向きがおかしくなる現象に遭遇したのでそれの対応も含めている 以下のサイトを参考にさせていただきました
MixamoアニメーションがUnityで動かない?足がおかしくなる?時の対処法【アバターの適用が重要】 | YouDoYou Blog ~スマートかつ快適に創造を楽しむ~
解決法としてはMixamoでダウンロードしたアニメーションのFBXのRigに対してMixamoで出力したキャラクターについているAvaterを設定することで正しく動く
使用方法
設定を変更したいFBXを選択してメニューバーにあるAssets/Set Animation Options
を選択することで変更可能
Assets/Set Loop
ではアニメーションクリップのLoop Timeにチェックを入れることができる
using UnityEngine; using UnityEditor; public class AnimationProcessor : AssetPostprocessor { static void SetAnimationImporterSettings(ModelImporter importer) { //rigの設定 importer.animationType = ModelImporterAnimationType.Human; importer.avatarSetup = ModelImporterAvatarSetup.CopyFromOther; var avatar = Resources.Load<GameObject>("Avatar/character"); if (avatar != null) { importer.sourceAvatar = avatar.GetComponent<Animator>().avatar; } //animationClipの設定 var clips = importer.clipAnimations; if (clips.Length == 0) clips = importer.defaultClipAnimations; foreach (var clip in clips) { clip.name = System.IO.Path.GetFileNameWithoutExtension(importer.assetPath); clip.keepOriginalOrientation = true; clip.keepOriginalPositionY = true; clip.keepOriginalPositionXZ = true; clip.lockRootRotation = true; clip.lockRootHeightY = true; clip.lockRootPositionXZ = false; clip.lockRootHeightY = true; clip.heightFromFeet = false; clip.keepOriginalPositionY = true; clip.heightOffset = 0f; clip.cycleOffset = 0f; clip.rotationOffset = 0f; } importer.clipAnimations = clips; } static void SetAnimationLoopSettings(ModelImporter importer) { //animationClipの設定 var clips = importer.clipAnimations; if (clips.Length == 0) clips = importer.defaultClipAnimations; foreach (var clip in clips) { clip.loop = true; } importer.clipAnimations = clips; } void OnPreprocessAnimation() { // 自動的に実行 //SetAnimationImporterSettings(assetImporter as ModelImporter); } [MenuItem("Assets/Set Animation Options", true)] static bool SetAnimationOptionsValidate() { return Selection.GetFiltered(typeof(GameObject), SelectionMode.Assets).Length > 0; } [MenuItem("Assets/Set Animation Options")] static void SetAnimationOptions() { var filtered = Selection.GetFiltered(typeof(GameObject), SelectionMode.Assets); foreach (var go in filtered) { var path = AssetDatabase.GetAssetPath(go); var importer = AssetImporter.GetAtPath(path); SetAnimationImporterSettings(importer as ModelImporter); AssetDatabase.ImportAsset(path); } Selection.activeObject = null; } [MenuItem("Assets/Set Loop", true)] static bool SetLoopValidate() { return Selection.GetFiltered(typeof(GameObject), SelectionMode.Assets).Length > 0; } [MenuItem("Assets/Set Loop")] static void SetLoop() { var filtered = Selection.GetFiltered(typeof(GameObject), SelectionMode.Assets); foreach (var go in filtered) { var path = AssetDatabase.GetAssetPath(go); var importer = AssetImporter.GetAtPath(path); SetAnimationLoopSettings(importer as ModelImporter); AssetDatabase.ImportAsset(path); } Selection.activeObject = null; } }