标识可导航区域

NavData 生成系统始终接受并考虑您在输入几何体中提供的所有三角形。这经常会导致在不希望可供您的角色在运行时访问的区域中生成 NavData。例如,屋顶上、树梢中、封闭建筑内等。

这些多余的数据不会导致性能问题,只要不尝试规划通向这些无法到达的区域的人物路径即可。但它会占用额外的内存,从而可能会影响其他用途的内存使用。

如果要排除不需要的数据,您可以利用以下部分中介绍的几种不同的方法。这些方法不是专用的;您可以根据地形的不同关卡或区域采用最适用的处理方法。

使用种子点

您可以针对每个地形为 NavData 生成系统提供任意数量的种子点,用于识别地形中可以行走的区域。如果为某个地块提供了一个或多个种子点,后期处理阶段将从每个种子点在 NavMesh 中传播。仅保留覆盖可从这些种子点到达的区域的 NavMesh。其他所有 NavData 都将丢弃。

示例

以下面的地形为例:默认情况下,会在所有屋顶上和每个建筑内部创建 NavData 的孤立区域(尽管室内 NavData 在图像中不可见,它仍会在运行时占用大量额外的内存)。

在地面上的任意位置放置单个种子点后,将自动丢弃所有无法从地面访问的 NavData。其中包括所有的屋顶和建筑内部,如下所示。

使用 Navigation Lab

要在 Navigation Lab 中创建种子点,请在地形上的任意位置单击鼠标右键,然后从上下文菜单中选择 Generation > Spawn Seed Point

在 C++ 中使用 Generator

创建每个地块时,您可以通过在为该地块创建的配置中调用 GeneratorSectorConfig::AddSeedPoint()GeneratorSectorConfig::AddSeedPointInClientCoordinates() 方法来为该地块提供种子点。

或者,您可以通过调用 ClientInputConsumer::ConsumeSeedPoint()GeneratorInputProducer 类中提供种子点。

请注意,每个地块仅考虑在其配置中为其指定的种子点或调用 GeneratorInputProducer 为该地块获取三角形时的种子点。因此:

  • 如果您希望所有地块的 NavMesh 反映同一可行走的区域,则应为每个地块设置相同的点列表。为了增强地块之间过滤的一致性,通常建议使用此方法。
  • 在某些情况下,您可能需要使用不同的地块来反映不同的种子点集。例如,您可能需要在相似地块的两个不同版本中将种子点放置在不同位置。在这种情况下,您可以仅为每个地块设置其需要的种子点集。

使用排除 TagVolume

您可以向 NavData 生成系统提供包括不需要的区域的 3D 体积,并将这些体积标记为不可行走。这样便不会为位于这些体积内的任何输入三角形生成 NavData。

示例

在本示例中,我们希望将营地设在地形右侧的安全区域,玩家可以在这里休息,而不必担心来自敌方 NPC 的攻击。

为执行此操作,我们创建了一个包括安全区域的 TagVolume,并将其标记为“排他”。生成之后,NavMesh 将在其边界处停止,使 NPC 无法进入该区域。

使用 Navigation Lab

在 Navigation Lab 中创建 TagVolume:

  1. 在地形上单击鼠标右键,然后从上下文菜单中选择 Generation > Spawn Tag Volume
  2. 按 Ctrl 键并单击鼠标左键以将顶点放置在要隔离的区域周围。完成后按 Enter 键。
  3. Scene View 窗口或 3D 视图中选择新 TagVolume。
  4. 打开 Attribute Editor 窗口,并选中 ExclusionVolume 框。

在 C++ 中使用 Generator

Generator 创建 TagVolume:

  1. 创建 ClientInputTagVolume 类的实例来表示体积。将其设置为所需的范围和位置。
  2. 要将 TagVolume 标记为排除体积,请对 ClientInputTagVolume::m_navTag 调用 Dynami NavTag::SetAsExclusive()
  3. 创建每个地块时,您可以通过在为该地块创建的配置中调用 GeneratorSectorConfig::AddTagVolume() 方法来为该地块提供 TagVolume。

    或者,您还可以通过调用 ClientInputConsumer::ConsumeTagVolume()GeneratorInputProducer 类中提供 TagVolume。

    请注意,每个地块仅考虑在其配置中为其指定的 TagVolume 或调用 GeneratorInputProducer 为该地块获取三角形时的 TagVolume。因此:

    • 必须为它们相交的所有地块设置位于两个相邻地块的边界上的 TagVolume。
    • 在某些情况下,您可能需要使用不同的地块来反映不同 TagVolume。例如,您可能需要在相似地块的两个不同版本中将不同的 TagVolume 放置在不同位置。在这种情况下,您可以仅为每个地块设置其需要的 TagVolume 集。

标记单个三角形

如果直接使用 NavData 生成框架的 API,可以在区域中使用特殊 NavTag 来标记希望排除的每个输入三角形。在生成过程中,不会为任何仅具有标记有此地形类型的三角形的像素生成 NavData,NPC 也无法在这些区域中导航。

要使用该方法,GeneratorInputProducer 的自定义类应使用 ClientInputConsumer::ConsumeTriangle()ClientInputConsumer::ConsumeTriangleFromPosInClientCoordinates() 方法向 ClientInputConsumer 提供每个输入三角形。通过调用其 DynamicNavTag::SetAsExclusive() 方法,将在参数列表中为这些方法提供的 DynamicNavTag 设置为“排他”。

请注意,将三角形传递到生成系统时,建议使用此地形类型机制而不是简单地忽略三角形,以确保这些三角形在需要时仍被看作静态障碍物。

设置最小 NavMesh 区域

可以为 NavMesh 中的任意部分设置最小曲面区域。生成 NavData 后,后期处理阶段会丢弃任何曲面区域小于该阈值的 NavFloor。

当 NavMesh 包含许多互不相连且角色不应穿越的小型孤立区域时,该设置非常有用。

请注意,为保证与相邻地块的 NavData 一致,始终保留与相邻地块重叠的所有 NavMesh 区域。因此,如果小屋顶刚好位于两个相邻地块的边界上,它可能不会按照预期被滤掉。

示例

在该测试地形上,斜坡上地形的局部变化会导致一些小型不相连区域,角色在运行时永远不需要移动到这些区域。

通过提高最小曲面区域阈值,我们可以使所有位于这些小型区域中的 NavData 自动丢弃,而不影响周围 NavData 的特征。

请注意,如果种子点出现在将正常使用最小曲面参数进行过滤的曲面上,则将保留包含该种子点的曲面,除非该曲面足够小以至于被视为噪波:即小于 GeneratorAdvancedParameters::m_noiseReductionSurface 参数。请参见下文。

使用 Navigation Lab

在 Navigation Lab 中设置阈值:

在 Navigation Lab 中设置最小曲面:

  1. 打开 Generation 窗口,并展开 Advanced Parameter 部分。
  2. Minimum Navigable Surface 值设置为每个单独的 NavMesh 区域必须占用的最小曲面区域(以平方米为单位)。

在 C++ 中使用 Generator

可以在可通过 GeneratorInputOutput.m_params.m_advancedParameters 访问的 GeneratorAdvancedParameters::m_minNavigableSurface 成员的值中设置曲面区域阈值。

降噪

除了上述的 GeneratorAdvancedParameters::m_minNavigableSurface 参数外,还可使用另一个参数来控制降噪:GeneratorAdvancedParameters::m_noiseReductionSurface。后一个参数的效果类似,不同之处在于:

  • 它在生成过程的第一个阶段应用,以通过尽早丢弃极小的区域加快生成速度。
  • 它忽略种子点的存在。
  • 它逐单元格应用。它只能移除完全位于单个 NavMesh 单元格边界内的区域。相反,GeneratorAdvancedParameters::m_minNavigableSurface 参数在整个生成阶段都会考虑到,因此它可以移除横跨相邻单元格之间边界的区域。

在大多数项目中,建议您调整 GeneratorAdvancedParameters::m_minNavigableSurface 参数并将 GeneratorAdvancedParameters::m_noiseReductionSurface 参数保留为默认值。但是,为获得最佳性能和保持一致性,GeneratorAdvancedParameters::m_noiseReductionSurface 的值通常小于 GeneratorAdvancedParameters::m_minNavigableSurface的值,因此如果您将 GeneratorAdvancedParameters::m_minNavigableSurface 设置为很低的值,则可能需要降低前者的值。