1 of 105

ゲーム開発におけるグラフィックス最適化セミナー

登壇者��Winter Crown Works�梶井 祐

株式会社 アル・シェア�声優 本多 早雲

声優 金村 明日香�声優  篠田 有香�株式会社 ワルキューレ� 声優 脇本 和恵

2 of 105

前半の部

  • 検証は【必ず】最初に行おう
  • クオリティを維持したままで最適化をするために
  • 頂点処理とピクセル処理
  • Wavefront は効率よく回そう
  • 無駄なピクセルの重複書き込み
  • 丁寧にデータを作る意義

3 of 105

はじめに

  • パフォーマンスを良くするって「結局クオリティ下げるんでしょ?」って思った事はありせんか?�
  • 「プログラマーの仕事だよね」って思った事はありませんか?�
  • パフォーマンスなんて「最後の行程でしょ?」って思った事はありませんか?

4 of 105

本当に?

  • 本当にクオリティを下げたら【パフォーマンスが良くなったと】本当に言えるのでしょうか?�
  • プログラマーだけで頑張れば解決するのでしょうか?�
  • 最後にやることは本当に効率が良いのでしょうか?

5 of 105

答えは?

  • NO!!

6 of 105

なんで?

  • 現在のGPUは速度が速くなった分、複雑な形状、複雑計算の表現、複数の処理にまたがった処理などがあり、パフォーマンスの低下はケース・バイ・ケースになるからです。�
  • そのため、【プログラマーだけで完結しない】し、【クオリティを下げた上で高速にならない事もある】し、【最後の行程にやったんでは修正箇所が多すぎて修正仕切れない】のです。

7 of 105

今日のスライドでは

  • 検証を行う大切さ�
  • 無駄なものとそうでないもの�
  • 最適化の意義�       この辺りをお伝えできればと思います。

8 of 105

検証は最初に行おう

  • 最初からクオリティに問題なく、軽いデータが作れるなら、パフォーマンスのための修正を最小限に抑えられる。フォーマット化してアセット発注できるので効率的。�
  • パフォーマンス的なリソースにバッファを設ける事で、本当に欲しい処理にリソースを割ける可能性を残せる。�
  • 上記の事から結果的に予算のリソースも無駄が減る。

9 of 105

絶対に最初に行おう!

  • 検証を行うのは早ければ早いほど、ノウハウを活かす期間が長いという事。�最初の方が恩恵が多いです。�
  • ゲームはチームでリソースをシェアしています。正しい配分にするためにも検証を。�
  • アンリアルにはパフォーマンスを検証する機能が沢山備わっている。�そして使い方は簡単です。�

10 of 105

じゃあ、どうすればいい?

  • いろんなパターンのデータを作成し、プロファイリングを取る。�そうすることで本当に重い処理が見えてきます。
  • 重い部分はここだ】という裏を取る事で、少ない手順で最適化。�クオリティが下がってパフォーマンスがあがらないような対応をれないためにもプロファイルを取る事が重要です。

11 of 105

アンリアルでは簡単にプロファイルが取れます。

  • Profile GPUというコンソールコマンドで大まかな負荷が計れます。�った結果と、測る時の画面から読み取れる事は多いです。�
  • リアルタイムに計測できる【統計データ】→【Advance】→【GPU】も便利です。�
  • Optimization ViewmodesもOverDrawやピクセル単位の負荷を早期に発見するのに有効です。

12 of 105

例えばこの画面

13 of 105

ProfileGPUを使った場合

14 of 105

統計データで見た場合(リアルタイムに見れます)

15 of 105

こんな情報が得られます。

  • PostProcess = フィルタ関連
  • Lights = 影ありライト、影なしライト、ライトブローブ
  • BasePass = GBufferへの書き込み。アルベド、メタリック、エミッシブ等
  • ShadowDepth = 影用の深度情報書き込み
  • ParticleSort_32= GPU Particleのソート
  • RefrectionEnvironment ComputeShader=静的な反射マップの処理
  • BeginOcclusionTests=Occlusion Querieで統計情報作成
  • RenderVelocities=速度ベクトル書き込み。モーションブラーが有効だと書き込まれる。
  • ParticleSimulation=GPUパーティクルの更新
  • PrePass DDM_AllOpaque=Early Zパス

16 of 105

よくある勘違い

  • 半透明増やして処理落ち → そもそも前段階で処理落ち寸前だったかも知れない�
  • ポリゴン数が多いオブジェクトが画面に入ってる → ポリゴン数多いけどピクセルのほとんどはカリングされているかも知れない。�
  • スクリーンで見えてないものは負荷じゃない → 一番手前のポリゴンが上から書いてるだけで奥で一回書かれてるかも知れない

17 of 105

よくある勘違い2

  • DrawCall減らせばいいんでしょ?→DrawCallはCPU負荷です。GPU負荷が表向き下がる事がありますが、それはCPU負荷が高すぎてGPUを引っ張ってしまった時です。�
  • ポリゴン数をもっと減らさなきゃ → テクスチャが多いのかも知れないし、巨大なテクスチャのせいかも知れない、そもそもシェーダーのノードがおかしな組み方されているかも知れないし、本当にポリゴン数が問題なのかも知れない。�これは、高精度なアナライザを使うとか、そうでなければ枚数減らしたり、テクスチャの解像度下げたり、シェーダーを単純化したりの検証などして原因の切り分けを行う必要があります。(PS4やXBOXのアナライザは超便利です。機会があれば使ってみましょう。)�

18 of 105

よくある勘違い3

  • パーティクル増やしたら重い。やっぱり半透明のせいだ!→GPUパーティクルのシミュレーション、GPUパーティクルのソートが重い可能性があります。もしかしたら特定のマテリアルだけが重いのかも知れません。�
  • DeferredLightってForwardLightと違ってLightの計算が軽いんでしょ? → 計算は一緒です。手順が違います。同じ体積ライティングする分には負荷はそう変わりません。むしろライトバッファをコンポジットする分DeferredLightの方が重いケースもありえます。�DeferredLightの方が効率がいいのは確かではあります。�

19 of 105

よくある勘違い4

  • テストや検証なんて、大きい会社とかお金持ってるとこがやるんでしょ? �↓ �いいえ!お金を節約して尚クオリティを出したいところがやるべきものです!

20 of 105

そんな数々の理由から負荷は�ケース・バイ・ケース!!�後半に回すほど面倒に

  • そこに至るまでに何も考慮してないのであれば、どれが重くなっていても不思議ではない。�
  • 画面に出している情報も増えているため、最初に比べて切り出しも大変。�
  • 修正対象も多くなり、時間を確保出来なければ単純にクオリティを落とす判断もありえる。(でもクオリティ出せって言われる。世知辛いよね。)�
  • 制作途中で、パフォーマンスを気にしてオミットしてしまった項目もあったのかも知れない。途中でパフォーマンスを確保できていれば導入出来ていたかも知れない項目を・・・。�
  • パフォーマンスが[自分のところで出なくなるかも知れない]という恐怖はスタッフを萎縮させる。�のびのびと発想を叩き込めない原因になる。�逆に気にせず作っていたスタッフはせっかく作った成果物のクオリティを下げさせられて不満を貯めるかも知れない。

21 of 105

だからこそ出来るだけはじめにテストする

  • UE4はテスト環境が作りやすい。�テスト用のレベルはじゃんじゃか作りましょう。�テストするコンセプトを決めて、絞った項目でテストできるようにする。�例えば:ライティング、LOD、ポストプロセスなど、極力小さく絞る。�新規作成して、もの置いてProfileするだけ。惜しむ手間ではない。�
  • とにかく沢山統計を取る。PGとアーティストで連携を取る。�片方だけではなかなか出来ないし、普段から連携するクセをつける意味でも有効。�どれが重いかは必ず裏を取らないと駄目。�闇雲に削るのは速くなったとしてもクオリティ低下が避けられない。�ユーザーやクライアントの事を本当に思うのならば、必ず裏を取る。�
  • 無駄がない状態をデフォルトにする。�無駄なデータが入るのが通常状態だと他の人も真似する。�特にアウトソースでは極力フォーマット化したものを出すようにしないと、2度手間、3度手間になってしまう。�とにかく早くテスト結果をまとめる必要がある。�時間が無い時は、テストの手順を量産効果の高いものから絞って行うのが良い。�プログラマーだけで完結するものもあるし、データのちりつもできてしまうパフォーマンスヒットもある。

22 of 105

調べる例を小芝居で見ていただきます。(検証編)�

23 of 105

小芝居02(検証編2)

24 of 105

小芝居3

25 of 105

リアルタイムProfileは大雑把

  • 統計情報からGPU見ると、大雑把なカテゴリで確認できます。�大雑把な代わりにリアルタイムなので、画面に何が入って重くなってるかなどは若干わかりやすくなります。�有効にしてると、ビジュアライザーさんがずっと囁き続けて教えてくれます。

26 of 105

小芝居4

27 of 105

まとめ

  • UE4に実装されている機能は有効活用しよう�
  • 検証ははじめが肝心。後に回すな。結果的にコストが安く済む。�
  • 情報は裏を取る。絶対に!!�
  • 必ず裏をとった情報を元に動く。�
  • 検証はユーザーにもクライアントにも、そして自分にもメリットのあること。�めんどくさがらずにやることが肝心。�リーダーも検証が大事である ということを理解する。

28 of 105

頂点処理とピクセル処理

  • ここではGPUの基本処理のパイプラインの動作を説明します。�説明を単純化するためにジオメトリシェーダーやテッセレータ、ドメインシェーダーの話は置いておきます。�
  • 色んなところで説明されている事なので、正直耳タコでしょうが、お付き合いください。

29 of 105

GPUパイプラインは大体こんな流れ

  • GPUリソース投入(ジオメトリ・RenderState・テクスチャの入力-DrawCall)

  • 頂点処理(頂点シェーダーさんが頑張ってる部分)�
  • 透視変換(頂点シェーダーさんが超頑張ってる部分)�
  • ピクセル化 (ラスタライザさんがピクセル化すべきかどうか検査します)�
  • シェーディングしたりテクスチャ貼ったり(ピクセルシェーダーさんが命令書片手にあくせく走り回ります)�
  • 深度・α・ステンシルテスト(ROPさんがラスタライザさんより容赦なく仕分けます)�
  • ようやくバッファへ出力

30 of 105

パイプラインは長いボトルネックもそれぞれ違う

  • 一回のレンダリングに投入される情報が多い。(コンスタントバッファの数やテクスチャの枚数、バッファ数が多い)�
  • 一回の頂点処理、投入されるバッファサイズがとにかく多い。フォリッジやインスタンスレンダリングを使っていても、ある程度のバッファ量行き過ぎるとガクンとパフォーマンスが低下する。GPUによって幅がある。�
  • 0ピクセル出力が多い。ピクセルシェーダーさんが空回る。�
  • テクスチャアクセスが多い。グローバルなメモリアクセスが多い。�
  • ピクセルの重複書き込み(オーバードロー)�
  • 一回のレンダーターゲットへの出力する枚数が多い、ターゲットのビット幅が広い�
  • 単純に計算量が多い、使用レジスタが多い。(最近ではちょっとやそっとの計算量は全然大丈夫ですが)�
  • 一回のレンダリングの面積が広い。�
  • paramaterCacheが多すぎて、ピクセルシェーダーさんが走りづらそうにする。

31 of 105

描画準備の負荷になる部分(主にCPU負荷)�

  • コンスタントバッファのセットアップ�こちらはUE4だとマテリアルパラメーターの部分�
  • 使用するテクスチャのセットアップ�
  • RenderState関連(ステンシル比較 書き込み設定、深度比較 書き込み設定、ブレンドモード、カラーマスク等)�コンテキストのスイッチが入るものはGPUにも影響する。�
  • 別ストリームのバッファ。フェイシャルの頂点情報など。�
  • 上記をセットアップして、描画を呼び出す。�描画を呼び出すとGPUが解釈するためのコマンドに変換されコマンドリストへ積まれる。このコマンドの数が多ければ多いほど処理する数が単純に増えるので負荷へ。�

32 of 105

マテリアルパラメーターの上書き系

33 of 105

描画準備の負荷になる部分(DrawCallに関して)�主にCPUの負荷になります。

  • コンスタントバッファのセットアップ�こちらはUE4だとマテリアルパラメーターの部分�
  • 使用するテクスチャのセットアップ�
  • RenderState関連(ステンシル比較 書き込み設定、深度比較 書き込み設定、ブレンドモード、カラーマスク等)�
  • 別ストリームのバッファ。フェイシャルの頂点情報など。�
  • 上記をセットアップして、描画を呼び出す。�描画を呼び出すとGPUが解釈するためのコマンドに変換されコマンドリストへ積まれる。このコマンドの数が多ければ多いほど処理する数が単純に増えるので負荷へ。�

34 of 105

頂点処理の負荷になる部分

  • とにかく頂点数がある程度以上多く処理されるのが厳禁。��画面外にある頂点も計算されているので、できるだけGPUに投入される前にカリングできるようにするのが望ましい。��UE4のCPU上ではオブジェクトは、カメラの視界に入ってるかどうかの判定が行われています。(普通のエンジンでは行われていますが)�この視界の内外判定をフラスタムカリングと呼び、視界外の場合はGPUには投入されません。��

35 of 105

頂点処理の負荷になる部分2

  • オブジェクトの視界の内外判定にはオブジェクトのバウンディングボックス使われており、バウンディングボックスが大きいと、モデルそのものは画面に入っていなくても、GPUに投入されて頂点処理してしまうケースもある。��ほどほどの粒度でバウンディングボックスを納めるのが重要で、【ほどほど】のさじ加減はモデルのデザインにも引きづられる部分なので、よくアーティストとPGは相談する事。��バウンディングボックスはメッシュの大きさから算出されるため、複数の建物を1つにまとめたりすると、カリング効率が悪くなり、視界の外の頂点もGPUに投入される確率が高くなるので注意が必要です。

36 of 105

ピクセル処理の負荷になる部分

  • 最近のGPUではメモリアクセスが真っ先にボトルネックになりやすい�要はテクスチャアクセス。巨大なテクスチャほど負荷を食う。�別々なテクスチャへのアクセスはさらにパフォーマンス低下の元。�
  • 頂点シェーダーから出力されたパラメーターの受取。�ちゃんと送られてきたデータが全部ロードされないとWavefrontが回りません。(この後、WAVEに関して少しだけ深く説明します)�
  • 書き込み面積が広い。�仕事量が単純に多いという事です。

37 of 105

ピクセル処理の負荷になる部分2

  • 複雑な計算が多い�例えばパーリンノイズ、ライティング�
  • 0ピクセル出力�ポリゴンが密集して潰れている部分。�面積は小さいものの、単純に小さい面積をレンダリングするより重いので質が悪い。�
  • ピクセルのオーバードロー�結果には見えなくても仕事している量が多くなってる。�画面を一見しただけではわからないのでより質が悪い。�一つ一つのモデルのオーバードローはボトルネックとして見えない事も多く、チリツモでいつの間にか増えているため、本当に質が悪い。�雑にモデルを作る事で開発期間短縮は唾棄すべき考え。

38 of 105

ピクセルの速い書き込みは?

  • あります!�GPUはカラーバッファへ出力しないZだけの書き込みの場合は通常のレンダリングよりとても高速です。��それを利用したレンダリングにEarly Z Pass(早期Zパス)と呼ばれるレンダリングパスがあります。��UE4でもEarly Zと呼ばれてる機能でデフォルトでは静的なメッシュ、StaticMeshで行われています。�先に深度だけを書き込むパスを設ける事で、カラーバッファへの無駄な出力を抑える効果があります。(ただしドローコールは増える)

39 of 105

ほんのちょっとだけWAVEを掘り下げます(詳しくは昔のGDCのAMDの資料がお勧め)

  • WAVEの事を本当に簡単に説明させていただきます。�AMD GPUでの処理単位は[WAVE]と呼ばれる単位で処理を行います。�
  • WAVEは64スレッド分の命令をWavefrontとして実行します。�同時に走るWavefrontが多いほど速いということになるのですが、このWavefrontは複雑な計算を行ったりすると同時に実行できるWavefront減ります。(厳密にはレジスタを消費するとなのですが、レジスタを消費するトリガーは複雑な計算に概ねなるでしょう)��つまりwavefrontが効率よく回るために、なるたけコンパクトなのが望ましい。�ここまでなら、シェーダーinstructionを気にしてる方はやってると思います。�
  • 気づきづらい部分がもう一点あって、それはWavefrontが実行され始めるタイミングです。���

40 of 105

走り始めるには

  • WaveFrontが走り始めるには、頂点シェーダーからの出力パラメーターをピクセルシェーダーがロードし終えないと走り始めません。
  • そしてレジスタは16byteレジスタなので、パラメーターの総量ではなく、パラメーターのベクトル数が問題になります。�今AMDのもので説明してますが、他のGPUも同じ事がおきます。�struct FAtmosphereVSOutput{

      float2 OutTexCoord : TEXCOORD0;

   float4 OutPosition : SV_POSITION;

   uint LayerIndex : SV_RenderTargetArrayIndex;

   uint LayerIndex : TEXCOORD1;

    };�    例えばこれはベクトル4本がピクセルシェーダー開始時に消費する事になります。�

  • つまるところピクセルシェーダーさんの運ぶ荷物が全部揃うまで動きません。�頂点シェーダーさんからピクセルシェーダーさんに渡す出力が多いほどピクセルシェーダーさんには荷物がなかなか届かず待たされます。�結果的にパフォーマンスネックになります。ポリゴン数少なくても起きるので、ものすごくたちが悪いです。�回避方法は今のところ使わない機能はベースシェーダーで、極力オミットしたり、使い分けるようのベースを用意する。(UE4のソース読んだけど、それぐらいしか思いつかなかった。)

41 of 105

なんでWAVEの説明するかというと

  • UE4にかぎらずで、今時のノードベースのシェーダーは、頂点情報の出力が実際どうなってるのかがパット見では分からなくなってきています。�そのため、実はかなりボトルネックになっている事がままあります。��なんとなくの概要と、そんなケースもあるんだということを知ってほしかった次第です。

42 of 105

GPUの普段の生活を見てみましょう(小芝居)

  • GPUの生活編

43 of 105

まとめ

  • GPUはとっても複雑。�画面を見ただけではわからない負荷はとっても多い。�ポリゴン以外の要因もかなり多く、一見しただけでは本当に正確な情報はわからない、頂点処理の負荷なのか、ピクセル処理の負荷なのか、ピクセル処理にしても一回の出力なのか、全体の出力が重いのかなど状況によって変わる。�
  • 重いと感じる前からプロファイルは取る。�
  • 重いと感じている時は尚取る。��コンソールの環境があるのなら、コンソールの環境で負荷を測る。�アナライザが非常に優秀なので。�そこまでしないとけないぐらいGPUのパフォーマンスは複雑です。��可能であればプログラマーでキャプチャを取って解析して、解析結果を元にアーティストと方針を立てる。��

44 of 105

小ネタ

  • レンダーターゲットのフォーマットが必要な精度かどうかを確認。�例えばUE4のHDRレンダーターゲットはr16g16b16a16の64ビットフォーマットですが、HDRレンダーターゲットのαを使わず、現実と同じ光量を使わなければR11G11B10_floatのフォーマットでも表現は可能です。�DefaultEngine.inlにr.SceneColorFormat=2で変更される。�整数部分が255の範囲にある分には大丈夫。�

   ParticleSystemのカスケードでライトを使うと【SimpleLight】という扱いになり、

   Tiled Deferred Shadingが走る。とっても重いので、r.TiledDeferredShading=0

できっておくといいです。�

  • 縮小バッファと被写界深度を使わない場合でTAAを使っているならseparate translucencyを切る。(動的に切り替えるのもありかと。)�シーンへのアップスケールの処理と、半透明バッファへのTAAがなくなるので、高速化に繋がる。�
  • AtmosphericFogはフォグじゃなく、ライトスキャッタリングなので用途に注意。�アーティストがフォグを欲しそうにしてたら、マテリアルノードでそっと作ってあげる。

45 of 105

小ネタ2

  • r.translucentlighting ボリュームデータなので必要がなければ切ったほうが良いです。�レイトレース系の処理や半透明のライティング処理で使用しています。�最適化のために処理を制限している場合、使われないと思いますが、有効にしているだけでボリュームデータのクリアにGTX 750TI 0.5ms以上食ってました。�

46 of 105

無駄なピクセルの重複書き込み

  • なかなか意識出来ないのですが、同座標にピクセルを出力することで、無駄に負荷になるケースがあります。�普段の作業ではなかなか気づくことが無いため、簡単に説明させて頂きます。�個々のアセットを気をつけないと、地味にピクセル負荷を持って行きます。�面積が少ないのに、【書き込み量が多い】なんてことにもなります。

47 of 105

頂点の密集例

48 of 105

どういう事か

  • 左側の画像ではほぼ青。無駄な書き込みはほぼ見られません。�
  • 右側の画像はほぼ緑の状態。無駄な書き込みが多く見られ、見た目の面積より書き込んでいる事が分かります。�
  • UNREALにはOptimize ViewMode→Quad Overdrawで重複書き込みを確認する機能があります。�超便利なので活用しましょう。

49 of 105

重複書き込みの小芝居

50 of 105

回避方法は?

  • 遠景では頂点の密度を薄くする。�つまりLODを【適切に作る】�
  • LODにする前段階から、表示面積と頂点の密度は意識する。�LODの自動生成だと全体のポリゴン数が下がっても、密度の濃い場所は相変わらず密集しやすい。

51 of 105

UE4のLODに関して少々掘り下げます。

  • LODの種類� 1.UE4の機能で自動リダクション� 2.LODモデルを直接import�
  • LODの切り替え方� BoundingBoxの画面占有率で切り替わる。� 1.各LEVELに対し、自動で割り当て� 2.各LEVELに対し、直接設定

52 of 105

何かここで気がつくことは?

  • 切り替えは画面占有率なので、単体で大きいモデルはLODが切り替わりづらい。�
  • そもそもモデルの部分的に密集している部分は、自動LODだと密集したままである事が多い。�LODで理想な形状を作ろうとすると手動で職人芸で作る事が最大クオリティだが、時間もかかる、後述しますが、別な問題もでます。

53 of 105

LODを作る上で大事なことは?

  • モデルの適切な大きさ、粒度。(LODに切り替え易くするためにもDrawCall数のためにも大事)�
  • 面積と頂点の密度の比率。(自動LOD生成ではそれなりに大事)�ポリゴン減らしただけでは効果としては全然足りない。�
  • LODモデルの適切な数。�切り替えの瞬間が分かりづらい程度に分けられるといいと思います。�
  • LODモデルの適切な切り替え距離。�
  • 切り替えレベルに応じた最適化したマテリアルの割当。(例えば、ある程度の距離のNormalMapはミップマップ的に潰れていて意味がないので外す)�マテリアルもLODできるという事。�
  • 一番大事なのは、それらを制作しているゲームに合わせてカテゴライズしてルールを作成して、出来る限り自動化したり、裁量の余地を与えないようにルール策定すること。�裁量の余地があるほど、量産期に雑なデータが紛れ込む。

54 of 105

ルールの決め手は

  • 形状�減ポリしづらい形状や、減ポリしやすい形状があるため�
  • 大きさ�どういう距離で設定すべきカテゴリかの要因のひとつ。�
  • 使われる場所�遠景ならそもそもLODでなんとかするのではなく、最初からディティールを作らない。

55 of 105

ルール策定にあたって

  • UNREALはテスト用のマップを作成するのは楽。�テスト用の色んなパラメーター違いのオブジェクトを作ってとにかく並べて見ましょう。�GPUのプロファイルは取って置くと良いです。�
  • カテゴライズできるようにルールを組む。�例えば自然物系なのか人工物なのか、何m以上とかでさらに分けるであるとか、コリジョンに関係無いもので近づけないものは遠景扱いにするとか。�カテゴリ紐付いて、LODであったり、パラメーターの設定であったりを作る事で作業にノイズが入り込む余地をなくす。�
  • ただし、BaseModelが丁寧に作られている事が前提。

56 of 105

LODを作る意義とは?

  • まず当然、処理負荷を軽くする事。�
  • 【表示の無駄】を無くすことで、後から出てくるアイディア実現のためのパフォーマンス的なバッファを設ける。��パフォーマンスが出てない状態からだと、要らない気を知らない間に回されて、【本当はやりたかったアイディア】を引っ込められてしまう なんて事もありえます。�相談されてもいない状態でオミットしたアイディアなんて知らんよ・・・。とは思うのですが、他人が気をつけてどうにかなるのであれば気を使ってもいいとは思います。ユーザーからしたらもっと知ったことかという話なので!�

57 of 105

まとめ

  • LODの減ポリはポリゴン数だけで見ては駄目。�表示との頂点の密度の面積が重要。�
  • マテリアルもLODする。�余計なテクスチャアクセスや、頂点シェーダーからのピクセルシェーダーへのアウトプットを最適化する。�
  • LODのためにもBaseModelは出来るだけ丁寧に作成する。�雑な部分は雑なまま引き継がれてしまう。�特にぶっ刺しモデルみたいなのは、ピクセルとして現れないだろうと過信するのは注意。�普通には確認が難しいですが、ZPrePass内でのOverDrawも積もると負荷になる。�

58 of 105

LODで注意が一点

  • LOD用のモデルを、手動が一番丁寧に作れるからと、LODのレベルに直接IMPORTするとそれぞれのLODにライトマップが作られるので注意。�自動生成の方は共有化されます。��おそらくカメラが離れていった時の、DrawCall対策にそうできるようになってるんだろうなあと・・・。

59 of 105

後半の部

  • Dynamic ShadowとStatic Shadow

 影の焼き込みは最後に行う�

  • 遠景モデルを効率よくまとめる

 全部一つにすればいいわけじゃない�

  • テクスチャ解像度に関して

 大きいテクスチャがクオリティを高くする方法ではない�

  • UE4でドローコールをまとめることの注意

 闇雲にまとめればいいというものではない

60 of 105

DynamicShadowとStaticShadow

  • パフォーマンスの最適化において非常に重要な項目になります。�UE4のライティングの詳細な話はDeepDive Lightmassの仕組み を見てもらえればと思います。��こちらでは仕組みは簡単な説明だけで済ませます。

61 of 105

Dynamic Shadowに関して(皆既に知ってる事ではありますが)

  • 名前の通り動的な影になります。�毎回光源からの各アクターの遮蔽情報を生成するための処理が走ります。�そのため、生成するアクターが多いとそれだけ負荷があがります。��当然DRAW CALLも増えるのでCPUにも直撃します。�

62 of 105

動的な事でのメリットは

  • アクターが動けば一緒に影も動きます。�アニメーションにも追従できる。�
  • 他の動的なアクターへ影の形状通りに影をドロップできる。�
  • シーンでリソースがある程度固定できるので、アクターが増えても影のためのリソースは増えない。

63 of 105

デメリットは?

  • DRAW CALLが増える。(CPU負荷が増える)�特にカスケードシャドウの場合は、カスケードする数で掛け算される。�
  • 影に書き込むGPU負荷がフレームかかる。アクターのモデルの作り、数に応じて比例する。�
  • アーティファクトが特に出やすい。

64 of 105

STATIC SHADOWに関して

  • 静的な影になります。�事前に影を生成することで、Dynamic Shadowに比べて、より詳細な情報をモデルごとにライトマップを生成しておきます。��ランタイムの負荷が比較的小さい処理になります。

65 of 105

静的な事でのメリットは?

  • 事前に準備するため、よりディティールのある間接光まで表現できます。�StaticShadowと書きましたが、ライトマップの焼付の場合影というよりは、名前の通り光の方を保存しています。�
  • 事前に準備しているので、高速�アクターごとに毎フレーム生成したりしないので、CPU的にも高速です。

66 of 105

静的な事でのデメリットは

  • 動的なものへの影響がLightProbe経由になる。�LightProbeだと結構曖昧な情報になります。�
  • これはこれでアーティファクト対策が必要。�よくあるアーティファクトとしては動的ライトが裏から当たってしまう、オブジェクトのつなぎ目からライトリークしてしまう、解像度が足りなくてがたがたになってしまうなど。�比較的、設定項目が多くて複雑。(CGのLightBuildよりマシ)�
  • ライトマップが生成されることによるメモリ消費�
  • ライトマップのベイク時間�タイトルによってまちまち、30分のチームもあれば、6時間のチームなどもあります。�UE4ではないですが、過去自分のいたチームでは24時間たっても終わりませんでした。

67 of 105

使い分けは?

  • まずは大きい分け方として、”影を落とすものが移動"するかどうかで切り分ける
  • 背景や配置オブジェクトは基本StaticShadowにする。�
  • キャラクターに配置オブジェクトのディティールのある影を落としたい場所は、ピンポイントでDynamicに置き換える。(そうしないとCPUもGPUもすぐ使い切る)�
  • 揺れ物も、目立つやつだけDynamicShadowにして、目立たないものは極力Static Shadowにする。�何度も言いますが、CPUもGPUも有限です。�

68 of 105

Shadowの小咄

69 of 105

まとめ

  • Dynamic Shadowはアクターの数で負荷が比例する。�Dynamic Shadowを処理するアクターを沢山は基本高負荷。�GPUにもCPUにも打撃を与えるので注意。�
  • Static Shadowはアクターの数にパフォーマンスは比例しない。�ただし解像度やアクターの数でメモリの使用量が変わるので注意。�基本高速。�ベイクに時間かかるし、ベイク対象は毎回シーン全体なので、レイアウトがある程度フィックスする、もしくはチェックに入るぐらいある程度切りのいいところでベイク。�過去あったものでは1つオブジェクト置くごとにベイクしてチェックしてもらってた方とかいましたが、普通はそんな事してられません。�
  • 使い分けはケース・バイ・ケース。�それぞれの表現したい内容に応じて、負荷の高いものはピンポイントで対応してあげる。

70 of 105

小ネタ

  • LightをBakeする時に一緒にLightProbeが生成されますが、あれは数が多いとランタイムでも負荷が高くなるので、注意。�LightProbeの更新処理が結構重いです。�こちらはUE4のデバッグ機能で、Show→Visualize→Volume Lighting Sampleで粒度を確認できます。�
  • UE4は配置アクターからDynamic Shadowの項目をはずしても、BakeしないとStatic Shadowの処理には入らない。�負荷計測の際は十分に注意。

71 of 105

遠景モデルは効率よくまとめる。

  • 遠景モデルのまとめ方になります。��よくDraw Callをまとめようとするあまり、全ての遠景モデルを1アクターに収めようとされるのですが、そのやり方には問題があります。��ここではなんで1アクターにまとめてはいけないのかなどを話ていこうと思います。

72 of 105

まとめる粒度が大きい場合

73 of 105

何が問題か

  • 視界の外にも、モデルがあります。�処理されているイメージが薄いですが、頂点シェーダーまでは処理が走ってしまいます。��もし頂点数が多ければ、頂点ネックの負荷としてパフォーマンスに影響があります。�こちらもぱっと見処理されていないように見えるので、ちょいたちの悪い類のボトルネックになります。�
  • そもそも移動領域をはっきり決められるゲームであれば遠景は描き割りの板で用意するのも手です。�
  • オープンフィールドのようなもの作る時では、近景用のアクターは一定距離では消して、遠くでだけ表示されるようなアクターにローポリをまとめておいて、ある程度のまとまりで表示するのがCPU的にもGPU的にも効率が良いと思われます。�UE4に4.13から入っているHLODも検討するのが良いのではないでしょうか。�アクターをグルーピングして、テクスチャをアトラスして纏めます。�
  • 書割にしてノーマルマップで陰影をつけるのも良いと思われます。

74 of 105

少し粒度を細かくしてみる。

75 of 105

さっきと比べて

  • カリングされる頂点数は増えている。�
  • Draw Callも増えている。�そのため、分けるべきかどうかはケース・バイ・ケース�CPUが先に限界に来ていれば、遠景をすべて纏めざるを得ない時もあるかも知れない。�

76 of 105

さらに細かく分けてみる

77 of 105

なんのために細かくしたの?

  • 遠景を手前と奥の2層になるようにしました。(画像がわかりにくくて申し訳ないですが・・・)
  • そうすることで、ピクセル単位のカリングを優先しています。�ZPrePassが走るのですが、ZPrePass時にも出来るだけ無駄なピクセルは省くに越したことは無いからです。��ただ、Draw Callは増えるので、やはりケース・バイ・ケースです。��アナライザでちゃんと調査するのが良い。

78 of 105

頂点カリングの小咄

79 of 105

まとめ

  • 視界外でもDraw CallされればGPUの負荷になる。(GPUに投入されるので)�
  • DrawCallを優先すればCPUが、ピクセルを優先すればGPUのパフォーマンスが良くなる。�
  • ゲーム制作は色んなケースが混在する。�遠景の纏め方はその時やりたい事、しなければならない事に合わせて最適な方法を。�必ず負荷調査、検証を!

80 of 105

テクスチャ解像度に関して

  • GPUメモリも使えて、GPUパフォーマンスも高い昨今。�潤沢なものほど浪費されるという法則通り、テクスチャ解像度をただ高くしてしまうケースが増えてきました。�とくに解像度高くしただけでクオリティをあげたのだと勘違いされるケースが増えたように思えます。�ここでは解像度あげればクオリティが上がるわけではないという説明を行います。

81 of 105

まずこの画像を見てもらいましょう。

82 of 105

オブジェクトのテクスチャ構成

83 of 105

テクスチャの解像度大きすぎませんか?

  • 大きいサイズのテクスチャへのアクセスはボトルネックになりやすい最有力候補です。�本当に2048x2048と4096x4096は必要なのでしょうか?�確かめてみましょう。

84 of 105

マスクテクスチャを半分へ変更してみましょう。

85 of 105

こうなった状態ですが違い分かりましたか?

86 of 105

次はノーマルマップを半分にしてみましょう

87 of 105

こんな状態ですが違い分かりますか?

88 of 105

ダメ押しにもう一枚ノーマルを半分にしてみましょう。

89 of 105

こんな状態になっちゃってますが違いはわかりますか?

90 of 105

4枚並べてみましょう(小さくてすみません・・・・)

91 of 105

違いはわからなかったと思います。

  • 必ずしも高い解像度が必要ではないという事がおわかり頂けたでしょうか?�今回は最初から帯域が問題ではなかったために速度の違いが出てきませんでしたが、本番ステージで、アセットが増えてくるとガツンとパフォーマンスに響いてくる部分になります。�
  • 高い解像度のテクスチャは容量も食います。�読み込み速度にもダイレクトに影響する部分なので、不必要に高い解像度はデメリットが非常に大きい次第です。�
  • UE4ではテクスチャアセットを直接書き換えする機能があり、この辺りの検証も非常に楽にできます。�実際の見た目を確認しながら検証を行う事ができるので、高い精度の検証結果を得られます。�テクスチャリソースを削減しつつも、クオリティを下げずにパフォーマンスを向上させることが出来ます。
  • また、テクスチャの解像度を上げてもミップマップ処理があるため解像度通りの結果がでるとは限りません。

92 of 105

テクスチャ解像度の小咄

93 of 105

UE4のテクスチャEDITOR(書き換えるとすぐ反映されます

94 of 105

まとめ

  • テクスチャの解像度が高いからと言って、クオリティが高い訳ではない。�
  • 不必要な解像度はメモリもGPUパフォーマンスもロード時間も圧迫する。�
  • UE4はテクスチャの検証も楽。

95 of 105

小ネタ

  • タイリングすべきところ、UVを分けてべた張りをしないようにする等の工夫で解像度を温存しましょう。��複数オブジェクトで使いまわす場合はなかなかテクスチャを最適化しづらいですが、やれる時にはやっていきましょう。��必要な解像度をできるだけ初期に割り出す事で、アウトソースする時にも便利ですし、管理もしやすくなります。��念頭に置くことで、準備する選択肢が増えるので、そういう手順もあるのだ と知ってもらえれば幸いです。�

96 of 105

UE4でDRAW CALLをまとめることの注意

  • 本当はUE4に限った話ではないのですが、UE4が便利だったために起きた不幸な事例があったため、注意を簡単に書かせて頂きます。

97 of 105

MERGE ACTORの誤解!!

  • UE4にはアクターをマージする機能としてMerge Actorという機能があります。�DRAW CALLを減らせる便利な機能なのですが、こちらはただくっついて、軽くなるだけの機能等ではありません。�デメリットもちゃんとあります。��1.くっつけたアクターの分大きいメッシュとして扱われる事でカリングがされづらくなる。�2.当然大きくなった分LODには切り替わりづらくなります。�3.一度くっつけるとメンテナンスしづらくなる。� マテリアルも統合されてしまうので、複数のアクターで生成した一点もののデータになっちゃうのでUE4からFBXへエクスポートしないとメンテナンスできなくなります。�4.DrawCallがマージされるようなマージの仕方をした場合、テクスチャがアトラス化されるので、元の解像度より大きく下がる可能性が高い。

  5.マージしてしまうと戻せないのでよく考えて使うこと。��  アーティストが勘違いして、使いまくってた事がありました。�  機能を使う場合は必ず検証をして、想定した運用方針、動作になっているのかどうか確認を!!!

98 of 105

フォリッジでとにかくインスタンシング

  • こちらも大変不幸な事例です。�インスタンシング=とにかく軽い�というイメージから起きた事でした。��インスタンシングは設定する頂点データは共通のデータで、描画時に座標を変換するマトリクスの配列をModel Index毎に頂点シェーダー内で参照させることにより1回のDrawCallで複数オブジェクトをレンダリングする技術です。�沢山のデータであるほどDraw Call分のCPU負荷は確かに減ります。��ただしレンダリングが1回分の処理に置き換わるわけではありません!!�
  • レンダリングするからには頂点計算を行っています。�LODにはクセがあり、ドキュメントには【インスタンスのすべてのクラスタが LOD を同時に変更します】と記述されています。�全体にまんべんなくばらまかれたフォリッジが正しくLODを切り替えている姿を少なくとも自分は確認出来ていません。�全部共通のLODでレンダリングされるため、効率的とは限りません。��便利ですが、使い方は注意しないといけません。�特に重いマテリアルが割り当てられているモデルは割けるべきでしょう。�社内オリジナルエンジンであってもインスタンスを使ったレンダリングは同様の事です。

99 of 105

DRAW CALL さえ減らせば描画は軽くなる???

  • そんな事ありません!!�描画に関わるCPU負荷が下がるのです。�CPUが重すぎる場合にはGPUも一緒に引っ張られて下がる事もあるため、Draw Callを下げるとGPU早くなるという誤解を生んだのでしょう。��纏めすぎる事で頂点ネックのパフォーマンス低下を引き起こす事もあります。�描画順も効率的かどうかには疑問が残ります。��必ず複数のパターンで検証を行いましょう!!!��

100 of 105

結局Draw Callはどうまとめればいいの?

  • どこで見えるものなのか?を考慮してケース・バイ・ケースで粒度を決める必要があります。�バランスが大事。�
  • 例えば遠景であればより大雑把な方が効率がいいでしょうし、近景ならそもそもインスタンシングしないほうが効率的な場面もあるでしょう。��モデルを纏め過ぎればLODに切り替わりづらくなることも考えると、マテリアル負荷の高いものは、LODしやすくなるようにDraw Callが増えたとしても分けてモデルを小さくしてしまった方がいい時もあります。�状況に応じて使い分けを。

101 of 105

まとめ

  • DRAW CALLはCPU負荷で、GPU負荷などではない!!断じてない!!�
  • 纏めすぎる事が逆にGPU負荷になることもある。�
  • そもそも美味しそうな機能は、注意書きを読むことと、色んなパターンの検証を行う。�UE4は機能検証し易いこともメリットの一つ。�
  • 粒度を正しく設定するためにも、作業より設計に時間をかける。�正しい粒度が正しいパフォーマンスへの近道。�バランスが大事

102 of 105

最後のまとめ

  • パフォーマンスの最適化は、ゲームが重くなってからやるものばかりではなく、初動が大事です。�特に中小企業は!�よく、時間が無いことを最初に検証をしないことにあげられるのですが、それは全くの逆で、お金や時間がないからこそ、効率的に回す必要があり、効率的に回すために検証を行う必要があるのです。��検証も完璧にすべてやろうとするのではなく、今自分たちに一番効果のある部分かつ後々まで使えるノウハウに絞り、次のプロジェクト、その次のプロジェクトにノウハウを引き継げるように積み重ねて行くのです。�これならば時間がない中でも、少しづつよくしていく事が可能なはずです。�日本は一度の作業で結果を求められやすいですが、仕事についてる時間や、自分のこれから生きていく時間を考えればその瞬間より、来年、再来年、今より良くなってる事が重要です。

103 of 105

最後のまとめ2

  • 最後の最後にパフォーマンス調整を行う想定は絶対にやめましょう。�最後にやれる事は、クオリティ下げるような対応になりがちです。�プロジェクト途中が時間がない状態だから仕方ない となっていれば、最後も時間がないに決まっています。�クオリティを落とす最適化を最後に行うのはそれまでの中間報告に嘘があったという事になり、クライアントやユーザーを騙す行為に繋がります。��作ってるゲームに責任を持つつもりで制作に関わっているのであれば、最後に調整は絶対にやめましょう。�

104 of 105

大事な事

  • 一つのやり方で解決する魔法のやりかたは存在しない。�どんなものでもケース・バイ・ケース。�
  • 丁寧な作りを心がける。�データの雑さはそのまま管理のしやすさ、パフォーマンスに直結する。�
  • 昔と違って一つのセクションでは完結しない。�データの粒度、クオリティ、画面の導線を決めるためにも、�PG、ゲームデザイナー、アーティスト、サウンド、状況によってそれぞれが協力し合う事。�

105 of 105

ご清聴ありがとうございました