ゲームエフェクトデザイナーのブログ | A Real-Time VFX Artist's Blog

About Making Materials on UE, Making Tools with C#, etc

「VR×ロボ×美少女! UE4におけるVR向けの絵作りと最適化」レポート

UNREAL FEST OSAKA 2016』のメモ公開2つめ。

ヒストリアさんによる、UE4で制作されたVRコンテンツ「アーガイルシフト」の開発事例。

はじめに


原龍さん エンジニア / TechResearch 元家庭用・スマフォ向けゲーム開発
原伸吾さん アーティスト / TA 元映像業界
ハラハラコンビ

◆アーガイルシフトについて

ダイバーシティ東京プラザ VR ZONE
ヒストリアは開発協力
アイネというキャラクターのナビゲーション
テストパイロットとして有人兵器ルシファーに搭乗
「サマーレッスン」の原田さん監修

バンダイナムコ
 クオリティコントロール、アウトゲーム、実機の揺れやサウンドアセットの作成

SOLA DIGITAL ARTS
 Matineeを使った全体的な演出を作成
 キャラクター、背景などのアセット作成
 荒牧伸志監督

・ヒストリア
 UE4内のシェーダー、ライティング、ポストプロセス、エフェクト作成
 インタラクティブパートのプログラミング、サウンドの組み込み
 最適化

ワークフローの中心はUE4のMatinee(マチネ)
シーケンサーは現状は懸念が大きかったのでMatineeを選択
SOLAさんにMatineeを触ってもらう

VRでの没入感を高めるために ~演出強化~


◆背景はPBRで描画しつつ、キャラクターはアニメ的なシェーディングで描画したい!

疑似ライティングあり/なし(比較画像)
光源の角度と法線から疑似的に光の影響を表現
か0分アセットを用いて光源の角度や光の色を時間経過により変動させる仕組みづくり

キャラクターマテリアル
肌や髪は標準のライティングはしていない ライトベクトルから色を決めている
服や靴などは標準の物理ベースシェーディングを使用
最終的にハイブリッドな構成になった
全てUnlitにしてみたりすべてリアルにしてみたい色んな検証を行った

◆キャラクターがそこに存在している感じにしたい
◆プレイヤーを目で追うようにしたい

目線追従が無いとただそこにいるだけになり認識している感じが出ない
これが入ると没入感に繋がる
Two Borne IKを使った Look at Tableを利用
ただし常時こちらを見ているというのは不自然
演出に合わせてブレンド率を切り替えることにより自然な目線を実現

◆画面中央のレティクル(照準)に動きが無く視認性が悪くて機能していない
レティクルの追従にわずかなディレイを入れた 画面の真ん中にずっといる訳ではない
これにより視認性がぐっと上がった

◆自機の前進速度が速すぎて撃った弾がまっすぐ飛んでいかないように見える
 ⇒ うまく敵に当てることができない!
演出の都合上とても速く敵も自機も動く
かなりの距離を移動してしまう 弾が曲がって見える 弾が当たらない
計測してみたら時速400kmになっていた
位置補正を入れることで操作感が向上
ロックオンと重なったものは気づかない程度にホーミングを入れた
Projectile Movemnt Componentを使用
物理的に正しい挙動ではなくとも、見た目や操作感を重視

◆飛んでくるミサイルに対して頭を左右に動かすという操作が難しい
 だが単純にミサイルの速度を下げると危機感が無い

ミサイルが近づいた際にスローモーションを入れた
視界全体の色も変えて危険を知らせ、回避を促す(画面がやや赤くなる)
Set Global Time Dirationノードを使用
UE4では簡単にゲーム全体の時間経過速度を変更可能

良い演出を余すことなく伝える ~最適化~


ついに演出がFIX! しかし全体的に40fps Viveでは90fpsが理想
しかもVRではさらに2パスある
最適化して改善を目指す
マスターアップ直前で最適化作業に取り掛かれる状況になった
今回は演出にとことんこだわりたい案件だったのでギリギリのスケジューリングだった
それまでにどこを直そうという目算は立てていた 急ピッチで進めた

◆最適化に対しての方針

1「可能な限り、最適化前の演出や描画品質を落とさない」
最適化で描画品質を下げたり要素を削ることでコンテンツのクオリティを下げるのは本末転倒

2「最高のVR体験のために90fpsは厳守」
 TimeWorkという機能でフレーム間が補間される機能がViveにある
 しかし実際に体験すると一瞬でも90FPSを下回ると違和感があった
 全てのシーン、カメラ位置で90fpsを知ら回らないようにする

◆Stat Unitでボトルネックを調査

Gameスレッド(CPU)がボトルネック
GPUも同じくらいだったがGameスレッドを待つためにストールしているだけなので実際はそこまでかかっていない

◆CPUプロファイラ

C++、ブループリントともに細かく処理時間を確認することが可能

「突然ですが、ここで問題です」
どちらが軽いでしょうか? Make Array 純粋関数かそうでないか
純粋関数とは?
実行ピンを繋ぐ必要がない関数 いつでも切り替えられる
ノードの見た目がとてもすっきりする

それぞれ一万回実行したところ、非純粋関数の方が早くなった
300msと400ms 同じ処理にも関わらず大きな差が!
こちらに関しては二つの要因が含まれている

(ForEachLoopマクロの中身を出しながら‥)
① ループ回数判定のための評価(実行)
② ループ実行の引数のための評価(実行)
一度のループのために二回以上のArrayの評価が入ってしまう
10回のループのために21回の評価が入る
入力に渡された配列をキャッシュせずループするたびに最新のArrayを取得する
ループ実行中に配列の中身やサイズを変更すると思わぬバグを生む可能性がある

純粋関数の特徴
実行ピンにつながなくて良いため見た目がすっきりする
 バグを未然に防ぎやすい、作用内容を把握しやすい
繋がれている非純粋ノードが実装されるときに実行される
先ほどの例で使用したMakeArrayを非純粋関数に置き換えたら?
純粋じゃない関数はもう一度実行ピンを通過するまでキャッシュを残す

このため純粋関数はgetterのような単純な処理に限定すべき
何度も実行されると問題があるような処理は避ける

こういった処理の最適化やロジックの見直し、不要処理の削除を行った結果
エディタ上でGameスレッドが11ms以下になった!
Standalone時はエディタの処理が無くなり7ms
GC/ガベージコレクションが入っても問題なし)
デフォルト設定だと60fpsごとにGC起こる CPU負荷が上がる

◆ほとんど効果がなかった負荷対策

ベクトル長の比較時にLengthSquaredを使用する
10万回実行してもほとんど差が見られなかった
やっておくにこしたことは無い程度 ノード複雑化するくらいならやる必要なし
引数を参照にする事によりコピーコストの削減
値渡しとの一万回実行速度比較をしてもほぼ変わらず

ちなみにこれらはBPの話 C++では違ってくるかもなのでそちらは計測してみて
CPUに関しては約3日かけて最適化 これで50fpsになった

GPUプロファイラ

スナップショットをとって瞬間的なGPU処理時間を出力できるので対策の足がかりになる
Shader Complexity(シェーダー複雑度)の表示
シェーダー命令数を視覚化 単純に負荷に直結するものではない
半透明オブジェクトの重なりなど大まかなボトルネックの目安になる

◆具体的な最適化内

1「距離とカメラが向いている方向を利用した自前の軽量化リング」

半谷のアクターは表示やアニメーションの計算などを切る!
標準は各アセットに設定したボリュームでオクージョンカリングする
アセットにそこまで手を入れてなかった・表示だけじゃなくてもっと切りたいものもあったので自前実装
カメラからの距離、角度をプロパティで設定できるようにしてある
Z軸方向の回転角 アクターからカメラまでのベクトルを使って求めている
そのままアタッチするだけで使える

2「プリレンダ向けメッシュのリダクション」

とても効果があった
アセットの最適化の話になる
主なスケルタルメッシュの頂点数のリダクション
・輸送機 80万超x6
・味方機 35万超x11
・敵気 20万超x沢山
 とてもヘビー級‥
まずこれを何とかしようとしてリダクション
味方機は35万 ⇒ 15万に(約6割減)ビューポートで見た目上ほとんど変わらない
輸送機は80万 ⇒ 8万に
敵機は20万 ⇒ 6万に
にぎやかしとして遠くに多数配置した味方機のアクターはビルボードに変更
これで1シーンで数百万ポリゴンの削減
しかも言わないと誰も気づかなかった
余談だが一昨日スライドを佐々木代表に見てもらったら驚かれて良いリアクションをもらった

アニメションの計算負荷を抑える
アニメーションが無いメッシュはスタティックメッシュに変更
アニメーションするメッシュも必要部分だけスケルタルにしてスタティックと併用
演出上、絶対に見えない部分のメッシュは削除

3「マテリアルのブレンドモード最適化」

UE4はディファードレンダリング
半透明オブジェクトとは描画パスの都合上、相性が悪い

不必要に半透明マテリアルとして設定されているものはOpaque、Maskedに変えている
大きく効果はあったが気の重なりが多くMaskでも重い!
木は不透明のものにするとfpsの落ち込みが無くなったので不透明にできるか検討
形状で木を表現 ポリゴン数は増えてしまう
フォリッジはインスタンスドスタティックメッシュなので負荷が増えなかった

4「ダイナミックシャドウの調整」

キャストシャドウするアクターの数を抑えた
思っていた以上に有効だった
近くで目立つアクターのみON 遠くのアクターはOFF
負荷と見た目を見ながら調整していった

地道にやった結果ついに90fps達成!
思った以上の最適化効果があったので描画解像度を110パーセントに上げた
ある特定の演出の時にHUDが重なることがありそれだけはどうしようもなかった
こちらは良い演出だったので削れなかった

全てBPで実装した
プロジェクトの都合上ではあったがC++を使わずとも90fps実現可能という良い例になった
C++ならもっと最適化できたかも知れないが、BPでもいけるという指標になった

VR開発のまとめ


作ってみないと分からないことが多い
演出の確認をする場合はHMDでの確認を徹底する
視差による相性の悪さから、使えなかった表現もある
 キャラの輪郭線を描いていない 左右でレンダリングするのでブレて見える
 ブルームを抑えたり 片目だけ画面内に入っていると違和感が出るので
演出も最適化も妥協すると途端に没入感を失う

Instanced Stereo RenderngがUE4.11から入る
両画面を同時にレンダリングすることによる速度改善 1パスにまとめられる
CPU GPUともに処理コスト削減
一度検討してみると良いかも知れない


togetterのまとめ。こなべさん毎回ありがとうございます!