Let's Enjoy Unreal Engine

Unreal Engineを使って遊んでみましょう

UE4 ブループリントとC++のバランスを深く考える

最近仕事柄UE4でのブループリントとC++のバランスをどうしていくべきかを考えることが多くなってきました。今回はそのことについてもう少し深く掘り下げていきたいと思います。

まず前提としてPCゲームを作る際にはそこまで深く考える必要はありません。PCゲームはほとんどの場合、高性能なCPUが搭載されており、メモリーも8GB以上の環境であることがほとんどです。そのような状況でブループリントとC++がどうとかというのは好みの問題になってくるでしょう。

おさらいとして、ヒストリアさんの以下の記事と自分が以前に書いたUE4のブループリントの記事を紹介しておきます。

[UE4] C++ or Blueprint?|株式会社ヒストリア

UE4 比較的大規模におけるブループリントの運用 - Let's Enjoy Unreal Engine


基本的な考え方はこの時から変わりません。ここから更に一歩踏み込んだ内容の記事がUE4の公式ドキュメントに追加されました。※現在英語のみ

Balancing Blueprint and C++


この辺りの内容を参考にもう少し細かく突っ込んでいきましょう。まず公式ドキュメントでも書かれていますが、ゲームの設計に「正しい答えはない」というのが結論です。ただ、よりよくするための手段はあります。


f:id:alwei:20180818182553p:plain


メリット

メリットについて公式ドキュメントからそれぞれ抜粋します。

C++クラスのメリット

・ランタイムパフォーマンスの向上
・明示的なデザインが可能
・広範なAPIへのアクセス
・多くのデータコントロール
・厳密なネットワークレプリケーション
・より良い数学計算
・差分/マージの容易性


などが挙げられています。

ブループリントクラスのメリット

・高速なクリエイション
・高速なイテレーション
・視覚化されるフロー
・フレキシブルな編集
・簡単なデータの扱い


非常に明確でわかりやすいメリットです。これらを意識した上で次に進んでみましょう。

ロジックとデータ

大規模なゲームを制作するためには、データドリブンという考え方が大事になってきます。ゲームというのは大まかに分けると"ロジック"と"データ"に分けられます。ロジックを表現する時は多くの場合、コードを使うことが多いです。ただし、UE4ではブループリントでもロジックを記述することができます。

データはC++コードでも表現可能ですが、一般的にコード上にデータをベタ書きすることをハードコードと呼び、外部から触ることが不可能になるため、推奨されません。対してブループリントはロジックとデータと同時に扱いつつ、外部からも編集しやすい作りになっています。このことからゲームデザイナーやアーティストからすればブループリントは非常に都合の良い存在となります。

しかしブループリントの変数やプロパティはC++から直接参照することは困難です。そのためにUE4ではC++上で直接データを扱わずに、C++クラスを継承したブループリント内でデータをセットする方式が推奨されています。C++からデータを読み込みたい場合、今のUE4には"Asset Manager"という仕組みがあり、エディター上で定義されたゲームデータアセットから読み込むという方式が推奨されています。この方が非同期読み込みでの対応や必要なアセットを逐一読み込むことができるからです。

Asset Managerについては以下のドキュメントを参考に。※英語

Asset Management


以下も参考になります。

UE4 アセットマネージメントフレームワークについて - Let's Enjoy Unreal Engine

【UE4】AssetManagerを使用したレベルストリームの高速化 | 株式会社アンナプルナ


C++で書く時にはロジックとデータの分離の仕方をしっかりと考えましょう。そうでなければプログラマーが全てのデータを管理するハメになり、デザイナーやアーティストが上手くゲームをコントロールできなくなってしまいます。

パフォーマンス

一般的にブループリントが問題になるのはこのパフォーマンスの部分です。ただしこれはPCゲームではなく、コンソールゲームやモバイルゲームの場合です。PCゲームは高速なCPUやGPU、メモリーが載っていることが多いため、そこまで気にする必要はありません。

「パフォーマンスが問題になるのなら始めからC++で書けばいいのでは?」と、こういう結論になりやすいですが、これは非常に危険です。全員が全員、UE4C++に詳しければ問題がないかもしれませんが、一般的にC++は非常に危険性が高いプログラム言語とされています。ネイティブにアクセスできる分、どんなことでも出来てしまいますが、アプリケーションをクラッシュさせることも容易です。また、多くのルールを理解しなくては上手く使いこなすことはできません。

パフォーマンスが問題になると言いましたが、実際のところブループリント自体はそこまで遅いわけではありません。ブループリントのノードはほとんどの場合C++で直接記述されており、その場合においてはC++コードを呼び出した時とほとんど速度の差はありません。

しかし例えばブループリントから"ForEachLoop"を使う時、これは場合によっては相当ボトルネックになる可能性があります。

f:id:alwei:20180818192035p:plain


このケースの場合、配列要素に対して直接関数を呼びだすことで早くなる可能性があります。

unrealengine.hatenablog.com


またPure関数の場合には更に顕著となり、これはかなりのボトルネックになります。以下の記事のように一度変数にキャッシュするか、専用にキャッシュするマクロを作ってしまうのもありです。

unwitherer.blogspot.com


このように積もり積もって、ブループリントが重いという印象を持たれるケースがあるようです。

またブループリントはTickが多くなれば多くなるほど、遅くなってくるという傾向があります。可能な限りTickをオフにします。

f:id:alwei:20180818193038p:plain


"Start With Tick Enabled"をオフにしていれば、Tick関数が呼び出されなくなります。これはコンポーネントにおいても同様です。デフォルトではオフにしておく方が良いでしょう。処理が重たくなってきたら"Tick Interval(secs)"の値をゼロ以外に設定するのも非常に効果が高いです。

Tickなしにどうやってゲームを作るの?と思われるかもしれませんが、UE4はイベントドリブン(イベントが発生してから処理を開始する考え方)による仕組みが非常に充実しており、Tickがなくても汎用的な仕組みは十分に作ることができます。特にブループリントはイベントドリブンで作りやすいように多くの機能が用意されています。イベントドリブンでしっかりと制作すれば、C++を使っている時と比較してもそこまで大きな速度差は発生しないはずです。

ここまでやってみて。まだブループリントが重い!!ということがあるかもしれません。そういう時はプロファイラーを利用します。

プロファイラ ツール リファレンス


重い場合、まずはどこが重いのかをしっかりと検証しましょう。プロファイラーを使えばどこが重たいのかがわかるはずです。そして重点的に重いと思われる部分を探し、ボトルネックを見つけた時にC++へとコードを変換するようにしましょう。可能であればNativizationツールを利用します。

ブループリントのネイティブ化


ほとんどの場合はこれでC++コードへ変換可能ですが、問題が発生することもあります。手動で修正可能なものであればいいですが、問題範囲が大きければそのままロジックを一部C++側で書いてしまうという方法もあるでしょう。これでパフォーマンスのボトルネックを解消します。

設計的な注意点

以下も公式から抜粋した内容です。そのまま翻訳したものではありません。

高価なブループリントキャストを避ける

BP_BというブループリントからBP_Aという様々アセットを参照するブループリントがあった場合、BP_BからBP_Aへのキャストは避けましょう。複雑な参照を持つことになり、BP_Bを読み込むだけで、BP_Aの参照する情報も全て読み込む必要性が出てきます。これはC++で定義したネイティブベースクラスか最小限のブループリントベースクラスを作成しておくことで、キャスト時のコストを避けることが可能です。

ブループリントの循環参照を避ける

循環参照とは名前の通りブループリントが別のブループリントを参照する際に、お互いがお互いを参照し合ってループしている状態を言います。上記のキャストを繰り返していると発生しやすいです。これは最悪、ブループリント内の情報を破壊する可能性もあり、非常に危険です。この問題も上記の"高価なブループリントキャストを避ける"と同様の対策が可能です。

C++クラスからアセット参照を避ける

FObjectFinderとFClassFinderを使用してC++コンストラクターからアセットを参照することは可能ですが、可能な場合は避ける必要があります。この方法で参照されるアセットはプロジェクトの起動時にロードされるため、参照が実際には必要ない場合は読み込み時間とメモリの問題が発生します。対策として、既に紹介している、Asset Managerの仕組みを使うか、設定ファイルを使って読み込むことで対策が可能です。

文字列によるアセット参照を避ける

C++上で文字列を使ってLoadObjectのような関数を使って手動でロードが可能ですが、これらの参照はクッカーによってトラッキングできないので、パッケージゲームで問題が発生する可能性があります。代わりにFSoftObjectPathもしくはTSoftObjectPtrな弱参照を使用し、iniまたはブループリントからそれらを設定して、オンデマンドに、または非同期にロードさせる必要があります。

ユーザー定義の構造体(Struct)と列挙型(Enum)に注意

C++で定義されている構造体と列挙型はC++とブループリント両方で利用できますが、ユーザー定義(ブループリント上で)の構造体と列挙型はC++では使用できません。もしC++で参照が必要な構造体、列挙型であれば、早いうちにC++で実装することをお勧めします。

ネットワークアーキテクチャを考える

ネットワークアーキテクチャはクラス設計に大きく影響する可能性があるので、早いうちから念頭において設計する必要があります。レプリケートされたデータの適切なフローを作成するためにイテレーションが難しくなるような意思決定が必要なるかもしれません。

非同期読み込みを考える

ゲームが大きくなると、ゲームに表示されるものを全てロードするのはでなく、必要に応じてアセットをロードする必要があります。このためにはハードリファレンスの代わりにソフトリファレンス、またはプライマリーアセットIDを使用するようにします。そしてAssetManagerを使い、非同期にロードを行うようにします。C++で低レベルな制御を行うSteamableManagerも利用することができます。

UE4 Visual StudioとUE4.20までの対応状況について

UE4C++を使うためにはVisual Studioのインストールが必須ですが、UE4Visual Studioもバージョンが増えたために厄介な仕様になりつつあります。

一旦このUE4.20での段階で、どのUE4がどのVisual Studioのバージョンに対応しているのかをまとめておきます。

以下は公式ドキュメントによる情報です。※最新版は現在英語になります

Setting Up Visual Studio for UE4

続きを読む

UE4 新しいポリゴンモデリング機能(メッシュエディター)を使ってみる

UE4.20 Preview 1がリリースされてからしばらく経ちました。

4.20でもかなり沢山の追加機能が増えており、検証するだけでも相当時間がかかりそうです。

個人的に去年のGDCで発表以来、かなり昔から気になっていた、ポリゴンモデリング(メッシュエディター)機能が遂に本家の方に実装されるようで、簡単な検証を行ないました。

しかしまだ実験的機能の中でも、かなり特殊な扱いらしく起動方法自体がかなり珍しい方法となっているので注意しましょう。

続きを読む

UE4 ポストプロセスによるセルシェーダーを公開しました

UE4用のポストプロセスによるセルシェーダーをGitHub上で公開しました。

github.com

このポストプロセスによるセルシェーダーは個別で調整可能なものと比較して、誰でもすぐに導入可能という点が最大の魅力です。

個別で調整可能なセルシェーダーは柔軟ですが、非常に調整が細かくなってしまい、お手軽さにはどうしても欠けてしまいます。ポストプロセスによる実装も制限はついてしまいますが、非常に簡単に使えてしまうというところで大きなメリットがあります。



GitHub上でも解説していますが、主な特徴として…

セルシェーディングに特化(セルルックらしさを追求)
2.余計な機能はほぼ持たない
3.柔軟な4種類のアウトライン描画
4.UE4標準のライトだけで調整可能(カラーもしっかり反映)
5.シャドウカラーやハイライトカラーの指定
6.Unlitマテリアルと遠距離メッシュは自動的にセルシェーダーから除外
7.Custom Depthで対象メッシュのみにセルシェーダーを適用するスイッチ
8.オプションとしてディフュージョンフィルターシェーダー


うまく利用すれば大抵の場面ではなんとかなるように作られています。あくまでもトゥーンシェーダーというよりもセルっぽいルックを作ることに特化しています。

何かいいものが出来た時にはぜひツイッターSNSなどで公開してみてください!

UE4 Oculus GoでVRアプリの開発を開始するまでの方法

今月の5月2日、Facebookのカンファレンスイベント、F8にて突然発表されてその場で購入可能となったOculus Goですが、なんとその2日後に海外から輸入されて、手元にきました!

あまりに早く届いたので、テンションが高いです。

Oculus Goはお値段も安く、スタンドアローンで起動するので本当に快適です。発送も早いのでぜひこの機会にどうぞ。

www.oculus.com


さて、UE4でOculus Goアプリを開発するためには基本的にGear VRと同様の方法を使えば可能なのですが、微妙に詰まるところがありましたので、そこを解説します。

続きを読む

UE4 シーケンサー上の物理演算をアニメーションベイクする

UE4シーケンサーでは様々なアクターを動かすことが可能ですが、そこで計算された物理演算をそのままシーケンサー上に録画される機能があることは意外と知られていません。

これを上手く使うと、物理演算の結果を完全にベイク(焼き付けてしまうこと)が可能で、例えば映像向けにカットを作りたい場合には毎回同じ結果を再生することができます。スタティックメッシュはもちろん、スケルタルメッシュでの物理演算もベイクできます!

今回はUE4.19.1を使っていますが、それ以前のシーケンスレコーダーという機能が搭載されているUE4のバージョンであれば基本的に同じことが可能なはずです。

物理演算を行うアクターを用意する

まず始めに物理演算を行うアクターを用意しておきます。今回は適当なキューブを用意し、"Simulate Physics"にチェックをつけておきます。

f:id:alwei:20180424222555p:plain


ここに"Radial Force Actor"を配置して、放射上に力を発生させるようにして、キューブをふっ飛ばします。"Impulse Strength"はかなり大きめに設定。

f:id:alwei:20180424222833p:plain

これでアクターの準備は完了しました。

シーケンサーを作成し、イベントを発生させる

ここでひとつレベルシーケンサーを作成し、イベントトラックを作成します。

f:id:alwei:20180424223050p:plain


イベントトラック内にキーをひとつ作成し、プロパティの"Event Name"をしっかりとつけておきます。

f:id:alwei:20180424223150p:plain


あとはレベルブループリント内に同様の名前の"カスタムイベント"を作成し、RadialForceAcotorのFire Impulseを呼び出すようにします。

ここで、ツールバー上で"プレイ"を"シミュレート"に切り替えてから再度"プレイ"を選択します。

f:id:alwei:20180424223441p:plain


この状態でシーケンサーの再生を開始します。

f:id:alwei:20180424223545p:plain

物理演算が動作していることが確認できました。

シーケンスレコーダーで録画する

メインメニューバーから"ウィンドウ"→"シーケンスレコーダー"を選択し、開きます。そしてアニメーションを録画したいアクターを全て選択し、"追加"のボタンを押すと、シーケンスレコーダー内にアクターが追加されます。

f:id:alwei:20180424223936p:plain


あとは"録画"ボタンを選択し、シーケンサーを再生します。再生が終わったら終了ボタンを押しましょう。

f:id:alwei:20180424224152p:plain


無事に終了すると録画されたシーケンサーが作成されています。スタティックメッシュの場合はシーケンサーのみですが、スケルタルメッシュの場合には別途アニメーションシーケンスも作成されます。

このシーケンサーを開き、再生すると…

f:id:alwei:20180424224348p:plain


全ての物理演算結果がベイクされたアニメーションが再生されます!ベイクされているので、何度やっても当然同じ結果になります!


動画で確認するとよりわかりやすいです。

UE4 GDC2018 フォートナイトの最適化について Part2

前回フォートナイトの最適化について記事を書きましたが今回はそのPart2です。前回の記事は以下から。

unrealengine.hatenablog.com

※英語の翻訳には自信がありませんので、それなりにミスがあると思って読んでください。大きなミスがあれば指摘していただけると嬉しいです。

Part2の動画は以下にあります。

Optimizing UE4 for Fortnite: Battle Royale - Part 2
www.youtube.com

続きを読む