LoginSignup
1
2

More than 1 year has passed since last update.

UnrealEngine アニメーション設計② UE5のLyraStarterGameのAnimationシステムを見てみよう

Posted at

はじめに

1回目ではC++のクラス設計についてお話しました。
そこで、処理負荷が高くなってしまうためAnimBPのイベントグラフは使わずC++で書くと言いましたが、
EpicのサンプルであるLyraStarterGameではどうしているか見てみようと思います。

Tour#1 ABP_Mannequin_Baseのイベントグラフ

これがLyraStarterGameのベースとなるAnimBPです。
image.png

イベントグラフを見てみましょう
image.png

要約すると

イベントグラフはパフォーマンスのボトルネックになるためUE5で新しく追加された
BlueprintThreadsafeUpdateAnimation関数に処理を書きました。これは並列実行されます。

Lyraでもイベントグラフは空でした。でも、C++化するのではなくBPを並列実行できるようにして対策したようです。
BlueprintThreadsafeUpdateAnimation関数を見てみましょう

Tour#2 BlueprintThreadsafeUpdateAnimation関数

image.png

要約すると

この関数はアニメーションを選択するために必要なゲームデータを収集しています。
しかし、スレッドセーフ関数はゲームオブチェクとを直接参照することはできません。
代わりにProperty Access systemを使ってデータにアクセスします。

この関数は並列実行されるため、ワーカースレッド上で実行されます。1回目でお話したマルチスレッドの注意点がここでも言及されていますね。

PropertyAccessSystemが自動的にパラメータをコピーしてくれるみたいです。

PropertyAccessSystemとは?

右クリックから"PropertyAccess"と検索すると出てきます。
image.png

作るとこんな感じ
image.png

「バインド」をクリックして関数又はプロパティを選択します。
image.png

ここでバインドした値をGameThreadで事前にコピーしておいてくれるという仕組みのようです。
独自の関数をリストに追加するにはUAnimInstanceを継承したクラスにUFUNCTIONでBPに公開するするだけでよい。

	UFUNCTION(BlueprintPure)
	ALyraCharacter* GetLyraCharacter() const { return nullptr; }

image.png

コピーのタイミングも選択できます。
image.png

自動とスレッドセーフって何でしょう?ドキュメントが無くてわからん!
エンジンの中身を調べるしかなさそうなので調べてみましょう。

Enumの定義はこれみたいです

UENUM()
enum class EAnimPropertyAccessCallSite
{
	// Access is made on a worker thread in the anim graph or in a BP function
	WorkerThread_Unbatched UMETA(DisplayName="Thread Safe"),

	// Access is made on a worker thread before BlueprintThreadSafeUpdateAnimation is run
	WorkerThread_Batched_PreEventGraph UMETA(DisplayName="Pre-Thread Safe Update Animation"),

	// Access is made on a worker thread after BlueprintThreadSafeUpdateAnimation is run
	WorkerThread_Batched_PostEventGraph UMETA(DisplayName="Post-Thread Safe Update Animation"),
	
	// Access is made on the game thread before the event graph (and NativeUpdateAnimation) is run
	GameThread_Batched_PreEventGraph UMETA(DisplayName="Pre-Event Graph"),

	// Access is made on the game thread after the event graph (and NativeUpdateAnimation) is run
	GameThread_Batched_PostEventGraph UMETA(DisplayName="Post-Event Graph"),
};

「スレッドセーフ」は何もしない直接参照みたいですね。

「自動」はコピー元と先が両方スレッドセーフの場合は何もしない「スレッドセーフ」、
そうじゃない場合はゲームスレッドで事前にコピーされる「ゲームスレッド(プリイベントグラフ)」
になるっぽいですね。

		if(InContext.ContextId == ContextId_Automatic)
		{
			if(InContext.bSourceThreadSafe && InContext.bDestThreadSafe)
			{
				// Can only be in the worker thread batch if both endpoints are thread-safe
				return (int32)EAnimPropertyAccessCallSite::WorkerThread_Unbatched;
			}
			else
			{
				return (int32)EAnimPropertyAccessCallSite::GameThread_Batched_PreEventGraph;
			}
		}

IKとかどうやってるの?

IKするためには足の下の地面の高さを取得する必要があります。ワーカースレッドのBPからレイキャストってできなかった気がするけど、どうやってるのか調べてみました。

ABP_Mannequin_BaseのコントロールリグでCR_Mannequin_FootPlantが登録されていて
そこでTraceされてました。ControlRigの処理負荷ってどんなもんなんでしょうね。足のIKくらいだったら自前で処理書いたほうが早い気がするのですが今度UE5のIKRigとか調べてみたいです。
image.png
image.png
image.png

UE4やC++でも並列処理にすることはできる

FAnimInstanceProxy::Updateをオーバーライドしてそこに処理を書けばc++でも並列処理にすることはできます。
ただ、C++の処理がそこまで重たくないのであれば並列処理する必要はないと思います。
実際に自分がやっているプロジェクトではほとんど変わらず、あまり意味がなかったので元に戻しました。

まとめ

  • Blueprintが好きな方はLyraのやり方が良いでしょう。
    BPの処理はワーカースレッドで行われるため処理負荷を気にする必要なさそうです。

  • C++が好きな方はアニメーション設計①で説明したやり方が良いでしょう。
    C++で書けば処理負荷は十分軽いのでゲームスレッドで処理しても問題ないでしょう。
    そのほうがスレッドセーフじゃない関数も使えて便利です。


UnrealEngine アニメーション設計① スレッドセーフなクラス設計

1
2
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
1
2