
Middle Earth:Shadow of Mordorは2014年に開始されました。 ゲーム自体は大きな驚きであり、それがロードオブザリング宇宙のストーリーのスピンオフであるという事実はまったく予想外でした。 ゲームは大成功を収め、執筆時点でMonolithはすでに続編-Shadow of Warをリリースしています。 Xbox 360やPS3など、さまざまな世代のコンソール用にリリースされたことを考えると、ゲームのグラフィックは非常に美しいです。 PCバージョンはかなり洗練されており、追加のグラフィックスオプションとゲームの可能性を完全に明らかにする高解像度のテクスチャパックが含まれています。
ゲームは比較的新しいDX11遅延レンダラーを使用します。 Renderdocを使用して、ゲームのレンダリングテクニックを深く学びました。 作業時には、可能な限り最大のグラフィックスパラメーター(ウルトラ)が使用され、順序に依存しない透明度、テッセレーション、画面空間のオクルージョン、さまざまなモーションブラーなど、可能なすべての「ローション」が含まれました。
フレーム
これが分析するフレームです。 プレイヤーはウドゥン地方の木製のプラットフォームにいます。 Shadow of Mordorは、Assassin's Creedのようなゲームのメカニズムに似たメカニズムを使用します。このメカニズムでは、建物やタワーに登り、屋上から周囲のデジタルランドスケープを楽しむことができます。

深さ通過
約140回の最初のレンダーコールは、最大の標高要素と建物を深度バッファーにレンダリングするための簡単な予備パスを作成します。 ほとんどのオブジェクトはこの予備パスに該当しませんが、ゲームに非常に多くのドローコールがあり、遠くを見ることができる場合に役立ちます。 興味深いことに、常に画面の中央にいて、画面スペースのかなりの部分を占めるキャラクターは、この通路に落ちません。 他の多くのオープンワールドゲームと同様に、エンジンは逆z値を使用します。 この手法では、近距離面を1.0にバインドし、遠距離面を0.0にバインドして、遠距離での精度を高め、zの競合を防ぎます。 Zバッファの精度についてはこちらをご覧ください 。

Gバッファー
その直後、約2700回の描画呼び出しで実行されるGバッファーの通過が開始されます。 キャッスルヴァニアの以前の分析:Lords of Shadow 2を読んだり、他の同様の記事を調べたりした場合、この文章はおなじみでしょう。 サーフェスのプロパティは一連のバッファに書き込まれます。これらのバッファは、ライティングの計算のパスで読み取られ、サーフェスのライトに対する反応を計算します。 Shadow of Mordorは従来の遅延レンダラーを使用しますが、この目標を達成するためにGバッファーの比較的少数のレンダーターゲットが使用されます(3)。 比較のために:Unreal Engineはこのパッセージで5〜6個のバッファを使用します。 Gバッファには次のスキームがあります。
通常のバッファー
R | G | B | A |
Normal.x | Normal.y | Normal.z | ID |
法線バッファは、法線を「8ビット/チャネル」の形式でワールド空間に保存します。 これは、滑らかに変化する平坦な表面を記述するのにかろうじて十分で、時にはまったくそうではありません。 よく見ると、これはゲームの水たまりに見られます。 アルファチャネルは、さまざまなタイプのオブジェクトをマークするIDとして使用されます。 たとえば、255はキャラクターを指し、128はフラグのアニメーション部分を指し、空はID 1でマークされていることがわかりました。これらの識別子は後で追加する段階でフィルタリングするために使用されるためです(空は独自の放射状のブルームを取得します)。


元の記事では、これらの画像や他の多くの画像はわかりやすくするためにアニメーション化されています。
バッファアルベド
R | G | B | A |
アルベド | Albedo.g | Albedo.b | 空洞閉塞 |
アルベドバッファには、アルベドの3つのコンポーネントすべてと、画面空間でのシャドウマップや後処理では達成できない小さなディテールをシェーディングするために使用される小規模オクルージョン(キャビティオクルージョンとも呼ばれます)が格納されます。 主に装飾目的に使用されます。たとえば、衣服の穴や折り目、木の小さなひび割れ、タリオンの衣服の小さな模様などです。


シェーダーで敵を処理するとき、アルベドは血液の質感を考慮に入れます(興味深いことに、タリオンは目に見える傷を負いません)。 血液テクスチャは、敵の衣服と身体のレンダリングフェーズへの入力ですが、血液の色は指定しません。これは、定数バッファーへの入力ですが、表示される血液の量を制御するための要因/血液レベルを決定します。 また、通常の方向を使用して効果をスケーリングし、血液の飛散の方向を制御できるようにします。 次に、アルベドは、敵が受けた傷の明るさによって本質的に陰影が付けられ、血液マップ上の対応する場所から取得され、鏡面などの他の特性も変更して、説得力のある血液効果を取得します。 マップがレンダリングされるフレームの部分は見つかりませんでしたが、剣が露出したときにフレームの最初に記録され、ここで使用されると想定しています。




鏡面反射バッファ
R | G | B | A |
粗さ | 鏡面強度 | フレネル | 表面下散乱係数 |
鏡面反射バッファには、ゲーム内で見ることができる他の表面特性が含まれます。例えば、粗さ(粗さではなく、鏡面度のスケーリングですが、このように解釈できます)、鏡面反射強度(鏡面反射の明るさ)正しいカラースペキュラ、反射係数(フレネルミラー応答への入力であるため、一般に文献ではF0と呼ばれます)および表面下散乱(表面下散乱)コンポーネントを取得するためのアルベド。 後者のコンポーネントは、薄い組織、植物、皮膚などの半透明の素材を照らすために使用されます。 後で照明シェーダーの研究に飛び込むと、Blinn-Fongに従って正規化された鏡面反射モデルのバリエーションを使用していることがわかります。




据え置きデカール
上で見たように、Shadow of Mordorは負傷したキャラクターにかなり詳細な血痕を表示します。 タリオンが剣を振るとき、環境はダークオークの血の一部も受け取ります。 ただし、別の手法が環境に使用されます- 据え置きデカール 。 この手法は、以前にレンダリングされたものの表面に一連のフラットテクスチャを投影することで構成されます。 このようにして、G-バッファのコンテンツは、ライティングパスを実行する前にこの新しいコンテンツに置き換えられます。 血の場合、血まみれのスプレーで十分であり、多くのデカールを順番にレンダリングすると、かなり暗い風景がすぐに作成されます。











Gバッファパッセージで最後にレンダリングされるのは空です。空のテクスチャはHDR BC6H形式で非常に高解像度(8192×2048)です。 HDRではすべての色が濃すぎるため、少し色調補正を行う必要がありました。

テセレーション
ゲームの非常に興味深い「機能」(オンになっている場合)はテッセレーションです。 地形からキャラクターのレンダリング(小道具やキャラクターオブジェクト)まで、さまざまな用途に使用されます。 ここでは、テッセレーションは低ポリゴンメッシュを細分割しませんが、詳細レベルの基準、たとえばカメラまでの距離に応じて、必要な細分割の度合いを使用して、ポイントクラウドからポリゴンを作成します。 興味深い例は、タリオンマントです。これは、ポイントクラウドとしてGPUに転送され(物理シミュレーション後)、テッセレーションシェーダーがポリゴンを再作成します。


順序に依存しない透明性

非常に複雑な特別なシェーダーを実行するため、その奇妙さで私を驚かせた最初のことの1つは、ヘアトリートメントパスです。 グラフィックオプションでは、髪のOIT(Order-Independent Transparency)オプションが言及されています。 まず、別のバッファーに出力を実行し、Gバッファーと同様の「深い」構造でプロパティを保存しながら、互いに重ね合わされた透明ピクセルの総数をカウントします。 後で、別のシェーダーが個々のフラグメントをその深さに従ってソートします。 矢印もこのようにレンダリングされるようです(おそらく、羽を適切に並べ替える必要があります)。 これは非常に微妙な効果であり、特別なグラフィックの違いはありませんが、それでも興味深い詳細です。 簡単な例を次に示します。上の画像は、重複するフラグメントの数を示しています(赤く、より多くのフラグメント)。 通常の透明度は引き続きCPUでソートされ、従来のアルファとしてレンダリングされます。 個々のエンティティのみがOITパスに分類されます。
モルドールの影
SoMには多くのシャドウソースがあります。 動的光源の従来のシャドウマップに加えて、SoMは、画面空間の2チャンネルアンビエントオクルージョン、ゲーム内のほぼすべてのオブジェクト用に作成されたマイクロスケールオクルージョン、およびトップビューの高さマップに似たオクルージョンテクスチャを使用します。
画面空間のオクルージョン

最初のパスは、画面スペースのGバッファアンビエントおよびスペキュラオクルージョンを使用してレンダリングされます。 シェーダー自体は、展開された巨大なサイクルであり、フルサイズの深度マップと、以前に削減された平均深度マップの両方をサンプリングし、特定のパターンで隣接するサンプルを探します。 4×4の正方形テクスチャを使用して、オクルージョンソースの検索で擬似ランダムベクトルを選択します。 ノイズの多いオクルージョンバッファーをレンダリングします。その後、2回のパスで単純なぼかしによって滑らかになります。 ここで最も興味深い機能は、2つの異なるオクルージョンチャネルがあることです。1つはスペキュラオクルージョンとして使用され、もう1つは拡散オクルージョンとして使用されます。 標準のSSAO実装では、ベイク処理されたすべての照明に適用される1つのチャネルが計算されます。 ここで、SSAOカードは、指向性照明通路への送信のために読み取られ、そこで使用されます。


シャドウカード
次のイベントは、シャドウマップのレンダリングです。 ゲームのアクションは主にオープンスペースで行われるため、ほとんどの光と影はメインの指向性ライトから取られます。 ここでは、 シャドウマップをカスケードする手法(バリエーションは平行分割シャドウマップ )を使用します。これは、長い距離にシャドウを適用するためのかなり標準的な手法です。これは、空間の異なる領域の光源の1つの視点から同じシーンをレンダリングすることで構成されます。 通常、カメラのカバレッジエリアから遠いシャドウマップは、遠い距離にあるか、以前のものよりも解像度が低く、ジオメトリが遠すぎるために詳細がまだ必要でないエリアの解像度を本質的に低下させます。 このシーンでは、ゲームは4096×4096の影のカスケードを3つレンダリングします(実際、ゲームには4つの場所があります)。 上部のカスケードはタリオンに非常に近く、下部のカスケードはカメラから非常に遠い山とオブジェクトを含みます。 シャドウを使用する場合、ゲームは深度マップと同じ逆z座標のトリックを使用します。

シャドウバッファー
次のステップは、シャドウバッファーを作成することです。 これは、以前のシャドウマップからのオクルージョン情報に基づいた単一チャネルテクスチャで、間隔[0、1]のシャドウファクターをエンコードします。 エッジの周りに滑らかさを作成するために、4つのサンプルを受け取り、それらを指定された値と比較する特殊なバイリニアサンプラーの状態を使用して、シャドウマップが4回サンプリングされます(これはPercentage Close Filteringと呼ばれます )。 複数のサンプルを取得し、その結果を平均化することは、多くの場合、 パーセントクローザーソフトシャドウと呼ばれます。 シャドウマップの読み取りに加えて、鏡面反射バッファの最後のコンポーネント(つまり、表面下散乱係数)もサンプリングされ、これに「ライトブリードファクター」が乗算されます。 これは、これらのオブジェクトからシャドウイングを除去して、もう少し多くの光がそれらを通過するために必要であると思われます。

方向投影テクスチャ
別の光源および影光源は、指向性光源によってサンプリングされたトップビューテクスチャです。 これは、指向性光源の色に追加される色かぶりと、指向性照明に適用されるグローバルシェーディングの効果です。 それらのいくつかは、トップビューで自動生成されたレベルライティングマップの上に手動で作成されたようです。 静的ジオメトリのシャドウのエッジは手動で調整され(おそらく実際のシャドウマップとの競合を避けるため)、一部の部分も手でわずかに色付けされているようです。 おそらく、このテクスチャのタスクは、指向性照明に加えて、大規模なアンビエントオクルージョンとライトグローバルイルミネーションシミュレーションを低コストで追加することです。 以下の画像は、両方の要因の色相、オクルージョン、および積を示しており、最終的なカラーマスクがどのように見えるかを示しています。



すべてのライティングパスの結果は、R11G11B10F形式のレンダーターゲットに保存されます。 結果は次のようになります。 結果の色調補正を実行して、レベルの指向性照明の効果をより見やすくしました。

すべての遠い山(上の画像には表示されていません)も指向性ライトで照らされていますが、照明をより適切に制御できるように、別のケースとしてハイライトされています。 いくつかはスケーリングされていますが、実際には巧妙に作成された法線マップとアルベドマップを持つ詐欺師です。 彼らは山にのみ影響する指向性照明の特別な光源を持っています。
静的照明
Shadow of Mordorは、非常に大きなボリュームテクスチャを使用する静的メモリの非常にメモリ集約型の実装を使用します。 以下の画像は、この領域の一部を拡散照明するために使用される照明量の3つの静的テクスチャを示しています。 これらはそれぞれ512x512x128 BC6Hの巨大な圧縮テクスチャです。つまり、テクスチャごとに32 MBまたは一般的に96 MBを占有します(最高品質の設定で再生します)。 色のテクスチャは、ボクセルに入る強度を示します。 他の2つは、xyzおよび-xyzの6方向すべてに沿ったこの強度の強度または大きさを示し、法線を使用して3つのコンポーネント(正または負のxyz、法線と最も一致するもの)を選択します。 このベクトルを作成したら、そのベクトル積を法線の2乗で計算し、これが強度のスケーリング係数になります。 式は次のとおりです。


静的ライトボリュームは、鏡面反射照明用の立方体マップもレンダリングします。これは、SLVの中心でキャプチャされる可能性があります。 興味深いことに、ボリュームテクスチャはBC6Hで圧縮されたHDR値を格納し、キュービックマップはBC3(DXT5)形式で格納され、浮動小数点値を格納できません。 この制限を補うために、アルファチャネルは明るさを保持し、その後1〜10にスケーリングします。 これは少し奇妙な決定であり、私にとっては、レガシー実装のように見えます。 ゲームは、新しいHDRテクスチャフォーマットをサポートしない前世代のコンソール用にリリースされたことを忘れないでください。

以下のフレームは、平均画像の影響を考慮して、「前後」の結果を示しています。 視覚化のために、色調補正を行いました。



大気の霧

Shadow of Mordorには天気と時間のシステムがあり、そのおかげでMordorのゲームでは太陽が輝いたり雨が降ります。 このシステムは、コンポーネントの合計によって制御され、最も重要なものの1つは霧です。 Shadow of Mordorは、単一のレイリー散乱、および球状粒子による散乱(三重散乱)を含む、大気霧のかなり単純だが物理的に健全なモデルを使用します。
地球の中心に対するカメラの位置を計算することから始めます。 いくつかの三角関数の式により、カメラが大気中のどこにあるのか、ピクセルがどこにあるのか、そして大気の所定の最大高さでビームが大気中をどれだけ移動するのかを決定できます。 この場合、大気は惑星の表面から65,000メートルの高さに設定されています。 この情報を念頭に置いて、レイリーと球形の粒子係数を使用して、霧とその色の両方のタイプの粒子密度を計算します。 これらの密度は、既にシェーディングされたピクセルを覆い隠し、シェーディングされた表面からカメラに入射する光を散乱させ、霧の原因となります。 このような散乱をシミュレートするとき、太陽の明るさと方向が考慮されます。


シャッタースピードとトーン補正
シャッタースピードを計算するとき、かなり標準的なアプローチが使用されます:メインHDRカラーバッファーから計算された輝度バッファーの解像度を、メインフレームバッファーの1/3のテクスチャで始まる、前のテクスチャの半分のサイズのテクスチャのチェーンに順次減らします。 この解像度の低下により、4つのサンプルが取得され、隣接するピクセルの値が平均化されます。つまり、すべての平均値を単一のテクセルに変換した後、最終結果は平均輝度になります。 テクスチャが16×9テクセルのサイズに達すると、計算シェーダーが起動され、残りのすべてのテクセルが合計されます。 この値は、明るさの値を変更するためにトーン補正パスですぐに読み取られます。






色調補正には、ラインハルト演算子が使用されます 。最適化された式は、 こちらとこちらにあります 。 hlslコードでは、これは次のようになります。
float3 hdrColor = tex2D(HDRTexture, uv.xy); hdrColor *= exposureValue; // This was calculated by the compute shader in the luminance downsampling pass float3 x = max(0.0, hdrColor - 0.004); float3 finalColor = (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
この曲線をプロットすると、この演算子は入力値が2.0であっても白の値の10%を破棄すると同時に、下部の間隔の一部を完全に黒のままにすることがわかります。 これにより、彩度の低い暗い画像が作成されます。

アルファステージ
アルファフェーズは、オブジェクトをLDRバッファに直接レンダリングするため、少し変わっています。 他のゲームもHDRバッファーにレンダリングして、シャッターパスに参加できるようにします。 場合によっては、以前に計算された輝度テクスチャはすべてのアルファ照明オブジェクトに制限されているため(たとえば、発光オブジェクトの場合、シャッタースピードはテクスチャ検索ではなくシェーダー定数を使用して計算されます)、したがって、レンダリング時にシャッタースピードが自動的に適用されます。後処理では実行されません。 ゲームでアルファを使用する非常に特殊なケースは、ゴーストモードへの移行です(このモードでは、セレブリムボールのゴーストがプレイヤーのキャラクターの上にレンダリングされ、LOTRユニバースソブリンリングで偽造されます。したがって、ゲームは、目に見えないが常に近くにいることを示します)。 ゲームは両方のキャラクターのメッシュにいくつかのパラメーターを渡します。これらのパラメーターは不透明度を制御し、ゲームがタリオンを部分的に覆い隠し、セレブリモアを徐々に表示できるようにします。 ゲーム内のゴーストモードの他のオブジェクトも、敵やタワーなどの不透明なオブジェクトの上にゴーストバージョンをレンダリングします。 これは幽霊の世界への移行の別のシーンです。




雨
調査したメインフレームでは、雨は降っていませんが、天気はゲームの非常に重要な部分なので、ここで言及したいと思います。 GPUで生成およびシミュレートされ、アルファフェーズの終わりにレンダリングされます。 シミュレーションを実行し、位置をバッファーに書き込むコンピューティングシェーダーが実行されます。 これらの位置は別のシェーダーによって取得され、インスタンス化された間接呼び出しの助けを借りて、前のパスで計算された位置と同じ数のクワッドのインスタンスをレンダリングします。 頂点シェーダーには単純なクワッドがあり、必要に応じて変形されてカメラに向かって回転します。 雨がサーフェスを貫通しないようにするため、頂点シェーダーはトップビューから高さマップも読み取ります。これにより、オーバーラップするサーフェスの下のすべてのドロップを拒否できます。 この高さマップは、フレームの最初にレンダリングされます。 同じ頂点シェーダーは、ピクセルシェーダーにドロップテクスチャからサンプルを取得する場所を指示します。 ドロップが表面に近い場合、スプラッシュアニメーションを含むテクスチャ領域を選択します。 さらに、雨滴はピクセルシェーダーでフォグ計算を実行して、シーンの残りの部分とシームレスにブレンドします。 これは、雨の日の同じ視点からのスクリーンショットです。


雨の効果がアクティブになると、鏡面反射バッファが全体的に修正されて濡れたサーフェスが作成され、雨の波が通常のバッファにレンダリングされます。 アニメーションのタイミングが調整されるため、ループアニメーションの1つのフレームのみが使用されます。 以下に示す通常のバッファーは、バッファーにレンダリングされる波を表示するように変更されます。




レンズフレアとブルーム
アルファレンダリングが完了すると、その上にレンズフレアがレンダリングされます。 一連のシフトされたクワッドは、指向性ライトの出所(この場合は太陽)からレンダリングされます。 この直後に、ブルームパスが実行されます。 これはかなり標準的な手法であり、一連のサイズを縮小し、明るさが特定のしきい値を超えるピクセルを含むぼやけたテクスチャで構成されます。 2つのブルームパスを使用します。これは、シーン全体のガウスぼかしと空にのみ適用される特別な放射状ぼかしで共通です。 放射状のぼかしは、空のピクセルのみが考慮されるため、法線マップのGバッファからの特別なIDを使用する操作の1つです。 ボーナスとして、このブラーは深度マップをサンプリングし、低コストのトワイライトレイを作成できます。 この段階ではLDRバッファーを使用しているため、ブルームしきい値の値はHDRカーペットの値とは異なります(通常、しきい値を超える値は1.0で計算につながります)。これは、そこから取得されるブルームの値がわずかに制限されることを意味します。 いずれにせよ、これはゲームに適しています。結果を以下に示します。 以下の画像では、ブルームミップテクスチャの色が少し奇妙に見えます。これは、各ピクセルがアルファチャネルに含まれる輝度によってスケーリングされるためです。 この明るさは、色調補正の段階で以前に計算されました。 最終合成では、ブルームはbloom.rgb・bloom.a・bloomScaleとして計算されます。















アンチエイリアス+被写界深度
これらの2つの操作については何も言うことはありません;業界標準のアプローチが使用されます。 FXAAアンチエイリアシングの単純なパススルーは、ブルームとLDRイメージを合成した直後に実行され、被写界深度はその直後に実行されます。 被写界深度については、ゲームは最終バッファの2つの縮小されたぼやけたバージョンをレンダリングします。 次に、ピクセル深度を使用して、ぼやけた画像と通常の画像を混合します。これにより、デフォーカスの効果が得られます。 わかりやすくするために、このキャプチャでは被写界深度の効果を誇張しました。 ゲームにはスクリーンショットモードが組み込まれているため、これらの条件を簡単に設定できます。







モーションブラー
モーションブラーは2つのパスで構成されます。 最初に、以前および現在のカメラの向きからのデータがフルスクリーン速度バッファーに転送されます。 この場合、テクスチャの2つのチャネルは、画面空間の速度で満たされます。 これで、チャネルrには画面の水平方向のピクセル変化の大きさが含まれ、チャネルgには垂直方向の大きさが含まれます。 これは、カメラを移動するときに放射状のストライプが取得される方法です。 キャラクターが再びレンダリングされます。今回は、カメラの場合のように、現在と以前の位置に基づいて青いチャンネルが塗りつぶされます。 青いチャネルは、レンダリングをレンダリングする必要があるかどうかを示すために使用されます。 アルファチャネルも一定の値(0.0598)で満たされていますが、その値や目標を調査していません。 速度バッファの解像度は、元のテクスチャの速度の比較的広い範囲で平均化することにより、非常に小さなテクスチャに低下します。 これにより、最後のパスで、実際のブラーパスでブラー半径がどの程度になるかを各ピクセルに概算できます。
ブラーパスは、速度テクスチャ、深度マップ、元のカラーバッファ、およびノイズテクスチャの両方を読み取ります。 後者は、鏡像の効果を隠すために使用されます。これは、大きな半径のこのタイプのぼかしで発生する可能性があります。 次に、画像バッファが速度バッファによって示される方向に数回サンプリングされ、色が平均化されます。これにより、動きベクトルの方向に画像がぼやけます。 また、この効果は、ゲームが機能するフレームレートに従ってスケーリングされます。 このキャプチャでは、ゲームを30fpsに制限する必要がありました。60fps以上ではほとんど目立たないからです。




色補正
色補正の最終パスは、「カラーキューブ」を使用して実行されます。 カラーキューブは、rgbコンポーネントがテクスチャのxyz座標にスナップする3Dテクスチャです。 これらのxyz座標には、元の色を置き換えるために必要な色が含まれています。 この場合、ルックアップテーブル(LUT)はニュートラルです(つまり、座標と色に同じ値が含まれています)。したがって、ゲームがカメラエディターで提供するプリセットを使用して同じシーンを変更しました。




最終フレーム
メインフレームを別のバッファーに作成した後、UIがレンダリングされます。 これにより、リアバッファーに選択されたサイズに関係なく、ネイティブウィンドウサイズでUIが常にクリアで美しいレンダリングになり、速度を確保するために必要に応じてゲームが解像度を変更できます。 最終的に、両方のテクスチャはUIアルファチャネルデータに基づいて混合され、最終フレームバッファーにレンダリングされ、画面に表示できる状態になります。


あなたが私の分析を楽しんだことを願っています。 この本当に忘れられないゲームのMonolithスタジオのスタッフだけでなく、グラフィックスを研究するようになった素晴らしい仕事をしてくれたAdrian Corregeに感謝したいと思います。