フォートナイト バトルロイヤル チャプター 4 で Nanite を活用

2023年1月26日
こんにちは、私は、Epic Games でエンジニアリング フェロー (グラフィックス担当) を務める Graham Wihlidal です。フォートナイト バトルロイヤル チャプター 4 で Nanite を導入するために、今年開発された優れた機能と改善点を紹介します。ここで紹介する機能は、Unreal Engine 5.1 で実際に(ベータ版として)お試しいただけます。

Unreal Engine 5.0 は、プロダクション対応の Nanite を搭載してリリースされました。Unreal Engine 5.0 ではすでに多くの優れた機能が使用可能ですが、この初期バージョンでは、Nanite を使用しないメッシュ向けに提供されている多数のすべての機能を完全にはサポートしていませんでした。代わりに、Epic では Nanite のコアの機能を向上させることに時間を費やしました。

今後は、Nanite がまだカバーしていない多くの領域にサポートを拡大していきたいと考えています。ワールド位置オフセット、ピクセル深度オフセット、カスタム UV、両面マテリアル、マスク付マテリアルなどの機能に対するサポートについては、ユーザーから強い要望がありました。今年の初めに、チームは要望されていた機能のいくつかをサポートするための実装に取り組む中で、多くの重要な問題を解決しなければなりませんでした。

GPU は、当初 固定機能パイプライン と呼ばれていた機能を採用していました。固定機能パイプラインはジオメトリのトランスフォーム方法と深度と色の書き込み方法がハードウェアにビルトインされおり、事前定義された限られた一連の関数を使用してのみ設定することができました。その後、ハードウェアがシェーダー コードによって「プログラム可能」になったことで、グラフィックスに新しい可能性がもたらされ、固定関数パイプラインでは困難または不可能だった機能を使用できるようになりました。

Nanite は当初から常に出力カラーを制御する「プログラム可能」なマテリアル グラフ シェーダーをサポートしていました。ただし、画面上の頂点の位置やトライアングルでカバーするピクセルを決定するラスタライザー自体は、事実上「固定関数」でした。つまり、ラスタライザー自体はシェーダー コードとして実装されていますが、コンテンツ クリエイターはそのロジックをコントロールすることができません。

これまでに述べた機能を Nanite でサポートするためには、ラスタライザー自体を プログラム可能 にする必要がありました。

最初のプロトタイプ

Epic では「Nanite Programmable Rasterizer」と名付けられたラスタライザーでマテリアル グラフ ロジックをサポートするために必要なアーキテクチャのプロトタイプの作成に着手しました。

次の画像は、Nanite を使用したゴミ収集車のメッシュでアニメートされているマスク付マテリアルの最初のプロトタイプです。
 
このプロトタイプでは、プログラム可能なラスタライザーが使用可能かどうかを実証することができました。ただし、プロダクション対応に向けて効率化するためには、まだ多くの作業が残っています。

Epic では、この作業の開発を推進するために、次のような明確な目標を定めました。
  • 既存の「固定関数」ファスト パスのパフォーマンス プロファイルを維持すること。プログラム可能なラスタライザーの導入により、既存のコンテンツの処理速度が低下しないようにする。
  • メンテナンスのしやすさを確保するため、固定関数とプログラム可能なラスタライザーのパスは、大半において同じコード パスを共有するようにする。
  • プログラム可能なラスタライザーは多くのコンテンツで多用されることを考慮して、シンプルなエバリュエーターは固定関数ラスタライザーより処理速度が若干低下するくらいのパフォーマンスを提供する。
  • インスタンス カリングとクラスタ カリング作業は一度のみ実行する。
  • GPU シーンと Nanite への追加メモリの影響を最小限に抑える。
  • これらを UE 5.1 のプロダクション対応機能として提供する。

最初のプロトタイプでは、シーン内で単一のプログラム可能なマテリアルのみをサポートするようにハードコード化されていました。そのため、次のステップは、何百ものマテリアルで構成される実際のゲーム シーンをサポートできるように適切なラスタライザーの「ビニング」パスをサポートしました。これによって実際のコンテンツをテストすることが可能になりました。
中世ゲームのショットはほぼすべて Nanite に変換されました!
Nanite トライアングルのビジュアライゼーション
シーン内の独自のラスタライザーの「ビニング」(マテリアル)。
中世ゲーム のテスト シーンでは機能しているものの、Nanite Programmable Rasterizer フレームワークをゲームに搭載するためには、最適化と機能拡張の作業が多く残されていました。

ごく初期の段階で、フォートナイト バトルロイヤル チャプター 4 で Nanite を活用したいという要望があることが判明していましたが、全面的な採用に必要な機能がまだサポートされていませんでした。不透明な建物の構成要素などの一見シンプルなメッシュでさえ、ダメージを受けたことを象徴する「バウンス」エフェクトをアニメートするためにワールド位置オフセットが必要だったのです。フォートナイトは、プログラム可能なラスタライザーを活用した最初のタイトルとなりました。

フォートナイトのユース ケース

アニメートされた小道具

サポートする最初のユース ケースは、ワールド位置オフセットを使用して二次的なアニメーションを行うシンプルな不透明なスタティックメッシュの小道具です。これらの小道具は効率的なレンダリングを行うために Nanite を必要としませんが、仮想シャドウ マップ のパフォーマンスは Nanite メッシュではより適切にスケールできるため、可能な限り多くのシーンを Nanite を使用してレンダリングすることが重要でした。


 

 

建物

フォートナイトの主要な特徴の 1 つは、多岐にわたる建物のセットですが、Nanite はすでに大都市を簡単に処理できることが実証されています。視覚的な忠実度を高め、LOD のポッピングをなくし、パフォーマンスを向上させるために、すべての建物のメッシュに Nanite を使用することを選択したのは当然のことといえます。
建築
フォートナイトには膨大な建物のメッシュが使用されているため、すべてのプラットフォームでそういったメッシュをすべて一からビルドし直すのは不可能です。そのため、アーティストが作成した変位テクスチャとルールを使用して、従来のバージョンよりもはるかに多くのトライアングルを備える高品質の変位された Nanite メッシュを生成できるオフライン プロセスを作成しました。

注:これは「ランタイム」ディスプレイスメントではなく、変位されたメッシュを作成するためのフォートナイト固有のオフライン ワークフローです。

プライマリ ビューのレンダリングの視覚的な改善に加えて、変位された Nanite メッシュにより仮想シャドウ マップの品質が大幅に向上しました。これは、レンガなどのジオメトリのディテール (以前はテクスチャ上の 2D のペイント領域として表現されていた) が、実際の 3D 空間に置き換えられるようになったためです。これにより、サーフェスの深度と詳細度が増し、セルフシャドウイングとシルエットが適切に生成されるようになりました。
 
フォートナイトの建物はすべて不透明なスタティックメッシュで、Unreal Engine 5.0 で使用可能な一連の Nanite 機能で完全にレンダリングすることができます。ただし、建物の構成要素がダメージを受けているとき (プレイヤーがツルハシで叩きつけるなど) に、一時的に発生する「ウォブル (ぐらつき)」エフェクトは除きます。

ウォブル (ぐらつき) は、マテリアルのワールド位置オフセットを使用して適用されるシンプルなアニメートされたトラックで、ぐらつきの発生が目に見えない場合 (ゼロ ウェイトが使用されている) でも、評価は常に実行されています。

フォートナイトには非常に多くの建物メッシュが含まれているため、このパターンをターゲットにした最適化を実装しました。この実装では、特殊なモード r.OptimizedWPO) を有効にすると、マテリアルにワールド位置オフセットを制御するロジックが含まれているかどうかにかかわらず、提供されたプリミティブ コンポーネントで [Evaluate World Position Offset (ワールド位置オフセットを評価)] が有効 (デフォルト設定) になっていれば、Nanite がこのロジックのみを評価するようになりました。
Nanite が前述の「ラスタライザー ビニング」パスを実行するときは、通常はプログラム可能なパスを使用しているものの、[Evaluate World Position Offset] が無効になっているすべてのプリミティブでは、代わりに標準の固定関数ラスタライザー パスを使用します。

この最適化は (遠景でのワールド位置オフセットの無効化など) 多くの場所で役立っていますが、建物のぐらつきにとっては必要不可欠でした。すべての建物メッシュで [Evaluate World Position Offset] をデフォルトで無効にし、建物が現在ダメージを受けているかどうか (およびぐらついているかどうか) に基づいて、この値をプログラムで設定するようにフォートナイトのゲーム コードを調整しました。
この新しい最適化にあわせて、メッシュが現在ワールド位置オフセットを評価している場合は緑色に、評価していない場合は赤色に表示される「Evaluate WPO」 Nanite デバッグ ビュー (r.Nanite.Visualize EvaluateWPO) を追加しました。
この最適化により、ほぼすべての建築メッシュは固定関数パスを使用します。ただし、少数のメッシュだけは、必要に応じて、プログラム可能なウォブル パスを使用します。
ショット例
r.OptimizedWPO がオフとオンの場合

樹木

プロトタイピングと開発で最も時間を費やした領域は、樹木です。チャプター 4 では、緑豊かな森林地帯を作りたかったので、予測可能なパフォーマンスで、効率的なソリューションが必要でした。また、樹木はこれまでタイトルで使用したことのない Nanite のまったく新しい機能を活用しています。そのため、最終的に採用するアプローチを決定するために多くのプロトタイピングと最適化を行いました。
建築
最初の実験では、樹木にマスク付マテリアルとカードを使用しました。
フォートナイトのコンテンツでは、特に木や草で、マスク付マテリアルを避け、代わりにメッシュのトライアングルの数を増やして、マテリアルを不透明に保つことが通常より迅速に処理できることを突き止めました。この主な理由は、Nanite のマスク付マテリアルは、ベース パスのシェーディングで大きな負荷が発生することにあります。これは、ピクセルごとに トライアングルのバリセントリック を再計算しなければならないため、アルファ マップのネガティブ スペースでオーバードロー負荷が増大するためです。

Preserve Area (エリアを保持)

フォートナイトの樹木を Nanite に変換した後、私たちは遠景の森林の上層部が失われていることに気付きました。これは、簡素化プロセスによるもので、葉がまばらになったり、場合によっては唐突に葉がまったくない状態になったりします。ある地点では、葉の 1 枚 1 枚でトライアングル 1 つ分以上の簡素化ができなくなり、トライアングルの数を減らすために葉を取り除く必要がありました。このように葉を取り除くと、森林の上層部がまばらな印象になります。

この問題を修正するために、境界のオープンなエッジを拡張することによって、失われた領域を残りのトライアングルに再分配する新しいロジック (メッシュの [Nanite Settings (Nanite 設定)] で有効にできる [Preserve Area (エリアを保持)] というオプション) を Nanite ビルダーに追加しました。葉の場合、これは残りの葉が大きくなるのと同じ効果があります。近い場所でこれを実行すると不自然に見えますが、[Preserve Area] が有効になる離れた場所では、その箇所に必要な密度を保った状態として表示されます。

この機能は、この問題があるフォリッジ メッシュでのみ有効にする必要があります。その他では無効にしてください。
 
[Preserve Area] が無効

 
[Preserve Area] が有効
風のアニメーション
すべての樹木が高忠実度でレンダリングされるのに、風の中でアニメートされないのは不自然です。これまで、フォートナイトでは、ワールド位置オフセットを制御する複雑なロジックで風のアニメーションを実現していました。Nanite を使用する樹木は Nanite を使用しない樹木 (1 ~2 万個) よりもはるかに多くの頂点 (30 ~ 50 万個) を含んでいます。そのため、Nanite のラスタライザー内で現在評価されているワールド位置ロジックでは、頂点ごとの評価負荷を削減できるように、樹木をアニメートする別の方法を模索しました。
この取り組みにより、複雑な風のシミュレーションをテクスチャにベイクするようにしました。これにより、頂点ごとに大量の複雑な計算を評価するのではなく、ワールド位置オフセットを制御するときにサンプリングできるようになりました。
樹木のジオメトリから、各枝のピボットと階層内のレベル、および各枝の親枝を抽出することができます。この情報からスケルトンを作成し、Houdini Vellum シミュレーションにその情報を入力することができます。
シミュレーションで得られた各枝のピボットと向きは、ピクセル値として画像にエンコードしたり、マテリアル シェーダーでサンプリングしたり、メッシュ アセットにエンコードされたカスタム UV 値を使ってインデックス化したりできます。これを使用して、枝の適切なピクセル列を選択することができます。

このため、Nanite ラスタライザーで必要なのは、オフセットを計算するために単一の位置とクォータニオンを参照することだけであり、複数の従属テクスチャの読み取りに依存する必要がありません。各枝が同じ UV 値を持つため、このアプローチでは、現在、剛体アニメーションのみをサポートしています。
距離のカリング
樹木の風のシミュレーションは、カメラの近くでは非常に重要ですが、遠景ではそれほど目立つものではありません。パフォーマンスを最適化するために、アーティストが定義した距離でワールド位置オフセットの計算を無効にする機能を Nanite に追加しました。この最適化は、[Evaluate World Position Offset] モードに基づいて構築されています。

このシステムに固有の距離カリングのサポートを含め、Nanite メッシュ インスタンスをスポーンするための ランドスケープ の草のサポートが追加されました。ここで使用しているアセットのアプローチは、樹木で使用するアプローチと似ています。草の葉には実際のジオメトリを持つ不透明なマテリアルを使用しましたが、これはワールド位置オフセット アニメーションを制御する単純な演算です。
 

 

ランドスケープ (Nanite)

仮想シャドウ マップの動作の性質上、Nanite を使用しない大きなメッシュは、同じサイズの Nanite メッシュよりシャドウのレンダリングにはるかに時間がかかります。これは特にランドスケープで問題になり、Nanite を使用しない大きなメッシュは多くの GPU 時間を消費します。UE 5.1 でリリースされたランドスケープ用の実験的な Nanite レンダリング機能を実装し、ビルド時にランドスケープの高さフィールドを Nanite メッシュに変換するようにしました。この変換によって視覚的な品質が向上することはないものの、ベース パスまたは仮想シャドウ マップへのレンダリング時に Nanite カリングおよびラスタライズのすべてのパフォーマンス特性を提供します。
Lumen はランドスケープの高さフィールドに対してトレースするための専用パスがあります。また、Nanite は現時点では ランタイム バーチャル テクスチャ へのレンダリングをサポートしていないため、このような場合、Nanite 表現は使用されず、代わりに高さフィールドが使用されます。
 

今後の取り組み

おそらく、残されている問題のうち最も重要なのは、ワールド位置オフセットによって実行されるアニメーションに一致する正確な (フレームごとの) インスタンスおよびクラスタのバウンディング ボリュームの演算処理でしょう。これは、Nanite のオクルージョン カリングがラスタライズの前にできるだけ多くのクラスタを確実に削除できるようにするために不可欠です。
 

現時点では、参照ポーズ境界を使用します (ワールド位置オフセットは無視する)。これは過度に慎重であったり (必要以上にクラスタをラスタライズする)、ワールド位置オフセットがクラスタを参照ポーズ境界の完全に外でアニメートさせると、ビジュアル アーティファクト (メッシュの構成要素が表示されなくなる) を生じさせます。プリミティブ コンポーネントの 境界スケール (Nanite を使用しないでこの問題に取り組む方法に似ている) をほぼサポートしました。このサポートにより、境界を任意の量だけ拡大することができますが、これによりカリングがさらに慎重になり、不必要なパフォーマンスによる負荷がかかります。

また、マスク付マテリアルやピクセル深度オフセットを使用するマテリアルの負荷を軽減するために、Nanite でのマテリアル システムの最適化に引き続き取り組む予定です。

Epic では、Unreal Engine 5.1 で Nanite のこの新機能をリリースできることを嬉しく思っています。また、デベロッパーの皆様がこの機能を活用して作成する素晴らしいコンテンツを見るのを楽しみにしています。
このブログに記載されている機能の詳細については、Nanite のドキュメント をご覧ください。

    今すぐ Unreal Engine を入手しましょう!

    Unreal Engine は、世界で最もオープンで高度な制作ツールです。
    あらゆる機能とソース コード アクセスを完備している Unreal Engine を使用すれば、すぐに制作を開始できます。