セクタのオーバーラップの処理

地形に複数のセクタが含まれていると、少なくともそのエッジ付近で、オーバーラップしやすくなります。このオーバーラップは、2 つのセクタのいずれかまたは両方の移動可能な領域に影響します。

NavData 生成システムは、NavData がメモリにロードされたジオメトリを正しく反映できるようにするために、このようなオーバーラップの領域を識別し、特殊な処理を行います。

  1. まず、各セクタにはそのセクタ用に生成された NavData がありますが、隣接するセクタに含まれているジオメトリは考慮されていません。

    各セクタには、セクタの作成時に指定する KyGuid クラスのインスタンスで表されるグローバルに一意の ID を設定する必要があります。

  2. 次に、すべての隣接するセクタ間でオーバーラップの領域が識別されます。次にオーバーラップする地形ジオメトリの組み合わせが反映された NavData の代替チャンクが生成されます。この代替チャンクには、オーバーラップに関連するすべてのセクタに割り当てられた一意 ID の組み合わせである KyGuid を使用してタグが付けられます。
  3. 代替チャンクは、オーバーラップするセクタのいずれかの .NavData ファイルに保存されます。
  4. セクタの NavData を実行時にメモリにストリーミングするか、メモリからストリーミングすると、Database は、現在ロードされているセクタに応じて、自動的にオーバーラップ データをスワップインおよびスワップアウトします。

たとえば、比較的平坦な平面を含むセクタと、丘を含む隣接セクタがあるとします。2 つのセクタのジオメトリは若干オーバーラップし、丘の一部が平面のレベルよりも下に伸び、平面の一部は丘の下に伸びています。

平面の NavData のみがロードされる場合、その NavData は平坦な地形を反映します。丘のみがロードされる場合、その NavData は丘の斜面のみを反映します。両方のセクタが同時にロードされると、平面と丘のオーバーラップする部分が自動的に、オーバーラップ領域を表す代替チャンクに置換され、Bot が、あるセクタから次のセクタに移ることができます。

このプロセスは全体が透過的です。必要な作業は、NavData 生成システムの 1 回の実行で異なるセクタをすべて指定することだけです。オーバーラップ データの生成および実行時につなぎ合わせるのは自動的に処理されます。

オーバーラップ データの生成をコントロールする

自動オーバーラップ検出および自動でつなぎ合わせるシステムは、セクタのあらゆる組み合わせをシームレスに処理して、どのようなセクタのセットがゲームに現在ロードされている場合でも、NavMesh を常にそのジオメトリと整合させる(セクタの間の境界に沿うようにするなど)ように設計されています。

ただし、場合によっては、セクタ用の NavData のメモリ使用量を減らすためにオーバーラップ データを生成しないようにすることもできます。NavMesh の精度を損なわずにオーバーラップ データの生成を無効にできる典型的な状況を次に示します。

スワップ可能セクタの使用

ゲームの途中で地形ジオメトリに大きな変化が生じる可能性がある場合、そのセクタの NavData を 2 つの異なる状態で生成し、地形の状態が変化した場合、実行時にスワップすることもできます。スワップ可能セクタの古典的な形として、実行時に破壊される可能性がある大きなビルを含む領域を考えてみます。ビルが存在しているときには、地面にいるキャラクタがビルの周囲を歩いたり、ビルの中や屋上を動き回ったりできるように設定できます。しかし、ビルが破壊されると、キャラクタは以前はビルがあった領域を自由に通り抜けられるようにする必要があります。

このような入れ替え可能セクタの NavData は、ジオメトリの各状態について異なるセクタを設定し、ワールド内の他のセクタと共に、両方のセクタを同時に生成することによって、透過的に作成できます。たとえば、破壊されていないビルの地形のジオメトリを含むセクタと、ビルが破壊された後の地形のジオメトリを含む別のセクタを作成します。Generator によって、スワップ可能セクタの両方のバージョンの NavData の作成と、両方のバージョンを周囲のセクタにリンクするオーバーラップ データの作成が透過的に処理されます。

ただしデフォルトでは、NavData 生成システムは、スワップ可能セクタの 2 つのバージョンを一度にメモリにストリーミングすることを可能とみなします。このシステムは、2 つのセクタのスペース内でのオーバーラップを検出します。そのため、各セクタの NavMesh を自動的に作成する他に、組み合わせたジオメトリのスワップ可能セクタの領域全体を覆うオーバーラップ データも作成します。このことは、どちらのセクタをどの時点でロードしているかに関わらず地形を正しく表現する NavMesh が常に 1 つは存在するので、システムが実行時にスムーズに動作するという意味では、特に困るということはありません。ただし、入れ替え可能セクタの場合、スワップ可能セクタの 2 つのバージョンは同時にロードされることはないので、オーバーラップ データが必要になることはありません。したがって、NavData 生成システムで最初からオーバーラップ データを作成しないようにすることで、メモリを節約できます。

Navigation Lab を使用する

Navigation Lab で排他的セクタを設定するには:

  1. Navigation Lab のシーンに複数の .obj ファイルを追加することで、複数のセクタを設定します。
  2. Scene View ウィンドウで、Add Excl. Sectors をクリックします。「ExclusiveSectors」という新しい要素が、Scene View の ExclusiveGuids ツリーに追加されます。
  3. 新しい「ExclusiveSectors」要素をクリックします。
  4. 3D ビューの右側に、Attribute Editor ウィンドウを開きます。このウィンドウには、現在シーン内に存在するすべてのセクタの一覧が表示されます。
  5. 互いに排他的であるすべてのセクタのチェック ボックスをオンにします。

    セクタのチェック ボックスをオンにするたびに、Activate ボタンが表示されます。3D ビューにそのセクタのみを表示する場合は、必要に応じてこのボタンをクリックします。

    Scene View の「ExclusiveSectors」要素の名前は、管理するセクタを示すために更新されていることに注意してください。

さまざまな排他的セクタのセットを、必要な数だけ設定することができます。

C++ でジェネレータを使用する

GeneratorInputOutput::AddExclusiveGuids() への呼び出しで該当のセクタの KyGuids を指定することで、同時にロードすることのないセクタを Generator に通知することができます。Generator は、指定されたセクタの組み合わせについてオーバーラップ データを生成しません。さまざまな排他的セクタのセットの設定に必要な回数だけ、このメソッドを呼び出すことができます。

fixed-step または grid-based 分割を使用する

サブレベルのストリーミングを使用するプロジェクトがあると思います。そのサブレベルの範囲は各セルの長さと幅が一定で、座標軸に平行のグリッドに準拠するものです。プロジェクトでこのようなグリッドを使用して、隣接するサブレベル間の分割をレイアウトする場合、セル ボックスを使用してセクタの範囲を定義することで、不要なオーバーラップ データを生成しないようにすることができます。

このアプローチでは、NavData 生成フレームワークによって内部的に使用されるセルのサイズを、グリッド セルのサイズと合わせます。各セクタに対し、どのセルがそのセクタに割り当てられるかを定義するボックスの範囲を指定します。

  • グリッド内の各セルの NavData は、セル ボックスにそのセルが含まれているセクタにのみ保存されます。
  • 各セルの NavData は、そのセルと交差する、地形のすべてのトライアングルの組み合わせを反映します。GeneratorInputProducer クラスによってこれらのトライアングルがどのセクタに割り当てられているかは影響しません。
  • オーバーラップするセクタに、それ自身のために設定されたセル ボックスがある場合、オーバーラップ データは生成されません。セクタの特定の組み合わせにオーバーラップ データが必要な場合は、GeneratorInputOutput::AddExplicitOverlapSectors() を呼び出すことで可能です。

各 NavData セルはすべてのオーバーラップするジオメトリの組み合わせを常に反映しますが、それぞれのセルは 1 つのセクタにしか保存されていないため、オーバーラップするセクタのうちの 1 つだけの地形メッシュをゲームにロードすると、オーバーラップする領域内の NavData とジオメトリの間に局所的な不整合が生じる場合があります。

各セクタで使用するセル ボックスの範囲を決定するため、以下の操作を実行できます。

  • 自分で値を計算します。3D セル ボックスの原点は、3D ワールド空間の原点と常に同じになります。また、セル ボックスの各セルの幅と長さは GeneratorInputOutput.m_params.m_cellSize の値によって決定されます。セル ボックスは常に軸に並行です。
  • セクタに最初の生成パスを実行し、Navigation Lab で NavData を開き、そのセクタ用に生成された NavData のセルのレイアウトを表示します。

コード サンプルについては、Tutorial_Generation_cellbox.cpp ファイルを参照してください。

Navigation Lab を使用する

  • 内部セル分割グリッドのサイズを設定するには、Generation パネルの Parameters グループ内の Cell size (m) コントロールの値を設定します。
  • Scene View パネル内の各セクタを順に選択し、そして Attribute Editor を開きます。Cell box 領域で、Active コントロールをオンにし、水平方向の X 軸と Y 軸に沿って、選択したセクタ用にセル ボックスの範囲を設定します。

    Generation Inputs ツールボックスの CellBoxes ボタンを切り替えることによって、3D ビューでのセル ボックスのレンダリングを切り替えることができます。

C++ でジェネレータを使用する

  • 内部セル分割グリッドのサイズを設定するには、GeneratorInputOutput.m_params.m_cellSize クラス メンバーの値を設定します。
  • セクタごとに GeneratorSectorConfig::SetInputCellBox() を呼び出して、水平方向の X および Y 軸に沿ってセル ボックスの範囲を設定します。