読者です 読者をやめる 読者になる 読者になる

UnrealEngine4でMMDの表情アニメーションを読み込む


目的
UnrealEngine4(以下UE4)に、MMDモデルの表情モーションを読み込ませます。

方針
MMDの表情モーションデータ(.VMD)をcsv形式に変換し、UE4で扱えるDataTable型としてインポートします。Blueprintの機能を利用して、インポートしたデータを、アニメーションシーケンスへ書き込みます。

前置き
MMDモデルとそのボーンアニメーションはFBXファイルに変換して読み込む方法を取っています。


①アニメーションシーケンスへのキー登録について
表情の情報はモーフターゲットと呼ばれる形で格納され、その情報はスケルタルメッシュの中にあります。元のデータが日本語の為、モーフターゲット名が???(※1)になっていますが、元は「まばたき」や「にっこり」などの日本語です。PmxEditorの内容と一致しています。
 
アニメーションシーケンスのエディット画面から、モーフターゲット名と同じ名前でカーブを追加し、キーを登録することでアニメーションが設定されます。つまり、ここへキーを自動登録することが目的になります。

(※1)
大体、ASCIIコード以外の文字1つにつき、?が3つ並ぶみたいです。csvに変換するときにこの法則を利用していますが、100%ではないので手作業で直しています。


②表情モーションデータ(.VMD)の入力方法について
表情モーションのデータはFBXファイルからインポートできていないようです。構造体の中を探しましたがそれらしいものがありませんでした(見つけられていないだけかもしれません)。その為、外部から読み込む方法を取りました。しかしUE4では、基本的にデータを扱いたいときはコンテンツ内のアセットから読むしかなく、アセットとしてインポートできる型式も限られています。そこで、表情モーションデータ(.VMD)をcsvに変換し(※2)、UE4のDataTableの型としてインポートすることで、アセットとしてアクセスさせるようにしました。


インポートできるようにするため、自前でDataTableの1行となる型を宣言します。FTableRowBase型を継承します。ここで、変数名はcsvのタイトル行と合わせる必要があります。必要な情報は、「モーフターゲット名、キー位置(フレーム番号)、キー値」です。

 USTRUCT()
struct BLUEPRINTOFFICE_API FMorphAnimationTable : public FTableRowBase
{
	GENERATED_USTRUCT_BODY()

	/** Full Path of Blueprint */
	UPROPERTY(EditAnywhere, Category = Pawn)
	FString Morph_Name;

	/** Category of GamePlay Object */
	UPROPERTY(EditAnywhere, Category = Pawn)
	float frame;

	/** Scriptable Use Code */
	UPROPERTY(EditAnywhere, Category = Pawn)
	float Value;
};

これで、DataTableのインポート時に自分で作った型が表示されます。今回は、FMorphAnimationTableです。
f:id:w_a_w_a_w_a:20150409233659p:plain
(※2)
MMDのモデルとモーションのフォーマットが公開されているのでそれを元にツールを作って変換しています。


③Blueprintでの処理について
①の内容を出力、②の内容を入力として、モーション自動登録用のBlueprintを作成します。
必要な引数は、「対象のモデル(スケルタルメッシュ)、対象のアニメーションシーケンス、読み込んだDataTable、DataTableのデータ数」です。「DataTableのデータ数」の引数がかっこ悪いです。DataTableの行数を読む方法が見つかりませんでした。
関数内で行っていることは単純で、DataTableを一行ずつ読み、モーフターゲット名と一致したカーブ名に、キーを登録しているだけです。

bool UMyBlueprintFunctionLibrary::VMDRead(USkeletalMesh* mesh, UAnimSequence* sequence, UDataTable* curveTable, INT32 data_num)
{
	if (mesh == nullptr || sequence == nullptr || curveTable == nullptr)
		return false;

	USkeleton* Skeleton = sequence->GetSkeleton();
	USkeleton::AnimCurveUID CurveUid;
	FFloatCurve* curve;

	FSmartNameMapping* NameMapping = Skeleton->SmartNames.GetContainer(USkeleton::AnimCurveMappingName);

	FName morphName;
	FMorphAnimationTable* dataRow;
	FString ContextString;

	//Clear Curves
	sequence->RawCurveData.Empty();

	//Add Morph Curves
	for (INT32 i = 0; i < mesh->MorphTargets.Num(); i++){
		if (Skeleton->AddSmartnameAndModify(USkeleton::AnimCurveMappingName, mesh->MorphTargets[i]->GetFName(), CurveUid))
		{
			sequence->Modify(true);
			sequence->RawCurveData.AddCurveData(CurveUid);
			sequence->RawCurveData.GetCurveData(CurveUid)->LastObservedName = mesh->MorphTargets[i]->GetFName();
		}
		else if (NameMapping->AddOrFindName(mesh->MorphTargets[i]->GetFName(), CurveUid))
		{
			sequence->Modify(true);
			sequence->RawCurveData.AddCurveData(CurveUid);
			sequence->RawCurveData.GetCurveData(CurveUid)->LastObservedName = mesh->MorphTargets[i]->GetFName();
		}
	}

	//AddKeys
	for (INT32 i = 0; i < data_num; i++){
		dataRow = curveTable->FindRow<FMorphAnimationTable>(*FString::Printf(TEXT("%d"), i), ContextString);
		morphName = FName(*dataRow->Morph_Name);
		NameMapping->AddOrFindName(morphName, CurveUid);
		curve = static_cast<FFloatCurve*>(sequence->RawCurveData.GetCurveData(CurveUid, FRawCurveTracks::FloatType));
		curve->FloatCurve.AddKey(dataRow->frame / 30.0, dataRow->Value);
		//UE_LOG(LogTemp, Warning, TEXT("%s, %f, %f"), *morphName.ToString(), dataRow->frame, dataRow->Value);
	}

	return true;
}

作成したBlueprintを、Level Blueprintに記述し、実行させます。
実行に成功すれば、アニメーションシーケンスにモーション情報が書き込まれます。
書き込んで保存してしまえば、Blueprintがなくても移行して別プロジェクトで使うことができます。
このコードはまともなエラー処理がないので、引数を間違えたり、2回以上実行したりするとUE4ごと落ちます。

f:id:w_a_w_a_w_a:20150407195319p:plain
できました。カーブタイプをモーフカーブにするようチェックをいれます。

動画テストです↓


④使用させて頂いたモデル・参考にさせて頂いた記事など
MMDモデル・モーション
::Lat式ミクVer.2.31 for MikuMikuDance:: / Lat さんのイラスト - ニコニコ静画 (イラスト)
【MMD-DMC3】galaxias! ‐ ニコニコ動画:GINZA

MMDデータの読み込みについて
Happy my life | UE4でミクさんに可愛く踊ってもらう方法
UE4でMMDのモーションを使ってみる - ぼっちプログラマのメモ
UE4 モーフターゲットを使って表情を変えてみる - Let's Enjoy Unreal Engine

UnrealEngine4 について
Using excel to store gameplay data - DataTables - Epic Wiki
Unreal Engine | Unreal Engine API Reference
Unreal Engine | データ駆動型のゲームプレイエレメント
Unreal Engine | アニメーション カーブ
Unreal Engine | FBX モーフターゲット パイプライン
Unreal Engine | C++ とブループリント
Unreal Engine | プログラミング案内