处理地块重叠

某个地形中有多个地块时,它们可能会重叠,至少边缘会重叠。重叠可能会影响其中一个或全部两个地块的导航区域。

为确保 NavData 正确反映加载到内存中的几何体,NavData 生成系统会标识这些重叠区域,并对其进行特殊处理。

  1. 首先,每个地块都为自己生成了 NavData,而未考虑相邻地块中的几何体。

    每个地块都需要配置由 KyGuid 类实例表示的全局唯一 ID,该 ID 在创建地块时提供。

  2. 接下来,将标识所有相邻地块之间的重叠区域。然后会生成备用的 NavData 块,以反映重叠地形几何体的组合情况。此备用块通过 KyGuid 进行标记,KyGuid 是指定给重叠所涉及的所有地块的唯一 ID 的组合。
  3. 备用块会保存到其中一个重叠地块的 .NavData 文件中。
  4. 在运行时将地块的 NavData 以流式加载方式载入和清除出内存时,数据库将根据当前加载的地块自动换入或换出重叠数据。

例如,假设一个地块包含一片比较平坦的平原,相邻地块包含一座山丘。这两个地块中的几何体稍稍重叠,这样,一部分山丘落在平原上,一部分平原延伸到山丘下。

仅加载平原的 NavData 时,其 NavData 将反映平坦的地形。仅加载山丘时,其 NavData 将仅反映山坡。同时加载两个地块时,平原与山丘重叠的部分将自动替换为表示重叠区域的备用块,从而允许人物从一个地块传递到下一个地块。

此过程是完全透明的。您只需在 NavData 生成系统的同一次运行中提供所有不同的地块;将自动处理重叠数据的生成和运行时缝合。

控制重叠数据的生成

自动重叠检测和缝合系统旨在无缝处理每个地块组合,以确保 NavMesh 始终与几何体保持一致,不管当前在游戏中加载的是哪一组地块,即使在地块之间的边界沿线也是如此。

但是,在某些情景中,您可能希望阻止生成重叠数据,以减少地块 NavData 的内存使用量。下面介绍了通常可以禁止生成重叠数据但不影响 NavMesh 精度的情景。

使用相似地块

有时,地形几何体在游戏过程中可能会发生重大更改,此时您可能希望为两种不同状态下的该地块生成 NavData,并在地形状态发生更改的情况时在运行时进行交换。相似地块的经典示例是包含可能会在运行时遭到销毁的大型建筑的区域。当该建筑存在时,您希望地面上的角色围绕该建筑行走,您可能还希望这些角色能够在该建筑内(如在屋顶上等)移动。但是,当该建筑遭到销毁后,这些角色应自由地在以前由该建筑占用的区域的地面上穿行。

通过为几何体的每种状态设置不同的地块,并与您世界中的其余地块一起同时生成这两个地块,您可以为这两个相似地块透明地创建 NavData。例如,可以创建一个包含建筑完好无损的地形几何体的地块,以及一个包含建筑遭到破坏后的地形几何体的地块。Generator 将透明地为两个可交换地块版本创建 NavData,并创建将两个版本链接到周围地块的重叠数据。

但是,默认情况下,NavData 生成系统认为可将两个可交换地块版本同时流入内存。它将检测到这两个地块在空间上重叠,因此除创建每个地块自身的 NavMesh 外,还会为几何体组合创建覆盖整个可交换地块区域的重叠数据。这不是问题,因为系统仍将在运行时平稳工作:不管何时加载哪个地块,您都将始终具有正确表示地形的 NavMesh。但是,如果是可交换地块,那么永远不需要重叠数据,因为永远不会同时加载两个相似地块版本。因此,您可以通过一开始就阻止 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++ 中使用 Generator

您可以通知 Generator 永远不会同时加载哪些地块,方法是在调用 GeneratorInputOutput::AddExclusiveGuids() 时提供这些地块的 KyGuidGenerator 将不会为该地块组合生成任何重叠数据。可以根据需要多次调用该方法,以设置不同的排他地块集。

使用固定步长分区或基于栅格的分区

某些游戏项目使用流化子关卡,其范围遵循每个单元格具有一致长度和宽度的常规轴对齐栅格。如果您的项目使用这样的栅格在相邻的子关卡之间布置分段,则可以使用单元格框来定义地块的范围,以避免生成不必要的重叠数据。

在此方法中,将 NavData 生成框架内部使用的单元格大小与栅格单元格的大小对齐。对于每个地块,提供定义哪些单元格将被指定给该地块的框范围。

  • 栅格中每个单元格的 NavData 仅保存在单元格框中包含该单元格的地块中。
  • 每个单元格的 NavData 反映与该单元格交叉的地形中所有三角形的组合,而不管您的 GeneratorInputProducer 类将这些三角形指定给哪个地块。
  • 对于已为其配置单元格框的任何重叠地块,不会生成任何重叠数据。如果您需要为特定地块组合强制生成重叠数据,可以通过调用 GeneratorInputOutput::AddExplicitOverlapSectors() 实现这一点。

请注意,由于每个 NavData 单元格始终反映所有重叠几何体的组合,但每个单元格仅存储在一个地块中,因此,如果您仅将一个重叠地块的地形网格加载到游戏中,可能会看到 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++ 中使用 Generator

  • 要设置内部单元格划分网格的大小,设置 GeneratorInputOutput.m_params.m_cellSize 类成员的值。
  • 对于每个地块,通过调用 GeneratorSectorConfig::SetInputCellBox(),沿水平 X 轴和 Y 轴设置单元格框的范围。