未来を創る、テックコミュニティー

代表技術通信~Unreal Engineで点群表示③ まずはUE4のチュートリアル(3)

草場代表
2020/10/21

引き続き、Unreal Engineのチュートリアルで遊んでいます。

今回はリアルタイムレンダリングの基礎です。難しかった。。。

リアルタイムレンダリングの基礎

基礎編を受けるにあたりの心構え。

リアルタイムレンダリングの裏側

背後で何が起こっているかの説明です。大きく5つです。
①異なるソリューションの組み合わせ
②スケーラビリティ
③ディファードレンダリングやフォワードレンダリングの意味
④Gbufferという用語の意味とレンダリングへの作用について
⑤頂点とピクセルシェーダーの基本について

①異なるソリューションの組み合わせ

リアルタイムレンダリングは二つの部分に分かれます。
1つは事前計算、もう一つは実際のリアルタイムレンダリングです。
オクルージョンシステムがいい例です。オクルージョンとは表示するものと表示されないものを決めることです。つまりフレームで何をレンダリングして、何をレンダリングしないかを決めることです。壁の背後にあればレンダリングは不要なので、オクルージョンされます。だいたい、オクルージョンプロセスは3段階か4段階のプロセスです。オクルージョンプロセスの手順の一つが事前計算で、そのほかの処理手順はリアルタイムに実行されます。4つのソリューションがあるのは、表示するものと表示されないものを計算するのが相当複雑な内容だからです。

②スケーラビリティ

リアルタイムレンダリングの特徴として、基本的にはレンダリングの質がいつでも変更可能で、また変更する必要があるので、実行中にスケーリングして高速・低速で実行したり、高品質の代わりに低速で実行したりできます。
品質や処理負荷のスケーリングが可能です。これがスケーラビリティです。
コンテンツ自体をスケーリングすることで、様々なデバイス上で実行可能になります。例えばモバイルデバイスで実行させることも、PCで実行することも、コンテンツのスケーリングの上げ下げが可能です。
スケーラビリティ機能はエンジンとツール内で必須です。例えば、[r.]コマンドが利用できます。パフォーマンスの良さがアプリケーションのリアルタイムレンダリングにとって重要です。
[r.]コマンドの制御とスケーラビリティシステムの一部である自動設定が大切です。

[r.]コマンドについて。ここからDemoに入るが、再現できず断念しました。

③ディファードレンダリングやフォワードレンダリングの意味

レンダリングには二つの方法があります。ディファードレンダリングとフォワードレンダリングです。これはUnreal Engineのみのはなしでなく、一般的な話です。Unreal Engineではデフォルトでディファードレンダリングですが、設定すればフォワードレンダリングも可能です。
めちゃ単純化すると、
ディファードレンダリングでは高付加なアプリケーションで比較的安定してパフォーマンスも良好、
フォワードレンダリングは比較的単純な使用またはハードウェアの制約が大きい場合、比較的拘束になる。
VRアプリケーションではフォワードレンダリングが使用されているらしいです。ディファードレンダリングが弱い部分は、アンチエイリアシングです。
ディファードレンダリングではテンポアンチエイリアシング(TTA)のみとなります。TTAでは表示されるフレームに若干のゴーストが発生します。これはリアルタイムレンダラに共通している課題。

④GBuffer

ディファードレンダラではGBufferが使用されてます。フォワードでは使われていない(実は組み合わせ可能)。
GBufferは基本的にはフレームごとの画像のセットです。これらの画像にはレンダリングプロセスの後工程で必要になるすべての情報が含まれています。そしてリアルタイムに合成が行われることになります。
画像の様々なバージョンをレンダリングしてGBufferでグループ化し、それらの様々なバージョンを使用できるようになります。その先のレンダリングプロセスで必要になる情報をこれらの画像を使用して計算させることができます。
例えば、フォグをシーンに適用するには環境の深度を計算する必要があるので、前もってGBufferのパスで深度を取得しておきます。この処理は完全にバックグラウンドでおこなわれるので、通常の作業には影響がありません。

ここからデモ。再現できず、断念。

⑤頂点とシェーダーについて

レンダリング中は非常に簡単な計算を何度も膨大な回数繰り返すため、プロセッサの処理が遅くなります。CPUはそのような処理に向いていません。そこで、シェーダーを作ります。基本的に各種シェーダーはGPUハードウェアの特定の箇所で何度も細かい計算を実行します。
シェーダーはリアルタイムレンダリングの中核をなすものなので、レンダリング手法とパフォーマンス低下に重要な影響があります。

ここでデモ。再現できず、断念。

ピクセルシェーダーはピクセルごとで、頂点シェーダーは頂点ごとです。すべてのリアルタイムライティングやシェーディングおよびマテリアルや霧や後処理のエフェクトやそのた数多くのレンダリングはすべてピクセルシェーダーで、レンダリングパイプラインの中核をなしています。

リアルタイムレンダリングのパフォーマンス

リアルタイムレンダリングを初めて使う場合、ターゲットフレームレートを設定するという考え方になじみがないかもしれないです。コンテンツの実行に必要なフレームレートを決定して実行する内容や機能の有効化や無効化、使用するレンダリング品質などすべてを、そのフレームレートに到達して維持できるように設定します。
一般的なフレームレートは30FPSまたは60FPSです。msも使われます。ミリセカンドです。。この単位はFPSより頻繁に使われます。パフォーマンスおよびレンダリングの実行環境ではFPSでなくmsで測ることが多いです。
例えば、30FPSは、1秒が1000ミリ秒なので、1000÷30で、33.3ミリ秒/フレーム。これが一つの画像をレンダリングするためのコストになります。コストが大きければ大きいほど、フレームレートは小さくなります。ミリ秒の数値が小さければ小さいほど、高品質です。
エディターでの計測方法も指定できます。

ここからデモ。今回は自分で適当なオブジェクトを配置してみました。
エディターに移動します。コマンドラインいじれるよう、Output Logを開きます。
↓手順1: Output Log(出力ログ)ウィンドウを表示する。

めちゃわかりづらいが、Output Logの一番下にCmdという文字を打ち込めるコマンドあります。例えば、stat fpsでフレームレートが表示されます。ビューポートの右上に。

もしくはビューポートのメニューにある矢印からFPSを表示でもOK。

フレームレートはFPSとmsの両方表示されますさらに、環境構築する際に、t.maxfps 600か、それよりも大きな値を入れると、フレームレートの制限がなくなります。画面でもともと60FPSだったのが180FPSとかになってます。

パフォーマンスを評価する際は、フレームレートを無制限にしたほうが良いです。何らかの処理を適用したことによりFPSが変化したかどうかがわかるため。
もう一つのコマンド、stat unitとコマンドに入れると、さらに数値が追加されます。Frame, Game, Draw, GPUです。

Frameがすべての基本です。stat fpsと同じ。
GameとGPUは重要。
Drawは少し特殊なのでここでは扱わない。

レンダリングは部分的にGPUで処理されます。GameはCPUを表します。レンダリグンはCPUとGPUで分業されます。
CPUはもっぱら環境とアプリケーション内の物体の位置、回転、変形に関すること全般を処理します。アニメーションや物理、コリジョン、AI、ランタイム時の物体のスポーンや実行中の破棄などを計算します。
GPUは基本的に実際のレンダリングつまりライティングやモデル事態のレンダリング、反射やシェーダーなどの処理をします。
リアルタイムレンダリングのパフォーマンスを理解するにはこの二つが協調動作する仕組みを理解することが不可欠です。
例えばフレームレートが低く、よろパフォーマンスが欲しい場合は、まずボトルネックがCPUなのかGPUなのかを突き止める必要があります。二つのうち遅いほうがパフォーマンスを決定するということ。

次はプロファイリングの基礎についてです。
先ほどのstat unilで表示されているものに記載されています。statコマンドを少し説明しいます。stat rhiというコマンドで、以下の追加情報と数値が追加されます。

統計情報を無効にしたければ、再度同じコマンド打ちます。stat rhiと打てばOK。
stat scenerenderingと打ち込むと以下。ステップごとの消費コストを表示しています。

例えば、ライティングの描画(Lighting Drawing)は、0.2ミリ秒消費しています。
他にも統計情報あります。ビューポートの▽を押して、ビューポートオプション>統計データ>Advanceから様々選べます。

次は、よく発生するパフォーマンスの問題4つについて。これらの4つすべてがパフォーマンスを非常に重くします。

(1)ドローコール
(2)Pixel/Vertex Shaderインパクト。
(3)Translucency rendering。透過処理。非常に高負荷。
(4)動的シャドウ

(3)Translucency rendering。透過処理。非常に高負荷。

とりあえず半透明マテリアルを作ります。Unreal Engine公式の、透過性を使用するを参照しました。

適当に半透明を作りました。数をどんどん増やしてグループ化すると、FPS落ちました。しかし、デモでは違うことしています。
デモでは、透過的な平面のパーティクルが用意されています。どれか選んで詳細タブを見ると、インスタンスパラメタという名のセクションがあります。展開すると最初のエントリは0で、そこにScalarがあるので、Scalar値を50とかに増やします。これがスポーンするパーティクルの数になります。そうすると平面の数が増えるので、カメラの中央に入っていくとFPSの値が下がります。

(2)Pixel/Vertex Shaderインパクト

距離の影響も受けます。ピクセルシェーダーのせいです。ビューポートのLit(たぶんライティングあり、のやつ)にいって、シェーダーの複雑度を選択すると以下の画面がでます。炎の部分がExtremlyバッドらしいです。

半透明部分をレンダリングする手間を減らせば、計算しなければならないピクセル数が減るので、距離をとるとFPS上がります。
マテリアルも距離を近づけると、マテリアルの複雑度に応じて、FPS落ちます。

(1)ドローコール

ここでドローコールです。うむ、わからん。
レンダリングで何が起きているかを見る方法が提示されています。順番に読み込まれます。これがドローコールです。環境のポリゴン数でなく、存在するドローコール数です。環境を形成している別個のモデルの数です。
そのため、例えば多数の小さい像を並べまくった場合、フレームレートが落ちます。ドローコール数が増えたからです。
stat rhiでドローコール数わかります。ポリゴン数とドローPrimitiveコール数です。
像が少なくても、一つ一つの像がカラフルであればドローコール数は増えます。無茶苦茶増えます。ポリゴン数はあまりクリティカルではない???
ドローコールごとにレンダリングされます。

(4)動的シャドウ

動的シャドウはとてもヘビーです。ライトでなく、シャドウが重いのです。ポリゴン数が多くなるとシャドウが増えるので、注意が必要です。静的シャドウを使うならポリゴン数増やしてOKです。

リアルタイムレンダリングの基礎まとめ

難しかった。

この記事を書いた人
草場代表
エディター