[UE5] Commandlet を使用したSkeletalMesh/StaticMesh/AnimSequence のインポート

検証バージョン：UE5.3.0

# はじめに
　この記事は **「自動化によってメッシュやアニメーションのリソースファイル（.fbxファイル）をUnreal Engineにインポートする」** ことを説明しています。リソースファイルを手動で１つずつインポートする場合、インポートする度にUnreal Engineのアセットとして認識させるための設定を行う必要があり手間がかかりますが、その作業をCommandletを使用して自動化し、インポート作業の効率化を図ります。

# 手動でもインポートできます
　この記事が有効なのは **「どうしても自動化シナリオに組み込んで手動で一切操作せずにアセットをインポートしたいケース」** です。手動で.fbxファイルを選択して、エディタにドラッグ＆ドロップしてもインポートすることはできます。複数のファイルを選択したり、ディレクトリを選択してドラッグ＆ドロップすることでも複数のファイルを一括してインポートすることが可能です。細かい設定を行わない場合は手動の方がむしろ早いかもしれません。

https://docs.unrealengine.com/5.0/ja/importing-assets-directly-into-unreal-engine/

# 用意するもの
　前提としてUnreal EngineはPCにインストール済みであるとして、以下の3つのファイルを用意します。

**・アセットとしてインポートする.fbxファイル**
　プロジェクトにインポートしたいメッシュやアニメーションのリソース

**・コマンドレット実行用の.batファイル**
　後述の ImportAssets.bat ファイル
　このファイルは自動でインポートを行うために発行するコマンドを定義します

**・インポート設定用の.jsonファイル**
　後述の ImportSkeletalMesh.json, ImportStaticMesh.json, ImportAnimSequence.jsonファイル
　このファイルはアセットのインポートに必要な設定の定義を行います

# スクリプト
　以下のファイルを利用して自動インポートを実施します。インポート前に必要な箇所を事前に変更しておく必要があります。

## コマンドレット実行用ファイル例
```batch: ImportAssets.bat
@echo off
rem editor.exe パス
set EXE_PATH=D:\Github\Release-5.3\Engine\Binaries\Win64\UnrealEditor-Cmd.exe
rem .uproject パス
set PROJECT_PATH=D:\Projects\TP_530\TP_530.uproject
rem importsettings.json パス
set IMPORT_SETTINGS=D:\Projects\TP_530\ImportSkeletalMesh.json
rem importasset command : "-dest"は不具合の回避策
set IMPORT_CMD=-run=ImportAssets -nosourcecontrol -importsettings=%IMPORT_SETTINGS% -dest="/Game" -AllowCommandletRendering -nosourcecontrol
@echo on
 
%EXE_PATH% %PROJECT_PATH% %IMPORT_CMD%
```

## インポート設定用ファイル例
　SkeletalMesh, StaticMesh, AnimSequenceのそれぞれのインポート設定ファイルの例を示します。設定に必要なパラメータは***class UFbxImportUI***で定義されており、手動操作によってUIからインポート設定を行う内容と同じとなっております。詳しい設定内容を知りたい方は [UFbxImportUI](https://docs.unrealengine.com/5.3/en-US/API/Editor/UnrealEd/Factories/UFbxImportUI/) をご覧ください。

　また、この内容は ***FbxMainImport.cpp***の***ApplyImportUIToImportOptions*** で設定されるため、どのように反映されるかはこの関数をチェックするか、デバッグ時にブレークしてみることをおすすめします。

```json: ImportSkeletalMesh.json
{
	"ImportGroups": [
		{
			"GroupName": "SkeletalMesh",
			"FileNames": [
				"D:/Projects/ImportTest/SK_Mannequin.FBX"
			],
			"DestinationPath": "/Game/Import",
			"FactoryName": "FbxFactory",
			"bReplaceExisting": "true",
			"bSkipReadOnly": "false",
			"LevelToLoad": "",
			"ImportSettings": {
				"OriginalImportType": "FBXIT_SkeletalMesh",
				"MeshTypeToImport": "FBXIT_SkeletalMesh",
				"bResetToFbxOnMaterialConflict": "true",
				"bImportAnimations": "true",
				"bCreatePhysicsAsset": "true",
				"PhysicsAsset": "",
				"bImportMaterials": "false",
				"bAutoComputeLodDistances": "false",
				"bImportMesh": "false",
				"bImportMorphTargets": "false",
				"bUseDefaultSampleRate": "true",
				"bImportAsSkeletal": "true",
				"Skeleton": "SK_Mannequin_Skeleton",
				"bImportMeshesInBoneHierarchy": "false"
			}
		}
	]
}
```

```json: ImportStaticMesh.json
{
	"ImportGroups":[
		{
			"GroupName": "StaticMesh",
			"Filenames":[
				"D:/Projects/ImportTest/SM_ChamferCube.FBX"
			],
			"DestinationPath": "/Game/Import/",
			"FactoryName": "FbxFactory",
			"bReplaceExisting": "true",
			"bSkipReadOnly": "false",
			"ImportSettings":{
				"OriginalImportType": "FBXIT_StaticMesh",
				"MeshTypeToImport": "FBXIT_StaticMesh",
				"bImportAnimations": "false",
				"LodNumber": "0",
				"MinimumLodNumber": "0",
				"TextureImportData":{
					"TextureImportData": "false"
				},
				"StaticMeshImportData":{
					"bBuildNanite": "true",
					"NormalImportMethod": "FBXNIM_ImportNormals",
					"NormalGenerationMethod": "MikkTSpace",
					"bComputeWeightedNormals": "true",
					"ImportTranslation": {
						"x": "0.0","y": "0.0", "z": "0.0"
					},
					"ImportRotation": {
						"x": "0.0","y": "0.0", "z": "0.0"
					},
					"ImportUniformScale": "1.0",
					"bTransformVertexToAbsolute": "true",
					"bBakePivotInVertex": "false",
					"bImportMeshLODs": "false",
					"bConvertScene": "true",
					"bForceFrontXAxis": "false",
					"bConvertSceneUnit": "false",
					"bReorderMaterialToFbxOrder": "true",
					"DistanceFieldResolutionScale": "1.0",
					"bCombineMeshes": "false",
					"bRemoveDegenerates": "true",
					"bBuildReversedIndexBuffer": "true",
					"bGenerateLightmapUVs": "true",
					"bOneConvexHullPerUCX": "true",
					"bAutoGenerateCollision": "true",
					"StaticMeshLODGroup": "None"
				}
			}
		}
	]
}
```

```json: ImportAnimSequence.json
{
	"ImportGroups":[
		{
			"GroupName": "AnimSequence",
			"Filenames":[
				"D:/Projects/ImportTest/MM_Idle.FBX"
			],
			"DestinationPath": "/Game/Import/",
			"FactoryName": "FbxFactory",
			"bReplaceExisting": "true",
			"bSkipReadOnly": "false",
			"ImportSettings":{
				"bImportAnimations": "true",
				"MeshTypeToImport": "FBXIT_Animation",
				"OriginalImportType": "FBXIT_Animation",
				"Skeleton": "/Game/Characters/Mannequins/Meshes/SK_Mannequin.SK_Mannequin",
				"bImportAsSkeletal": "false",
				"bImportMaterials": "false",
				"AnimSequenceImportData":{
					"bImportMesh": "false",
					"AnimationLength": "FBXALIT_ExportedTime",
					"bUseDefaultSampleRate": "true",
					"bRemoveRedundantKeys": "false",
					"bPreserveLocalTransform": "false",
					"bImportMorphTargets": "true",
					"bForceFrontXAxis": "false",
					"bSetMaterialDriveParameterOnCustomAttribute": "false",
					"bDeleteExistingMorphTargetCurves": "false",
					"bConvertSceneUnit": "false",
					"bDoNotImportCurveWithZero": "true",
					"bConvertScene": "true",
					"bImportCustomAttribute": "true"
				}
			}
		}
	]
}
```

# 実行方法
**1) スクリプトの編集**
　上記インポート設定用ファイルの内容をコピーし自作用.jsonファイルを作成して、アセットをインポートしたい設定に沿って内容を編集します。次に上記コマンドレット実行用の.batファイルの内容をコピーし、自作用バッチファイルを作成して、自身のプロジェクトに沿った内容にパスを変更します。

**2) ImportAssets.bat を実行**
　1) で作成した、コマンドレット実行用の.batファイル を実行すると自動でアセットのインポートを開始します。実行時にコマンドプロンプトを開き、終了すると閉じます。

# デバッグ
　うまくインポートが動作しない場合、**Visual StudioからCommandletを実行する**ことによってデバッグが可能です。Commandletによる動作をVisual Studioからステップ実行によって確認する場合は、プロジェクトのコマンド引数(Command Argumnts)に、バッチファイルから実行している引数を与えるだけで、F5起動した際にデバッグ実行が可能となっております。

　Visual Studioから起動する場合、ソリューションのスタートアッププロジェクトは「インポート対象のプロジェクト」を指定しておきます。以下はVisual Studioのプロジェクトからコマンド引数を指定する例です。このデバッグ方法は ImportAssets以外のコマンドレット実行時にも同様に利用可能です。
![2023-07-27_00h14_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/364110/6f0b445a-e074-7a3c-367e-3de62da55d25.png)

# まとめ
　複数のStaticMeshやAnimSequenceをまとめてインポートしたい、同一設定で一括してインポートしたい、といったケースでは本記事が役に立つかと思いますので是非ご活用ください。

# おまけ
　他の手段として、Pythonでもインポートやリインポート処理を作成して自動で実行することは可能です。ご参考までに。

https://docs.unrealengine.com/5.0/ja/scripting-the-unreal-editor-using-python/

https://zenn.dev/kta552/articles/bf11b5cc958319