17
12

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 5 years have passed since last update.

Epic Games Japan #1Advent Calendar 2019

Day 12

[UE4] Animation Sequenceをアセット複製せずに直接リターゲットする方法について

Last updated at Posted at 2019-12-11

はじめに

UE4にはアニメーションのリターゲット機能があり、この機能を使うことで一つのアニメーションを様々なキャラクターで流用・共有できます。そして、アニメーションのリターゲット機能には**「同じスケルトンアセットを共有するキャラクター間で行うリターゲット」** と **「スケルトンアセットが異なるキャラクター間で行うリターゲット」**の2種類があります。まずはこれらに関して軽く説明します。

「細かい話はいいから早く機能を使いたいYO!」という方は https://github.com/pafuhana1213/AnimationPreviewer で公開しているサンプルの EUW_RetargetAnimation をご利用ください

同じスケルトンアセットを共有するキャラクター間で行うリターゲット

RetargetingHeader.jpg
https://docs.unrealengine.com/ja/Engine/Animation/AnimationRetargeting/index.html

異なるSkeletal Meshアセットでもスケルトンアセットが共有している場合はアニメーションを流用・共有することができます。また、AnimationBPも流用・共有することができるため、AnimationBPのAnimGraphやEventGraphで実装したロジックも使い回すことができます。更に、アニメーションアセットの数を抑えることができるため、メモリ使用量も最小限に抑えることが可能です。

スケルトンアセットが異なるキャラクター間で行うリターゲット

Retarget1_1.jpg
https://docs.unrealengine.com/ja/Engine/Animation/RetargetingDifferentSkeletons/index.html
スケルトンアセットが異なるキャラクタ間の場合でも、リターゲット用のリグを設定しておけばアニメーションの流用は可能です。しかし、リターゲットされたアニメーションアセットは完全に別アセットとして保存されます。そのため、例えば10個のモーションを10個のキャラクタ(スケルトンは別々)で流用しようとした場合は合計100個のアニメーションアセットが出来上がります。

完全に別アセットになるため、アニメーションの共有はできません。そのため、AnimationBPで実装したロジックも使い回せません。更に大量のアニメーションアセットをロードすることになるため、メモリ使用量が増加していまいます。マーケットプレイスで購入したアニメーションアセットを自作キャラモデルに流用する際は便利な機能ではあるのですが、キャラクタの数やプロジェクトの規模が増えるにつれてこれらのデメリットが問題になる可能性が大きくなります。

アニメーション・スケルトンの共有に関するより詳細な情報に関しては、上述のドキュメントや以下のスライドをご確認ください。
https://www.slideshare.net/EpicGamesJapan/cedec2018-ue4-111104578/103
https://www.slideshare.net/EpicGamesJapan/ue4animation-blueprint/14
https://www.slideshare.net/EpicGamesJapan/ue4-bp18/122

という前提を踏まえて、ようやく本題へ。

Animation Sequenceをアセット複製せずに直接リターゲットする方法について

image.png
image.png
マーケットプレイスで購入したアニメーションアセットを自作キャラモデルで使用する場合、最も有名な方法は上図の方法かと思います。しかし、この方法を使った場合に走る処理は**「スケルトンアセットが異なるキャラクター間で行うリターゲット」です。スケルトンの構成が完全に一致している場合でも「スケルトンアセットが異なるキャラクター間で行うリターゲット」**が走り、完全に別アセットとして保存されます。

「同じスケルトンアセットを共有するキャラクター間で行うリターゲット」 を行うためには、対象のアニメーションアセットに紐付いているスケルトンを変更する必要があります。つまり、購入したアニメーションアセットを自作キャラモデルのスケルトンアセットに紐付ければOKです。

図1.png
この紐付けの変更が簡単にできればいいのですが…ひと手間かかってしまう状況です。具体的には以下の手順が必要です。

  1. 対象のアニメーションアセットをFBX出力
  2. その出力したFBXをContent Browserにドラッグアンドドロップ
  3. 表示されたインポートオプションのSkeletonに自作キャラモデルのスケルトンアセットを設定

面倒ですね!
ということで、Animation Sequenceに紐付ているスケルトンアセットを別のものに差し替える仕組みを Editor Utility Widgetで作成してみました。

具体的な実装方法に関しては https://github.com/pafuhana1213/AnimationPreviewer で公開しているサンプルの「EUW_RetargetAnimation」と 「AnimationPreviewerUtilEd.h/.cpp」を見て頂くとして、この機能を実装する上で最も重要なリターゲット処理の呼び出し部分について解説します。といっても、C++コードを一行呼び出すだけの簡単な内容です。

アニメーションのリターゲット処理を実行するC++関数について

EditorAnimUtils.h
UNREALED_API UObject* RetargetAnimations(USkeleton* OldSkeleton, USkeleton* NewSkeleton, TArray<TWeakObjectPtr<UObject>> AssetsToRetarget, bool bRetargetReferredAssets, const FNameDuplicationRule* NameRule, bool bConvertSpace);
UNREALED_API UObject* RetargetAnimations(USkeleton* OldSkeleton, USkeleton* NewSkeleton, const TArray<FAssetData>& AssetsToRetarget, bool bRetargetReferredAssets, const FNameDuplicationRule* NameRule, bool bConvertSpace);
UNREALED_API UObject* RetargetAnimations(USkeleton* OldSkeleton, USkeleton* NewSkeleton, FAnimationRetargetContext& RetargetContext, bool bRetargetReferredAssets, const FNameDuplicationRule* NameRule);
EditorAnimUtils.cpp
UObject* RetargetAnimations(USkeleton* OldSkeleton, USkeleton* NewSkeleton, FAnimationRetargetContext& RetargetContext, bool bRetargetReferredAssets, const FNameDuplicationRule* NameRule)
{
	check(NewSkeleton);
	UObject* OriginalObject  = RetargetContext.GetSingleTargetObject();
	UPackage* DuplicationDestPackage = NewSkeleton->GetOutermost();

	if(	RetargetContext.HasAssetsToRetarget() )
	{
		if(NameRule)
		{
			RetargetContext.DuplicateAssetsToRetarget(DuplicationDestPackage, NameRule);
		}
		RetargetContext.RetargetAnimations(OldSkeleton, NewSkeleton);
	}
...

EditorAnimUtils::RetargetAnimations関数を呼び出すことで、アニメーションのリターゲット処理を実行することが可能です。ここで特に重要なのは引数の一つである const FNameDuplicationRule* NameRuleです。このNameRulenullptrでは ない 場合、「スケルトンアセットが異なるキャラクター間で行うリターゲット」によるアセットの複製処理が走ります。そして、nullptrをした場合は「同じスケルトンアセットを共有するキャラクター間で行うリターゲット」 が走ります。つまり、アセットの複製処理が走ることなくAnimation Sequenceに紐づくスケルトンの変更処理が行われます。

AnimationPreviewerUtilEd.cpp
void UAnimationPreviewerUtilEd::RetargetAnimations(USkeleton* NewSkeleton, const TArray< UAnimSequence*> AssetsToRetarget, bool bDuplicateAsset, bool bRemapReferencedAssets, bool bAllowRemapToExisting, bool bConvertSpaces)
{
	if (!NewSkeleton || AssetsToRetarget.Num() == 0)
	{
		return ;
	}

	TArray<TWeakObjectPtr<UObject>> ObjectToRetarget;
	for (UAnimSequence* AnimSequence : AssetsToRetarget)
	{
		ObjectToRetarget.Empty();
		ObjectToRetarget.Add(AnimSequence);

		if (bDuplicateAsset)
		{
			EditorAnimUtils::FNameDuplicationRule NameDuplicateRule;
			EditorAnimUtils::RetargetAnimations(AnimSequence->GetSkeleton(), NewSkeleton, ObjectToRetarget, bRemapReferencedAssets, &NameDuplicateRule, bConvertSpaces);
		}
		else 
		{
			EditorAnimUtils::RetargetAnimations(AnimSequence->GetSkeleton(), NewSkeleton, ObjectToRetarget, bRemapReferencedAssets, nullptr, bConvertSpaces);
		}
	}
};

そのため、公開しているサンプルでは上記のように実装しています(…あまりテストせずに勢いで書いたコードなのでご注意くださいまし)。

このようにやってることは単純なのですが、僕のようなマーケットプレイスガチ勢にとっては結構便利なエディタ拡張かと思います。是非是非お試しあれ。

おまけ:Skeletal Meshのスケルトン変更について

image.png
Animation SequenceではなくSkeletal Meshに対してのスケルトン変更処理は右クリックメニューの「Assign Skeleton」から実行可能です。
image.png
変更対象のスケルトンと現在のスケルトンアセットにおける各ボーン名の比較を表示してくれますし…
image.png
ボーン構成が一部異なる場合はスケルトンのマージ処理を行ってくれます。いくつか注意点はありますので、以下の資料を事前に確認することをオススメします!
https://www.slideshare.net/EpicGamesJapan/cedec2018-ue4-111104578/103

おしまい

17
12
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
17
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?