117.3K Views
May 25, 23
スライド概要
2016年の資料なのでちょっと古いです
シェーダちょっとできるクライマー
なぜなに リアルタイムレンダリング リアルタイムの今までとこれから
本日のお品書き • はじめに • レンダリング基礎 • レンダリング手法Q&A • これからの話
はじめに
はじめに • 最近は猫も杓子もDeferred Rendering! – 光源がいっぱい置けるようになった! – ポストプロセスで使える情報が多くなった! • その一方で… – 半透明をできるだけ使わないでと言われる – 不透明マテリアルより半透明マテリアルのほうが出来ることが 少ない – 描画の自由度が低すぎない? • キャラ固有のライトが使えない or 使えるけど制限あり • キャラを描画する前にパーティクル描画したいのに出来ない
はじめに • Deferred Renderingってそんなにいいの? – 利点は間違いなくある – 欠点も間違いなくある • Deferred Renderingを使うべきか? – 作品による – アニメ系だとDeferredじゃなくてもいいんじゃない? • 大量のライトを使うと逆に陰影がおかしくなってしまう • 作品の目指すところとレンダリング手法はマッチしている? – たいていはエンジニアがヒアリングの結果、決定している – 提案したいけど、よく知らないから提案できない
はじめに ならば知ろう!
レンダリング基礎
ポリゴンラスタライザ • 現在のリアルタイムレンダリングで最もよく使われて いる手法 • 処理順序 – – – – ポリゴンの頂点をスクリーン空間に変換 処理を行うべきピクセルを選択 各ピクセルの色を決定 レンダーターゲット(描画バッファ:RT)に描画 • 半透明などの手法でブレンディングする場合は RTの内容をフィードバックする
ポリゴンラスタライザ
ポリゴンラスタライザ 頂点シェーダ スクリーン空間に変換
ポリゴンラスタライザ 頂点シェーダ スクリーン空間に変換 ラスタライザ 塗るピクセルを選択
ポリゴンラスタライザ 頂点シェーダ スクリーン空間に変換 ラスタライザ 塗るピクセルを選択 ピクセルシェーダ 色を塗る レンダーターゲット(RT)
ドローコール • 描画プログラムの命令でDraw~という命令を発行すること、 もしくはその発行の単位 – 通常、同じモデル、同じマテリアル、同じカメラ、同じRTに対し て1ドローコールが行われる • 昔はハードの制約の問題で同じマテリアルだけど複数回のドローコー ルということもあった – ドローコール発行のタイミングで描画に必要な各種設定を収集、 問題がないか検証を行ってGPUに命令を伝える • GPUが処理できる“コマンド”を生成 • これはCPUが行うので、ドローコールはCPU負荷となる
描画パス • 同じような描画設定で発行される複数のドローコールをまと めたもの – 例えば、モデル、パーティクル、UIはそれぞれに描画設定が異な るので、すべて描画した場合は3パス – モデルでも、背景モデル、キャラクタモデルを別々に描画してパ スを分けることもある • 描画レイヤーとも呼ばれる – 同じモデルでも描画する属性の違いによりパスは分割される • トゥーン系レンダリングで、カラーの描画とアウトライン用背面モデ ルの描画を別のパスとして考えることもある
Forward Rendering • Traditional Forward Rendering – 従来タイプの手法は区別するためにこのように呼ばれる • 通常、モデル中の各マテリアルを1ドローコールで描画 する手法 – ピクセルシェーダでライティング/シェーディングを行う – シャドウマップを描画する場合はドローコールが増える • 不透明と半透明で同じシェーダが使用できる – 違いはRTに描き込む際のブレンド設定
Forward Rendering 頂点シェーダ スクリーン空間に変換 ラスタライザ 塗るピクセルを選択 ピクセルシェーダ 色を塗る レンダーターゲット(RT)
Forward Rendering 頂点シェーダ スクリーン空間に変換 ここでライティング/シェーディングを行う ラスタライザ 塗るピクセルを選択 ピクセルシェーダ 色を塗る レンダーターゲット(RT)
Forward Rendering • PS2までは主流の方法 – ハードウェアの制約上、この手法しか取れなかった – 現在のハードウェアでは3DSがこの手法しか使えない – 日本のゲームではPS3でも主流だった • 使用可能なライト数に制限がある – これも主にハードウェアの制約による – 固定シェーダの頃はライト数がハード固定 – プログラマブルシェーダでもシェーダに渡せるパラメータ数に 限界があった
Deferred Rendering • PS3中期くらいから使用されだした手法 – 現在ではほぼ主流と言っていい • 1回のドローコールでG-Buffer(Geometry Buffer)にモデル のジオメトリ、マテリアル情報を描き込む – この段階ではライティング/シェーディングは行わない – すべてのメッシュをG-Bufferに描画したらライティングを行う • ライティングパス – ジオメトリパスでライティング結果を求めず、遅延(Deferred)さ せてライティングを行うのでこう呼ばれる
Deferred Rendering • G-Bufferの例 – – – 画像はUE4のG-Buffer 実際にはこれより多くの情報が描画されている 情報が圧縮されて格納している場合もある • • 少ないG-Bufferで多くの情報を格納するため 情報の使用時にデコードコストがかかる Base Color Roughness World Normal Depth
Deferred Rendering 頂点シェーダ スクリーン空間に変換 ラスタライザ ここが… 塗るピクセルを選択 ピクセルシェーダ 色を塗る レンダーターゲット(RT)
Deferred Rendering 頂点シェーダ スクリーン空間に変換 ラスタライザ こうなる 塗るピクセルを選択 ピクセルシェーダ 色を塗る レンダーターゲット(RT)
Deferred Rendering • メリット – – • 光源を多く使用できる G-Bufferの情報をあとで利用できる デメリット – – – – 半透明が弱い MSAAが使えない シェーダのバリエーションを多く出来ない 描画レイヤーなどの自由度が低い
レンダリング手法Q&A
Deferred Renderingが 昔は使われなかったのはなぜ?
Deferred Renderingの歴史 • 元になったのはSIGGRAPH 1988の論文 – Michael Deering氏による – この時はDeferred Renderingとは呼ばれず、G-Bufferも使ってい ない • G-Bufferに言及した論文はSIGGRAPH 1990の論文 – 斎藤隆文氏、高橋時市郎氏による – この時もDeferred Renderingとは呼ばれていない • 実際に使われ始めたのはPS3/Xbox360世代 – 最初の商用ゲームは『Killzone2』? – なぜこの世代まで使われなかったのか?
Deferred Renderingが使われなかった理由 • 固定シェーダでは実装が難しい – G-Bufferに適切な情報を適切な形で描画できない – G-Bufferから適切な情報を適切な形で取得できない – ピクセルシェーダの実装は初代Xbox • この世代以降なら使える? • 複数のG-Bufferに描画する機能がない – 1回のドローコールで描画可能なRTは1枚だった – 複数のG-Bufferに描画するには複数回のドローコールが必要 – マルチレンダーターゲット(MRT)の実装
マルチレンダーターゲット(MRT) • 1回のドローコールで複数のレンダーターゲットに同時 に描画を行う機能 – PS3/Xbox360世代以降のGPUに追加された機能 • PS3/Xbox360世代は最大4つ • 現在のハイエンドGPUはもっと多い – 同じ解像度のバッファに、同じスクリーンに投影したポリゴン のみ使用できる • 例えば画面4分割をMRTで処理するとかは出来ない – カメラが違うのでスクリーンが違う
マルチレンダーターゲット(MRT) RT枚数に関係なく1回 頂点シェーダ ラスタライザ RT1 ピクセルシェーダ RT2 ピクセルシェーダで 複数のRTに出力 RT3
Deferred Renderingが使われなかった理由 • 日本のゲームにはDeferredは合わないと言われていた – DeferredのデメリットがPS2時代の日本のゲーム作りと合ってい なかった • 特に半透明問題は顕著 – CEDEC 2010のパネルディスカッションでも話題に上がっていた • ここでも日本のゲームに合わないと言われていた • しかし、現在は多くのゲームが採用 – バイオハザード7 – ファイナルファンタジー15 – UE4採用タイトル など
おまけ • PS3になって半透明がすごく遅くなった PS2世代の作り方をするとパフォーマンスは出ない – PS2のメモリ帯域は化け物級 • 48GB/s • PS3が22.4GB/s、PS4が176GB/s – GPU↔バッファ間のやり取りが速い – 半透明はバッファを読み込み、半透明計算後に書き込み – その上解像度は低い • 320x240 • PS3が720p、PS4が1080p • PS3の1/12、PS4の1/27
Deferred Renderingで 多光源を扱えるのはなぜ?
多光源が使える理由 • 現行のGPUではForward Renderingで多光源を扱えない? – ハードウェア的制約は存在しない • 十分な数のライトパラメータをシェーダに送れる – しかし、Traditional Forward Renderingで多光源を扱うことはほ とんどない • では何が問題? – 比較する前に各手法のライティング戦略を知ろう
Forward Renderingのライティング戦略 • シーン内の光源の中から影響を受ける光源を選択する – バウンディングボックスとライトの接触判定 • • – 赤の球が接触しているポイントライト 緑の球は接触していないのでシェーダに送られない より詳細な衝突判定は? • CPUとGPUのコストバランスによる
Forward Renderingのライティング戦略 • ピクセルシェーダでモデルをライティングする – ラスタライザで選択されたピクセルすべてにおいて、 すべてのライトとの計算を行う • 緑のピクセルはどのライトとも接触していない しかし、計算処理は行われる
Forward Renderingのライティング戦略 • 無駄なピクセル処理が多すぎる – – – バウンディングボックスに接触しているが実際のモデルに接触していない 光源 影響を与えるピクセルが極小の光源 光源と一切接触していないピクセル 境界箱に接触しているので選択される しかし効果範囲外なので影響は受けない しっかりとライトの影響を受ける が、描画されるピクセル数は多くない 影響がない範囲のライトは選択されない ライトの影響を受けるがほんのちょっとだけ これらのピクセルはライトの影響を受けない
Deferred Renderingのライティング戦略 • 基本戦略 –ライトの形状に合わせたオブジェクトを描画する • 深度テストを行って描画する • 描画された範囲がライトの影響範囲とみなすことが出来る –ステンシルマスクを使うことで影響範囲はより正確に • ライト形状オブジェクトの裏面を描画する • この際にステンシルバッファの値を1に設定 • 表面を描画する際にステンシルバッファが1ではない部分を描画 • 正しい範囲のピクセルのみライティングできる
Deferred Renderingのライティング戦略 このようなシーンを想定
Deferred Renderingのライティング戦略 ポイントライトの範囲は球
Deferred Renderingのライティング戦略 ポイントライトの範囲は球 裏面のみ描画
Deferred Renderingのライティング戦略 裏面のみ描画
Deferred Renderingのライティング戦略 描画されたピクセルのみステンシル値が”1”
Deferred Renderingのライティング戦略 表面描画が行われ、ステンシル値が”0”の 描画されたピクセルのみステンシル値が”1” ポイントライトの範囲は球 裏面のみ描画 ピクセルが描画される
Deferred Renderingのライティング戦略 最終的に計算されるライティングポイント
Deferred Renderingのライティング戦略 • ディレクショナルライト – – シーン全体に影響を与えるライティング 画面全体を覆う板を描画し、画面内のすべてのピクセルでライ ティング計算を行う このように画面全体を覆う板を描画する 画面すべてのピクセルでシェーダが動作する そのピクセルシェーダ内でライティング計算を行う
Deferred Renderingのライティング戦略 • ポイントライト、スポットライト – 影響範囲を示すメッシュを描画する • – 球、コーン 減衰なしだと無限範囲になってしまうので注意 ポイントライトなら球、スポットライトならコーンを描画 深度テストを行い、描画されたピクセルのみ計算する 特殊な形状のライトも効果範囲を示すモデルで対応できる →CEDEC2010 「Eidosの最新ゲームエンジン詳解」参照
Deferred Renderingのライティング戦略 • IBL(キューブマップ) – グローバルキューブマップならディレクショナルライトと同様 • – ローカルキューブマップなら範囲ボックスを描画 • – シーン全体に影響するため ポイントライト、スポットライトと同様 両方使いたい場合 • • • ローカルキューブを描画して、その範囲をマスク マスクされていない部分にグローバルキューブ描画 ブレンドしたい場合はもうちょっと工夫する必要がある
Deferred Renderingのライティング戦略 • 前述の方法はあくまでも一例 – エンジンによっては別の方法が取られていることもある • • 極小の光源が多い場合はスプライトで描画する手法も Deferredの戦略では不要なピクセルに対するライティン グ計算はほとんど行われない – ピクセルシェーダを軽くすることができる • – ほとんどのゲームではピクセルシェーダがネックになりやすい ライティング計算自体も軽い処理ではない • ピクセルシェーダが重くなる原因の1つ
Deferred vs Forward:多光源 • 実例:昔作ったサンプル – 1024個のライティングサンプルのフレームレート比較 Deferred – Forw ard 境界箱との接触判定なしだが、この数だと差が大きい
Deferred vs Forward:多光源 • ライティング計算を行うピクセルを減らす工夫が Deferred Renderingには存在する – – Traditional Forward Renderingでは不要な計算が多い しかし、現在は不要な計算を減らす手法が存在している • • • • Forward+ Rendering Clustered Rendering 詳細は後述 ライトの影響範囲が大きいと速度差は小さくなる – – 計算する必要があるピクセル数が近づくため Deferred Renderingの際にはライトの影響範囲に注意
Forward RenderingでG-Bufferは使えない?
G-Bufferの使用用途 • Deferred Renderingで作成するG-Bufferの使用用途は多岐 にわたる – – – – 通常のライティング計算 SSAO、SSRなどのスクリーン空間ライティング処理 アウトライン描画などのポストプロセス シェーディングモデルIDを調べて特殊なポストプロセス • • Screen Space Subsurface Scatteringなど Forward Renderingでは深度バッファとカラーバッファの み使用可能 – – 深度がわかれば位置もわかるので、これも使える Deferredに比べると使える情報は少ない
Forward RenderingではG-Bufferは使えない? • • NO! MRT自体はハードウェアの機能であり、Deferredでなけ れば使えないということはない – • ライティングを行うのと同時に別のバッファに必要な情報を出 力すればよい 実例:新生DOOM(Bethesda Softworks/id Software) – 不透明のForward Rendering時に2枚のG-Bufferを描画 • • – – Specular & Smoothness Normal 薄いG-Buffer(thin G-Buffer)と呼んでいる ただし、実装はClustered Forward Rendering
Deferred Renderingはなぜ半透明が弱いのか?
半透明の問題 • 半透明は昔から問題だらけ – 描画順序の問題 • • • 誰もが一度は苦労する 通常はカメラから見て奥にあるものから描画していく 例:水に下半身が浸かっているクリスタルボーイ – – 処理負荷の問題 • • • • • 水とクリボー、どちらを先に描画します? 描画対象のRTから今のカラーを取得する 描画するカラーとRTのカラーをブレンド 描画対象のRTにブレンドしたカラーをコピー RTへのアクセスが2回発生する Deferredでの問題はこれらではない
Deferredでの半透明の問題 • そもそも半透明でブレンドされるべき色とは? – – – 描画する半透明オブジェクトの色 描画されるピクセルに描画済みの色 この2つをブレンド値とブレンド関数によってブレンド 1枚目のトライアングル 2枚目のトライアングル α=0.5 結果
Deferredでの半透明の問題 • そもそも半透明でブレンドされるべき色とは? – – – • 描画する半透明オブジェクトの色 描画されるピクセルに描画済みの色 この2つをブレンド値とブレンド関数によってブレンド 2つの色はライティング結果の色 – Forwardの場合はRTに描画する段階でライティング済み • – 2つの色はライティング済み Deferredの場合は?
Deferredでの半透明の問題 • モデルを描画する段階ではライティングされていない – • この段階ではブレンドができない ライティングパス後にブレンドする? – G-Bufferには1ピクセルにつき1つのジオメトリ/マテリアル情報 しか保存できない • – 不透明と半透明の同居はできない 不透明か半透明の情報はG-Bufferに存在しない • 双方のライティング結果を参照できない → 半透明に対して何らかの戦略が必要
Deferred Renderingの半透明戦略 その1 • 半透明だけForward Rendering – – 多くの描画エンジンで採用している手法 Forwardでも描画順序は不透明→半透明 • • メリット – – • この不透明描画部分のみDeferredに置き換えた印象 屈折表現が可能 半透明に関してのみ描画レイヤーの調整は比較的しやすい デメリット – Deferredのメリットは活かせない • • – 多光源の実装は難しい G-Bufferを使うポストプロセス対応が難しい シェーダが増える • 同じ処理でもForward用とDeferred用を用意する必要がある
Deferred Renderingの半透明戦略 その2 • ディザによるアルファ抜きを使う – – 16色時代のドット絵の半透明表現と同じ手法 時間軸方向にディザパターンを変えていけば穴が開いているだけには見えなくなる • – UE4ではDitherTemporalAAと呼ばれている • • http://monsho.blog63.fc2.com/blog-entry-148.html メリット – – – • この場合はTemporal AAを使う必要がある Deferred Renderingのライティング機能がフルに使用可能 ポストプロセスにも対応 戦略 その1と共存可能 デメリット – – 透明度が変化する状況に弱い Temporal AAによるゴースティングが目立つ • 動きの激しいVFXでは使用しづらい
Deferred Renderingの半透明戦略 その3 • 半透明を使用可能なDeferred Rendering手法を用いる – 代表例:Deep G-Buffer • • G-Bufferをレイヤー化する手法 Depth Peelingという手法で各ピクセルごとに異なる深度でレイヤ ー分けが可能 – • • http://marina.sys.wakayama-u.ac.jp/~tokoi/?date=20081123 半透明順番問題、SSAOの隠れた部分の精度問題にもある程度対応 できる レイヤー数分のG-Bufferが必要なのでメモリが厳しい – 2~3レイヤーが限界では? – 不透明レイヤー以外は薄いG-Bufferを使う手もあり
Deferred Renderingの半透明戦略 その4 • G-Bufferの段階でブレンドしてしまう – – • 正しい結果にはならない 使い道を限定すれば悪くない手法 代表例:バイオハザード7の水 – ベースカラーと法線を不透明物体に対してブレンド可能 • – 深度バッファは描き込む • – ブレンド値はそれぞれの要素ごとに設定可能 ライティングは水の位置を用いて行われる https://cedil.cesa.or.jp/cedil_sessions/view/1488
Deferred Renderingの半透明戦略 その5 • Order Independent Transparency (OIT)を使う – – 半透明の順番を正しく処理するための手段 リンクリスト方式なら各ピクセルの正しい情報を保持できる • • メリット – – • http://www.slideshare.net/hgruen/oit-and-indirect-illumination-using-dx11linked-lists 正確なライティングとブレンドが可能 半透明の描画順序問題も解消できる デメリット – – 屈折の対応は少し難しいか? 重すぎて使い物にならな…げふんげふん
Deferred Renderingの半透明戦略 その6 • パストレーシングを使う – – • メリット – – – • いわゆるレイトレ 半透明のみ、不透明はDeferredで ブレンドはかなり正確にできる 屈折にかなり正確に対応できる 実装は比較的やりやすそう デメリット – – ライティングは限定的にしないとリアルタイムは難しそう スプライトパーティクルに対応すると速度は厳しそう • ソリッドオブジェクト限定なら検証の価値はあるかも
Deferred Renderingの半透明戦略 まとめ • やはり、その1・2が安定して使いやすい – • その3・5は現在のハードでは難しい – • 今後の4K、8K解像度を考えるとより難しい印象 その6も速度的な問題は抱えそう – • デメリットもあるがほとんどの場面で対応できる スケーラビリティは確保しやすそうなので、実現可能性は低く ないと思う その4の可能性を探りたい – 条件と使いどころを限定すれば効果高いかも
Deferred RenderingでMSAAが使いたい!
MSAAとは? • Multi Sample Anti Aliasingの略 – – 各ピクセルに複数個のサブピクセルを設定し、それぞれにピク セルシェーダの結果を格納する手法 Super Sampling Anti Aliasing (SSAA)の簡易版
MSAAとは? ・MSAAなしの場合 ピクセル中心がポリゴン内部に存在するかどうかで そのピクセルを塗るかどうか決定される
MSAAとは? ・MSAAありの場合 ピクセルに複数のサブピクセルが存在し、ポリゴン内部 に1つ以上のサブピクセルが存在すると描き込まれる
MSAAとは? • もう少し詳しく処理を見ていく – RTと深度バッファはサブピクセルの数だけバッファサイズが倍率 されている • – 各ピクセルではピクセルシェーダの起動は一度だけ • • – サブピクセルを複数内包していても一度 SSAAの場合はサブピクセルごとにピクセルシェーダが起動する 内包されているサブピクセルすべてにピクセルシェーダの出力を 保存する • – 4xMSAAの場合、4倍のバッファが取られる 内包していないサブピクセルには格納されない すべての描画が終わった後、すべてのサブピクセルのカラーの平 均を求める • リゾルブ処理
MSAAが使えない理由 • なぜDeferredではMSAAは使えないのか? – 使えないわけではない • – G-BufferをすべてMSAA用に変更する必要がある • – • Forward+MSAAの場合は1ピクセルにつきライティングは一度 Deferred+MSAAの場合は1ピクセルに付きライティングはサブピクセル 分の回数 ライティングした後にリゾルブ • – 4xMSAAの場合はすべてのG-Bufferが4倍 ライティングはサブピクセル単位で行わなければならない • – 単純に費用対効果が悪すぎるだけ 半透明のブレンドと同じで、ライティング後のカラーでなければリゾ ルブできない SSAAとほとんど変わらない
Deferredで使えるAA手法 • ポストプロセスAA – – – • FXAA、MLAAなど FXAAは特に軽量なのでよく使われる サブピクセルの処理はされないので細い物体の接続が切れる問題 が発生しやすい Temporal AA – – – 時間軸方向にサブピクセルを増やしていく方法 現行世代の標準的なAA技法となっている 激しい動きや半透明部分でゴースティングが発生しやすい • – 前のフレームの情報が激しく残ってしまう問題 最近、SMAAがちょっと話題 • Temporal AA+MLAAのような技術
Deferred Renderingで描画の 自由度を高めるにはどうすればいい?
描画の自由度 • ゲームにおけるレンダリングの自由度とは? –シェーダの自由度 • オブジェクトの種類に合わせたシェーディングモデル • 金属、髪、肌、水など –描画順序の自由度 • 描画レイヤーによる柔軟な描画順序 • 背景→背景エフェクト→キャラ→キャラエフェクト→特殊半透明 –ライトの自由度 • 特定のキャラだけ影響を与えるライト –いわゆる女優ライトとか
シェーダの自由度 • シェーディング手法はいろいろ –拡散反射:Lambert、Oren-Nayar –鏡面反射:Blinn-Phong、Ward、GGX –髪:Kajiya-Kay、Marschner –肌:Pre-Integrated Skin、Separable Subsurface Scattering –NPR:Cell-Shading • Deferredではライティングパスで処理される –基本はG-Bufferにシェーダの種類を格納しておく –ライティング時にその情報からシェーダ内で分岐
シェーダの自由度 • PS3/Xbox360世代はシェーダ内の分岐が非常に遅い – 分岐するより、2種類の計算を行って0 or 1でブレンドする方が速い くらい – Forwardなら特定の計算を行うシェーダに切り替えるだけ • シェーダ数が爆発的に増えるが、動作は高速 – 特殊なシェーダは半透明じゃなくてもForwardで実装していた • PS4/XboxONE世代では普通に使えるくらいに速い – 階層の深い分岐・ループはパフォーマンスが悪化しやすい – シェーディングモデルが多いとパフォーマンスが悪化しやすい • シェーダ命令数が増えてしまう
シェーダの自由度 • 高速化例:Uncharted 4 –16x16のブロック単位で使用されるマテリアルをカウント –すべて同一のマテリアルならこのブロックでは単一マテリアル 用のシェーダを使用する –ライティングはコンピュートシェーダを使い、DispatchIndirectで GPU側からシェーダの選択を行う –20~30%高速化したらしい –詳しくはSIGGRAPH 2016「Deferred Lighting in Uncharted 4」を参 照 • http://advances.realtimerendering.com/s2016/s16_ramy_final.pptx
描画順序の自由度 • 通常の描画順序は不透明→半透明→ポストプロセス –ForwardでもDeferredでも同じ • しかし、こういう場合はどうする? –背景のみに適用したいポストプロセスがある –キャラクタの背後にのみ表示されるパーティクルエフェクトが ある • こんな時こそ描画レイヤーの出番
Forward Renderingにおける描画レイヤー • Forward Renderingでは描画レイヤーを分けるのは簡単 –レンダリング時点でライティングカラーが求められているため • 例えば –背景不透明/半透明→背景エフェクト→キャラ不透明/半透明 →キャラエフェクト→手前背景半透明→ポストプロセス • 割とよくある3Dゲームのレイヤー –奥側背景不透明/半透明→キャラ不透明/半透明→エフェクト →手前側背景不透明/半透明→ポストプロセス • 横スクロールゲームのレイヤー
Deferred Renderingにおける描画レイヤー • Deferredではライティングパスが終わるまで半透明ブレ ンドできない –半透明でも解説した通り • 同じようなことをDeferredで行うと? –背景不透明→背景ライティング→背景半透明→背景エフェクト →キャラ不透明→キャラライティング→キャラ半透明 →キャラエフェクト→ポストプロセス • ライティングパスが不透明パスの数だけ必要! • ライトの数が多いとコストが高くなる –Deferredの多光源の意味が薄れる
Deferred Renderingにおける描画レイヤー • 現実的な方法 – 不透明は背景・キャラ関係なくすべて描画 • ただし、レイヤーごとにステンシル値を入れる – 半透明・エフェクトを描画する際に必要なステンシルでマスク • 背景エフェクトなら背景のみに描画されるようにする – この方法では背景のみのポストプロセスが難しい • キャラ不透明で隠れてしまう部分が出てくるため • Deep G-Bufferを使う – より良い方法だが現実的かどうか疑問 • レイヤー数による
ライトの自由度 • 特定キャラ、もしくはレイヤーにのみ影響があるライト – アクションゲームなのでキャラを目立たせたいとか – カットシーン中の女優ライトとか • ライトマスクを利用する – G-Bfferにライトマスクのチャンネルを用意する – 不透明描画時に影響を受けるライトチャンネルのフラグを立てる – ライティングパスでライトチャンネルをチェック – 4ビットくらいでたいていなんとかなる • 背景、キャラ、主人公、特殊
Deferred ShadingとDeferred Lighting その違いは?
Deferred ShadingとDeferred Lighting • Wikipediaより –https://ja.wikipedia.org/wiki/遅延シェーディング –遅延ライティング(Deferred Lighting) • ALAN WAKE • Halo:Reach など –遅延シェーディング(Deferred Shading) • KILLZONE 2, 3 • Battlefield 3 など –Deferred Shadingは多量のメモリを使用するため人気がない • えっ、ほんとう?
Deferred ShadingとDeferred Lighting • そもそもこの2つの違いは? – 使い分けてない場合もあるのではないか? – Light Pre-Pass Renderingと名乗る場合は明確に別 • Light Pre-Pass Renderingとは? – 各ピクセルにおける光のエネルギーの総量をライティングパスで求 める方法 – 描画パスは2パスではなく3パスで行う • G-Buffer描画、ライティング、シェーディング – シェーディングパスはモデルをもう一度描画する • ライティングパスで求めた光の強さとマテリアル情報からシェーディ ングの結果を求める
Light Pre-Pass Rendering • ライティングパスの計算 – Lambertの拡散反射 1 𝜋 • 𝐶𝑑𝑖𝑓𝑓 = 𝐶𝑚𝑎𝑡𝐶𝑙 (𝑁 ∙ 𝐿) • 𝐶𝑑𝑖𝑓𝑓 = 𝐶𝑚𝑎𝑡 𝐶𝑙1 𝑛 1 1 𝑁 ∙ 𝐿1 + 𝐶𝑙2 𝑁 ∙ 𝐿2 + ⋯ 𝜋 𝜋 1 = 𝐶𝑚𝑎𝑡 𝐶𝑙𝑖 𝑁 ∙ 𝐿𝑖 𝜋 ① 𝑖=0 ② – 𝐶𝑚𝑎𝑡 はマテリアルカラー → マテリアルに依存 – それ以外の部分は法線、座標とライト情報がわかっていれば求めら れる
Light Pre-Pass Rendering • G-Bufferには法線のみ描画 – シーンの形状はこれで求められる • ライティングパスでは前述の式の②だけ求める – これをライティングバッファに保存する – 各ライトごとに加算していけばいいので、ライティングバッファの ブレンドは加算合成 – スペキュラは強度のみ保存 → 詳しくは後述 • シェーディングパスでもう一度モデルを描画 – この際にライティングバッファの情報を取得 – 前述の式の通り、マテリアルカラーと乗算して求められる
Light Pre-Pass Rendering • Deferred Shadingに対するメリット – G-Bufferは法線のみなので1枚で済む – 光のエネルギーに対してマテリアルがどう反応するかをシェーディングパ スで決定できる • シェーダを切り替えることで様々なマテリアルを表現可能 – PS3/Xbox360世代でもMSAAと併用できる • Deferred Shadingほどバッファサイズが増えない • Deferred Shadingに対するデメリット – 描画パスが増える • Z Pre-PassをG-Bufferパスと一緒にすればさほど問題はない – スペキュラ成分の計算が不正確 • PBRでは最大の問題
Light Pre-Pass Renderingのスペキュラ成分 L-Buffer 1 Diffuse R Diffuse G Diffuse B Specular • Light Pre-Pass Renderingの発表当時のL-Buffer – Diffuse RGBは前述のLambert式の② – Specularはスペキュラ強度 • 例:Blinn-Phong • 赤枠内をライティングパスで計算したい
Light Pre-Pass Renderingのスペキュラ成分 • RGB 3チャンネルを保存できない – Specularに割り当てられているのは1チャンネルのみ – ライトカラー𝐶𝑙𝑖 をあらかじめ計算式に入れられない – Diffuse RGBからライトカラーの総和を推定する or ライトカラーを考慮しない • 𝑝はマテリアルのパラメータ – スペキュラの鋭さを指定するパラメータ – 定数にする or (σ(𝑁 ∙ 𝐻𝑖 ))𝑝 の計算式で対応 – どちらの手法でも相当問題あり
Light Pre-Pass Renderingのスペキュラ成分 • Cook-Torranceモデルではより問題は複雑に 𝐷∗𝐺∗𝐹 𝐼= 𝑁∙𝑉 • フレネル項(F項)を考える 𝐹 = 𝐹0 + 1 − 𝐹0 1 − 𝐿 ∙ 𝐻 5 • マテリアルパラメータとライト情報から求められる値を分離 できない – 𝐹0 はマテリアルパラメータ – 𝐿 ∙ 𝐻はライト情報から求められる値 • 分布関数(D項)もラフネスなどのマテリアルパラメータが影響 する
Light Pre-Pass Rendering • 多分、もう使われていない技術 –PBR全盛の今ではスペキュラが不正確すぎて使えない –L-Bufferを求める段階でライティング計算が決まってしまうので、 髪、布、肌、金属といったライティング計算自体が違うマテリ アルに対応できない –大量のオブジェクトを使用するシーンではジオメトリ描画を2回 行うのはコストが高い • Z Pre-Passと同時にG-Bufferを描画すれば少しはマシだが… • PBRを使わないゲームならまだ使えるかも…
Z Pre-Passって何?
Z Pre-Pass • 不透明描画パスにおいて、あるモデルが別のモデルに隠 される場合がある このピクセルでは後ろの赤い板は前面のグレーマンで隠される • 不要なピクセルのピクセルシェーダは起動したくない –しかし、ピクセルシェーダは起動してしまう
Z Pre-Pass • 理由その1:描画順序 – 手前のグレーマンが描画された後に赤い板が描画されるなら隠され ることがわかる – しかし、赤い板から描画してしまうとグレーマンがどこに描画され るかわからない – では、手前の不透明モデルから描画すればいい? • 理由その2:深度テストの処理順序 – 描画パイプラインは以下のようになる 頂点シェーダ ラスタライザ ピクセルシェーダ 深度テスト –ピクセルシェーダの方が先に処理される! 描き込み
Z Pre-Pass • Early Depth Stencil Test –ピクセルシェーダよりも前に深度テストを行ってしまう機能 頂点シェーダ ラスタライザ 深度テスト ピクセルシェーダ 描き込み – 深度テストを行う段階で深度バッファへの書き込みも行う – 現代のGPUではこの機能を有しているものが多い – 使用の際に注意しなければならない場合がある • ピクセルシェーダで深度値を修正する場合 • アルファテストを行う場合 • UAVを使用する場合 • 詳しくはCEDEC 2016「Unreal Engine 4のレンダリングフロー総おさらい」参照 – http://www.slideshare.net/EpicGamesJapan/cedec2016-unreal-engine-4
Z Pre-Pass • Early Depth Stencil Testを最大限に活用する –手前から奥にモデルを描画するだけで対応できる? • 同一モデル内では効果がない このピクセルは左手・左足・右足が描画されている 同一ドローコールなので、左手のポリゴンが先に 描画される保証はない –細かくドローコールを分ける? • ドローコールが増えすぎてCPU負荷が高くなる • 描画順序のソートもタダではない
Z Pre-Pass • 重いピクセルシェーダが動く前に深度バッファが生成されて いればいい – これがZ Pre-Pass • 描画の開始時に深度バッファだけを描画する – ピクセルシェーダは基本的に起動しない • 深度値の修正、アルファテストをする場合のみ起動 • ドローコールが2倍になって重くならないか? – Forward Renderingではほとんどの場合で効果絶大 – Deferred Renderingでは状況による? • 経験上、Z Pre-Passを使った方が高速 • ドローコールが多すぎる場合にCPUコストが大きくなる恐れ
Tile-based Renderingとは?
Tile-based Rendering • Deferred Renderingのボトルネックは? – 1つのライトが影響を与えるピクセルすべてでピクセルシェーダが 起動する – ピクセルシェーダ1回の処理ごとに1回のG-Bufferアクセスが発生す る • 複数ライトが1つのピクセルに影響を与えた場合、 G-Bufferサンプリングはライトの数だけ発生 • サンプリング回数が増えるとメモリ帯域を大量に消費 – 同一ピクセルでのG-Bufferサンプリング結果は同一 • 無駄なサンプリングは減らしたい • Tile-based Deferred Rendering誕生
Tile-based Deferred Rendering • 図のようなフラスタムを仮定する
Tile-based Deferred Rendering • 図のようなフラスタムを仮定する • スクリーンをタイル状に分割する –タイルの大きさは16x16ピクセルなど
Tile-based Deferred Rendering • 図のようなフラスタムを仮定する • スクリーンをタイル状に分割する –タイルの大きさは16x16ピクセルなど • タイルごとに小さなフラスタムが作成される
Tile-based Deferred Rendering • 図のようなフラスタムを仮定する • スクリーンをタイル状に分割する – タイルの大きさは16x16ピクセルなど • タイルごとに小さなフラスタムが作成される • タイルフラスタムごとにライトとの接触判定を取る • タイル内のすべてのピクセルで接触したライトを計算する
Tile-based Deferred Rendering • G-Buffer描画パス – 通常のDeferred Renderingと同様 • ライティングパス – ライト情報を配列としてバッファに保存しておく • シェーダからアクセスできるように – 画面すべてのピクセルに対してコンピュートシェーダを起動する • ピクセルが所属するタイル内の最大・最小深度を求める – これらがフラスタムの最大・最小深度となる • タイルのフラスタムとライトの接触判定を行う • 接触したライトの情報を共有メモリに保存する – コンピュートシェーダのスレッド単位で参照可能なメモリ • 各ピクセルが所属するタイルのライト情報を参照し、ライティング計算を行う
Tile-based Deferred Rendering • タイルの最大・最小深度を求め
Tile-based Deferred Rendering • タイルの最大・最小深度を求める 塗りつぶし範囲外のライトは計算不要
Tile-based Deferred Rendering • フラスタムとライトの接触判定 接触しているので計算される 最大・最小範囲外は計算されない
Tile-based Deferred Rendering • 接触したライトを共有メモリに出力 6 1 共有メモリ 4 2 7 2 3 5 –ここまでタイルごとの処理 8 3 4 5 6
Tile-based Deferred Rendering • ピクセルごとにライティング 共有メモリ 2 3 ライト情報 4 5 6 ライト 1 ライト 2 ライト 3 ライト 4 ライト 5 ライト 6 ライト 7 ライト 8 タイル内のすべてのピクセルにて ライティング!
Tile-based Deferred Rendering • この手法で高速化可能なのか? –条件によっては高速化するが、逆に遅くなることもある • ライティング計算を行うピクセル数は増える –図の赤のピクセルはライト計算の必要がない –深度方向でも同様の問題は発生する
Tile-based Deferred Rendering • G-Bufferのサンプリング回数は減る – 各ピクセルごとにG-Bufferのサンプリング回数は1回 • コンピュートシェーダは各ピクセルごとに1回しか起動しない • この1回で影響のあるライトすべての計算が終了する • 昔試したサンプルでの話 – 通常とTile-basedを比較すると、ライト数に大きく左右された – 数100のオーダーではTile-basedが有利 • 数10のオーダーでは通常のDeferredが有利 • 1024個の場合はTile-basedが圧倒的に速い(500fps→800fps) – ライトの影響範囲も関わってくる • 概ね、ライト数が多くなるとTile-basedの方が有利
Forward+ Rendering • タイルごとにライトをリストアップできるなら、 Forward Renderingでもそのリストを使用できないか? –AMD 原田隆宏氏らがEurographics 2012でForward+を発表 • https://sites.google.com/site/takahiroharada/storage/EG2012takahiroHa rada.pdf –また、後に同氏らによって改良版であるForward++が発表されて いる • https://sites.google.com/site/takahiroharada/storage/2012SA_2.5DCullin g.pdf
Forward+ Rendering • Forward+のレンダリングの流れ Z Pre-Pass タイルごとのライトリスト作成 Forward Rendering – Z Pre-Passは必ず行う • タイル毎のフラスタムサイズを最小にするため – ライトリストはリンクリストで保存される • 必要な情報はライトのインデックス番号のみ – Forward Renderingパスでは基本Early Depth Stencilを有効 • 余分なピクセルの計算を行わないため – 各ピクセルが所属するタイルのライトリストに従って 必要なライトの計算を行う • 通常のForwardより計算量は圧倒的に少ない
Forward++ Rendering • Tile-basedのライトカリングで最悪な状況とは? –タイルごとに最大・最小深度の差が大きい場合 –例:樹の葉、草など 手前の葉っぱと奥の壁までのサイズの タイルフラスタムが作成される • このような状況を回避するためにForward++が生まれた
Forward++ Rendering 計算不要なライト • 手前の木の葉の隙間から奥のオブジェクトが見えていると仮 定 – 図のようなタイルフラスタムが作成される – 真ん中付近のライトは不要なライトだが、計算が行われてしまう
Forward++ Rendering 0 1 2 3 4 5 6 7 • フラスタムを深度方向に32分割(図では8分割) –各セルに0~の通し番号を手前から割り振る
Forward++ Rendering 0 1 2 3 4 5 6 7 接触していないと判断されるライト • 深度の存在するセルとライトの接触判定を行う – ビット演算で比較的高速な判定が可能 • 接触したライトのみライトリストに追加 – 以降の処理はForward+と同様
Forward+ vs Tile-based Deferred • どちらが高速か? – Tile-based Deferredの方が高速な印象 • シーンによるかも • 以前作ったサンプルではTile-based Deferredの方が高速 • Forward+にはForward Renderingのメリットがある – デメリットである多光源もDeferredほどではないが十分高速に動作 する • 半透明に対してもライトリストは利用できる – ただし、その場合はForward++は利用できない • Forward+は採用事例が存在しない? – 自分が知る中では – 知ってる人がいらっしゃいましたら教えてください
Tile-based DeferredとForward+の共存 • Tile-based DeferredとForward+は共存が可能 –不透明はTile-based Deferred、半透明はForward+ • コンピュートシェーダでのライティングパスで、 ライトリストを共有メモリとバッファに出力 –共有メモリ側はTile-based Deferredで使用 –バッファ側はForward+で使用 • 某社のゲームエンジンで採用していたとか –残念ながらそのエンジンは日の目を見ていない…
Clustered Renderingって何?
Clustered Rendering • Tile-basedの改造版 – HPG 2012で発表された論文 「Clustered Deferred and Forward Shading」 • http://www.cse.chalmers.se/~olaolss/main_frame.php?contents=publication &id=clustered_shading – タイルより細かなクラスタという単位でライトリストを生成 • タイル分割した後、深度方向にフラスタムを分割 • 各ピクセルの深度情報からクラスタに割り当て • クラスタごとにライトリストを作成 • 実際にはデータ圧縮など、ちょっと複雑な手法を採用している – Deferred、Forwardの両方に対応できる – 100万光源をリアルタイムに処理できる
Clustered Rendering • ゲーム向けの簡易な実装 –Avalanche StudiosのEmil Persson氏がサンプルを公開している • http://www.humus.name/index.php?page=Articles&ID=7 –同社の『Just Cause 3』で実装 –日本では『バイオハザード7』で使用されている • https://cedil.cesa.or.jp/cedil_sessions/view/1488 –フラスタムを3次元に分割してクラスタを作成する • ピクセルをクラスタに割り当てる前にライトリストを作成する • ライトリストを使ってDeferred or Forward Rendering • ライトリストは半透明にも使用可能
Clustered Renderingの実装 • フラスタムを3次元で分割 –スクリーン平面は一律に分割 • 通常のタイル分割 –深度方向は対数分割 • 一律分割より効率が良い • ライトとクラスタの接触判定 –深度バッファやG-Bufferは不要 • 非同期コンピュートで ラスタライザと並列動作可能
Clustered Renderingの実装 • ライトリストの作成方法 – Forward+と同様のリンクリスト • アトミック操作が頻繁に発生 –複数スレッドでの同期操作のようなもの • ライト数を柔軟に変更できる • バッファサイズが確定しづらい – ライトインデックスに対応するフラグ操作 • Emil Persson氏の実装 • ライトの最大数は固定され、あまり多く取り扱えない –バイオハザード7では512個まで • バッファサイズも固定されるので扱いやすい • 速度はリンクリストより(多分)高速
Clustered Rendering • Tile-basedとの比較 –Z Pre-Passを行わなくてもライトリストの生成が可能 • ただし、各種描画パスを高速化するためには行った方がよい –ライトリストのバッファサイズは大きめ • 深度方向にも分割し、それぞれのクラスタでライトリストを持つた め • Tile-basedの場合はタイル単位でしかライトリストを持たない –オープンワールドで比較的有利 • 奥行きのスケールが大きく、奥行方向に計算不要なライトが増えや すい
これからの話
これからの話 • 4k, 8k時代の到来 – PS4 Proでは4kに対応、来年末予定のScorpioも4k対応 PCはすでに4kでゲームが動いている • 8kも割と近い未来? • VR HMDへの対応 – PSVRの発売で一般化する可能性 – 解像度は両目を合わせるとフルHD以上 • その上、高フレームレートとその安定を要求される – スタンドアローンHMDも今後出てくる • Hololens, Sulon Q, Oculusの試作機など • PC接続のHMDよりスペックは低くなる?
これからの話 • Deferred Renderingで対応できる? –厳しくなってくる可能性が高い –Oculus社はVR用にUE4にClustered Forward Rendererを組み込んだ • 現在はEpic社が自らForward Rendererを組み込んでいる • まだ使うのは控えた方がいいらしいが… –4kになるとG-Bufferのサイズは4倍 • 消費するメモリ帯域も単純計算で4倍 –新しいレンダリング手法が求められている • 例:Visibility Buffer
Visibility Buffer • GDC Europe 2016で発表されたForward Renderer – 発表者はWolfgang Engel氏 • Light Pre-Pass Renderingを発表した方 • GPU Proの編纂者 • いろんなゲームエンジンのレンダリングに関わってるらしい –CryEngineとか – http://www.gdcvault.com/play/1023792/4K-Rendering-BreakthroughThe-Filtered • 4k時にDeferred Rendererの半分のバッファサイズで済む – 比較対象は現在のFrostbite Engine – 使用するバッファは32ビットのVisibility Bufferと頂点バッファ • 頂点バッファは解像度に依存しない
Visibility Bufferの実装 • Visibility Buffer生成パス –モデルを描画 –Visibility Bufferにそのピクセルに描画されたトライアングルの情 報を格納 • 論文によると –Alpha masked bit:1ビット –Draw ID:8ビット –Primitive ID/Triangle ID:23ビット
Visibility Bufferの実装 • シェーディングパス –Visibility Bufferの内容を取得 –トライアングル情報から座標、法線、UVなどを計算 –頂点情報内のマテリアルIDから必要なマテリアル情報を取得し、 シェーディングを行う • ライトの選択は? –Clustered RenderingかTile-basedで選択しておくと良い
Visibility Bufferの疑問 • デフォームするモデルはどうする? –ボーンによる変形、頂点ブレンドなど –コンピュートシェーダで変形したトライアングルを毎フレーム 生成する • 同じオブジェクトを大量に描画する場合は頂点バッファサイズが心 配 • テッセレーションは? –Visibility Buffer生成パスでトライアングルになっているので、こ れを頂点バッファに出力する?
Visibility Bufferの疑問 • マテリアルが参照するテクスチャはどうする? –マテリアル情報は構造体バッファを使えば対応できる –しかし、参照されるテクスチャはマテリアルによってまちまち • どうやってアクセスする? –サイズがすべて同じならテクスチャ配列で対応できそう • サイズがまちまちなら追加でMipLevel情報が必要かも • 長方形テクスチャがあると難しくなるのでは? –Tiled ResourceやBindlessテクスチャが使えるか?
Visibility Bufferの有効性 • 論文より • 速度面ではDeferredより高速 – ESRAMの制約があるXboxONEでも使用できる • サンプル公開するって話だったけどまだぁ?
これからの話 • パーティクル描画が重くなる – 高解像度では特に問題 • パーティクル量が増えると同じピクセルに何度も描画が行われる • 消費メモリ帯域アップ • ピクセルシェーダの起動回数アップ – 縮小バッファを使う • 4kに対する1/4縮小バッファは1080p • 現在でも1080pフルにパーティクル描画するの大変なのに… • ボリュームのあるパーティクルでは顕著に – 厚みを出すためにパーティクル量が増える – ライティングをして重厚感を出すため、ピクセルシェーダが重い
パーティクルの描画 • ピクセルシェーダを軽くしたい –特にライティング • Clustered Renderingのおかげで複数ライトが使えるようになった • 仕組み的には使えるが、速度的には使えない –ピクセルごとのライティング • 無理 –テッセレータを起動して分割頂点ごと • テッセレータを起動すると単純に重い –描画頂点単位 • 『ワンダと巨像方式』 • 現実的な速度になるが、法線マップが使えない
パーティクルの描画 • 新生DOOMの例 – テクスチャアトラスを利用してパーティクルライトバッファにライティン グ結果を描画 • パーティクルごとに重ならないようにバッファにアトラス化 • パーティクルライティングの結果をバッファに描画 – フレームバッファへの描画時にライティング結果を参照 • ライティングが解像度に依存しない • 下の画像は1パーティクルにつき64x64サイズ – http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/
これからの話 • レイトレで解決する未来 – レイトレが使用できると半透明、シャドウなど、様々な問題が一気 に解決する – しかし、まだ来ない • 解像度の影響が非常に大きいため、4k, 8kが厳しい • ソフトウェアレンダラの未来 – GPUが完全に汎用的になる • ラスタライザがハードで対応しない • 必要なレンダラは自分で作る – CEDEC 2008でTim Sweeney (Epic Games) が10年後の未来と言ってた • あと2年!
まとめ
まとめ • Deferred Renderingは全盛だけど万能ではない –欠点多い –しかし、多光源を扱う上では圧倒的に高速 • Traditional Forwardでは逆立ちしても対抗できない • 最近は多光源を扱えるForward Renderingも登場 –Tile-based, Clustered –速度だけを考えるとDeferredの方が速いかも • Forwardの特徴を活かせる利点とのトレードオフ
まとめ • 4k, 8kへの対応は近い将来、確実にやってくる –4kはもう対応し始めなければならない –8kも割と近いかも? • VRへの対応も必要 –両目用の映像を別々に生成しなければならない –立体視特有の問題もある –高フレームレートを維持しなければいけない
まとめ • 他にも考えなければならないことも – Global Illumination – Shadow • 最終的に重要なこと – 自分が表現したいものに合わせて技術を選ぶこと • 表現したいものが曖昧だと適切な選択は難しい • すべてが決まっている必要はないが、軸がぶれるとあとで困る – 困ったらエンジニアに相談 • ~って出来る?と聞くのはあまりお勧めしない • こういう表現をしたい!と聞くとアイデアを出してくれることが多い