Search Unity

昨年の Unite LA で、『FPS Sample』プロジェクトと Visual Effect Graph が公表されました。『FPS Sample』の目的は、開発者に一人称視点シューティングの設定方法を説明することです。その最初のリリースでは、パーティクルシステム(現在制作に利用できるパーティクルソリューション)で作成したエフェクトを使用していました。その後、HD レンダーパイプライン(HDRP)を活用するために、新しい Visual Effect Graph を使用してすべてのビジュアルエフェクトをアップグレードしました。Visual Effect Graph はまだプレビュー版であるため、このツールを製品版への使用に耐え得るものに改良するために情報収集をしたり、制作パターンを試したりする貴重な機会でした。この記事では、アップグレードプロセスの事後分析とアップグレードから得た教訓のいくつかを紹介します。

システム間の移行はとても簡単

Visual Effect Graph は、テンプレートからエフェクトを実行するシンプルなコンポーネントを備えたパッケージです。その点で、すべてのエフェクトデータがシーンコンポーネントに埋め込まれているパーティクルシステムソリューションとは大きく異なっています。また、Visual Effect Graph では、複数のコンポーネントを 1 つのエフェクトグラフに埋め込むことができるため、Unity で 1 つのコンポーネントを使用するだけで複数のパーティクルシステムをレンダリングできます。

もっとも、この C# インターフェースはパーティクルシステムのインターフェースそっくりに作成したので、動作も非常によく似ており、あるシステムから別のシステムへのアップグレードが非常に簡単になっています。

『FPS Sample』の場合、新しいシステムへの移行は以下の理由から非常に簡単でした。

  • C# コードにパーティクルシステムへの参照がほとんどない。
  • C# コンポーネント API が(ほとんど)同じ。
  • ゲームコードの構造が追加の最適化を行えるほどに簡単。

移行にあたっては、まずプレハブとコード内にあるパーティクルシステムへの参照をすべて探し、慎重にそれらをすべてプレースホルダーで置き換えました。ゲームプレイに使うエフェクトはすべて、Assets/Effects ヒエラルキーの下にある専用のプロジェクトフォルダーに保存されていたため、非常に簡単な作業でした。

シーン内の他のエフェクトはすべて、ヒエラルキーのフィルターを使用して簡単に特定できました。それらの多くはプレハブ内に保存されていたため、プレースホルダーと置き換えるのはやはり簡単な作業でした。

置き換えが完了したら、エフェクトを改良、イテレーションする余地がある程度ありました。

Visual Effect Graph を使ったシューティングシステムの最適化

シューティングシステムではさまざまなエフェクトを使用しており、そのパフォーマンスは、ゲームの速度、プレイヤー数、プレイエリアのトポロジー、現在のゲームの状態などに左右されます。つまり、多くのオブジェクト(衝撃など)が生成される可能性があり、シーングラフで多くのドローコールが発生するということです。

この FPS 実装は、64 個の衝撃のプールを使用して作成されました。リサイクルシステム(1 つの衝撃につき 1 つのパーティクルシステム + 1 つのオーディオソース)を使用し、Entity Component System によって管理されます。

このシステムの主な欠点は、すべての衝撃インスタンスで、システムごとのドローコールが行われることです。エフェクトごとに使用するドローコールを数個に限定する制約を設けていたとしても、最悪のケースのシナリオでは、各種の衝撃で N × 64 個のドローコールが発生します(N は各衝撃を構成するパーティクルシステムの数)。

共有プールシステムの実装

対策としてすぐに思いついたのが、1 種類の武器の衝撃すべてに共通のシミュレーションを使用する方法でした。このようにすると、すべてのレンダリングが同じシミュレーションで行われます。私たちは、各衝撃を個別に整理するのではなく、すべての衝撃システムを 1 つにまとめることにして、それに伴う欠点を受け入れました。というのも、この方法には以下の利点があるからです。

  • 1 つのシステムでより多くのパーティクルをレンダリングできる(GPU シミュレーションのためには、この方が効率がよい)。
  • 多くのパーティクルシステム(レイヤー)を使用して、より素晴らしいエフェクトを作成できる。
  • 引き続きカメラへの距離を計算するので、ある種の LOD を行うことができる。

これを行うために、衝撃のソースと衝撃の法線を配置する目的で、VFX SendEvent() API および VFXEventAttribute ペイロードを使用しました。

 

衝撃の定義はアセットテンプレートのみを参照し、シーンレベルのマネージャーはマスターシミュレーションオブジェクトの処理とイベント(VFXSystem)の送信を担当します。

VFXSystem は、プールされたエフェクトすべての処理を担う最上位クラスです。これは、私たちが『FPS Sample』のために開発したものです。その動作は以下のとおりです。

  • プレイヤーが、VFXSystem による処理を必要とするプールされたエフェクトをトリガーする。
  • VFXSystem がそのエフェクトの属性(衝撃の場合は位置/法線)を受け取る。
  • VFXSystem がそのエフェクトのテンプレートも受け取る。
  • テンプレートがまだ生成されていない場合、生成させる。
  • どちらにしても、イベントを衝撃の位置と法線のインスタンスに対応する属性のペイロードと一緒にこのシステムに送信する。
  • レベルが変わった時に、プールされたエフェクトをリセットする。

このカスタムプールシステムを採用した結果、パフォーマンス面は大幅に改善できたものの、以下のような欠点があることもわかりました。

  • イベント属性を使用して設計されたエフェクトは、(属性が関与するので)C# API を使用してトリガーする必要がある。これはプレビューとオーサリングの点で理想的ではない(私たちがこの問題にどう対処したかは、「VFX Event Tester」の節を参照してください)。
  • 大きなバウンディングボックスを使用してエフェクトをカスタマイズする必要がある。FPS Sample では、バウンディングボックスがレベル全体を内包するように静的に設定しました。このバウンディングボックスを C# で管理して、動きのある仮想的な衝撃と共に拡大/縮小するようにする方法もあったということが、今回の教訓のひとつです。
  • エフェクトの LOD は生成時に計算されるため、遠方の衝撃は常に簡略化されている(この点については、パフォーマンス向上のための意図的な選択でした)。

VFX Event Tester

 

VFX Event Tester は、プールされたエフェクトに取り組むなかで、かなり早期に実装した機能です。プールされたエフェクトはイベント属性(衝撃の位置と法線、弾丸ヒットスキャンのソースとターゲット位置)を使用して開始する必要があったため、それらの属性を保存するために何らかの形で C# を使用する必要があります。

最初に思い付いた対策は、ダミーの Timeline と一緒に、パラメーター化されたエフェクトを送信する VFX Activation Track を使用して、エフェクトをプレビューすることです。問題はプレハブでした。この方法では、プレハブをシーンに埋め込んで編集し、後でシーンから取り除く必要があったため、理想的であるとは言いがたかったのです。

その代わりの方法として開発したのが、「VFX Event Tester」という名前の SceneView ユーティリティーウィンドウです。このウィンドウを使用すると、イベントと属性ペイロードを現在選択しているアセットに送信できます。

このツールは、「Edit」>「Visual Effects」>「Event Tester」メニューから、必要に応じてオンとオフを切り替えることができます。ソースコードは次の場所で確認できます。Assets/VFX/VisualEffectGraph-Extras/Editor/Utility/VFXEventTester/VFXEventTesterWindow.cs

カスタムパーティクル LOD システム

すべての衝撃で、常にあらゆるエフェクトコンポーネントを生成する必要があるわけではありません。非常に小さなパーティクルであればなおさらです。そこで、深度に応じたレンダリングを実現するために、パーティクルに対して初歩的ですが役立つフィルタリングシステム(Cancel By Distance)を実装しました。このシステムはゲートのようなもので、いくつかの条件を満たした場合にパーティクルの生成を無効にします。

このシンプルな LOD システムは、ほとんど見えない衝撃パーティクルを無用に生成しないようにするうえで役立ちました。しかし、このシステムは、ドリル研削機の岩のエフェクトなど、遠方のエフェクトの生成を停止させるためにも必要でした。

 

ここで説明したパーティクル発生を防止するシステムのソースコードは次の場所で確認できます。Assets/VFX/Script/CustomSpawners/CancelByDistance.cs

VFX Volume Mixer:プレイヤーの周囲のエフェクトをブレンド

短期間でエフェクトを展開すると、問題が発生する可能性があります。そのため、プレイヤーのカメラの周囲に 1 つのエフェクトを使用し、SRP Volume システムを使用してプレイヤーの位置に応じて周囲のエフェクトをブレンドすることにしました。

 

このボリュームミキサーは、Volume という名前の SRP コア機能を活用しています。これらのクラスは、ボリュームシステムに保存されているレンダリングパラメーターやポストプロセスなどのパラメーターを使用でき、レベル内のカメラの位置に応じて設定をオーバーライドすることができます。

このシステムのソースコードは、次の場所で確認できます。Assets/VFX/Script/VFXVolumeMixer

このシステムは、プレイヤーのカメラに合った環境エフェクトを展開するために使用しました。これによって、屋外や溶鉱炉の熱エフェクトや、屋内や洞窟の埃が作成されます。

このシステムを使用するには、プロジェクト設定で一連の値を設定する必要があります。このシステムでは、最大で 8 つの浮動小数点値、8 つのベクトル値、および 8 つのカラーの値を制御できます。開発者は、使用する設定値の数を選択し、それらの変数に名前を付けることができます。

その後、VFX Volume Mixer ボリュームコンポーネントをシーンボリュームに追加して、それらの値を入力し、レベル内でローカルにオーバーライドすることができます。これは、ローカルでオーバーライドを行うことのできる非常に便利な方法です。

最後に、それらのボリュームから値を抽出する必要がある場合は、VFX Volume Mixer パラメーターバインダーを使用できます。

Level_01 の他の注目のエフェクト

『FPS Sample』には、Level_01 シーンで使用したものの汎用システムには含まれていない、いくつかのパーティクルシステムも表示されています。以下に解決したケースをいくつか紹介します。

キャプチャーポイントの円

キャプチャーポイントの円は非常に興味深いエフェクトです。というのも、16 個の制御点を持つスキン化されたチューブから作られた変形可能なパスを追従するパーティクルが必要だからです。今のところ、Visual Effect Graph はスキンメッシュ上の生成を処理することができないため、このボーンチェーンに関する情報をまだ持っています。また、このエフェクトのためのスムーズな 3D 補間を実現するにあたっては、Sample Bezier オペレーターが非常に役立ちました。

 

複数の位置から構成されるパス上にパーティクルを生成する方法は非常に単純です。位置属性マップに位置のリストをベイクした後、このテクスチャのピクセルをサンプリングして、パーティクルを生成する必要のある位置を決定します。

このために、「Multiple Position」バインダーという新しいパラメーターバインダーを作成しました。このバインダーはゲームオブジェクトのリストを受け取り、すべてのゲームオブジェクトのワールド空間位置をテクスチャに書き込み、特定の Visual Effect Graph 内で公開されているパラメーターにその点の数とテクスチャを設定します。

この位置マップのサンプリングは非常に簡単です。2 ピクセルのグループを 4 つのベジェ点と見なし(2 つの中間ベジェ接線を計算)すべてを補間して、すべてのパーティクルがベジェブレンディングで生成されたすべての位置を通過するようにします。

この例は、Assets/Prefabs/Gameplay/Capturepoint_A にあるプレハブで確認できます。エフェクトは Small_emitter ゲームオブジェクトにあります。

Multiple Position バインダーのソースコードは、このプロジェクトの次の場所にあります。Assets/VFX/Script/ParameterBinders/VFXMultiplePositionParameterBinder.cs

岩研削機

岩研削機は、峡谷の終わりで使用されているシンプルな装飾的エフェクトです。研削ドリルを力強く見せるために使用されています。ドリルは足止めされた状態で、左側にある岩石層と、キャプチャーポイントの役割を果たすテラフォーマーの卵を削っています。

埃とダクトの蒸気

レベル全体に多くの光源が配置されており、それぞれをシンプルな蒸気、埃、空気の流れのエフェクトで装飾する必要があります。光源のほとんどは静止していますが、なかにはこの回転しているエアダクトのように動いているものもあります。


このケースに対処するために、特別に点灯させたパーティクルを使用して、漏れ出す蒸気とボリューメトリックライトの軌跡を同期しました。適切なフレームレートを保つために、これらのパーティクルはカメラから遠く離れた位置ではフェードアウトさせる必要がありました。というのも、このシェーダーではピクセルごとに点灯を処理していて、全画面にレンダリングすると非常に多くのリソースを消費するからです。


このレベルには他のエフェクトも配置しました。今回は、パフォーマンスを節約するために、それらは光学処理のないパーティクルとして設定しました。垂直に伸びる大きなエアダクトを照らすこともできましたが、パフォーマンスの点でそのサイズが少し問題となりました。さらに、光の軌跡がそれほど鋭くなかったため、シンプルな光学処理のないエフェクトを採用することにしました。これらのインスタンスはすべて、シーン内で直接フェードアウトする距離と色を指定して設定しました。

溶鉱炉のエフェクト

溶鉱炉のエフェクトは非常にシンプルで、円形になるように多数の泡を生成し、実験的な GPU イベントを使用して、それぞれの泡が崩壊する際に、泡がはじけるフリップブックと立ち上る火の粉を生成しています。

またこれは一般的に、局所的でない立ち上る火の粉、蒸気、および熱のエフェクトを使用して装飾されています。

このエフェクトのかなり近くまで寄ることは可能ですが、蒸気と熱に Camera Fade ブロックを使用したため、オーバードローが緩和され、フレームレートが制御されています。

まとめ

FPS Sample の Visual Effect Graph への移行は予想よりもスムーズでした。このパッケージはまだプレビュー版であるため、プロジェクトのニーズに応じて体験をカスタマイズできるだけの柔軟性がある程度残されています。さいわい、『FPS Sample』プロジェクトの構造は非常にわかりやすく、一時しのぎの実装やカスタム実装はほとんどありません。そのため、『FPS Sample』は Visual Effect Graph の実装を試す絶好の対象でした。しかし、実際のプロジェクトでは、勝手がまったく異なり、作業がもっと困難になることが予想されます。とにかく、今回の取り組みで、2019 年に私たちが取り組む Visual Effect Graph の次のバージョンの制作ケースを特定することができました。

このプロジェクトの一部の機能は、今回の統合のために特別に開発されたものです。今回開発した機能は、今後より汎用的なツールを考え出すための参考として、これからも維持していく予定です。

コメント受付を終了しました。

  1. Sascha Schulz

    4月 15, 2019 10:01 pm

    Great Post.

  2. Keep building on that game, please! Unity needs a real product to try all the new features. Also, try to use as few custom things as possible, as most of Unity’s “cinematics” released in the past use a ton of custom scripts/shaders that aren’t in the base engine. This project is looking good!

  3. Finally, a blog post worth reading. Though it’s miles better than other blogs, I thought the core of the FPS Sample is on the multiplayer where Unity lacks the most. I’ll appreciate if you focus more on the multiplayer rather than the eye-candies for FPS Sample. You can show the eye candies on other projects you have. Thanks.

  4. I definitly have to take a closer look at the visual effects graph. Thanks for this informativ post. Keep up the great work!

  5. This looks like an excellent “real-world” example (or close it) for the VFX Graph.

    Will you be providing a demo project that we can examine to better understand the details of your implementation?

  6. Florian Bässler

    4月 11, 2019 1:18 am

    I am using Unity since years now, and i have to say, these whole FPS project is, for me, the best learning ressource (exspecilly for new features) unity ever provided. I am really happy to see, that you guys do a well progress there and keep us up to date. Thank you for sharing and helping me out finally understanding some advanced topics, i really could not figure out before!

  7. Marcin Szymanski

    4月 10, 2019 6:19 pm

    Fantastic post, can’t wait to dig into this on our next project!

  8. Isaac Surfraz

    4月 10, 2019 2:28 pm

    great post, more like these!