碰撞回避过程
路径跟随时的动态回避是用于计算每帧中的速度以满足以下要求的过程:
- 回避路径中的任何移动或静态人物或者障碍。
- 拾取用于跟随计算的路径的速度(离该路径不太远)。
- 遵守 NavMesh 边界和计算的通道。
- 在尽可能保持稳定的情况下将回避操作降到最低。
动态回避包含以下步骤:
- 收集潜在碰撞对象。请参见收集碰撞对象
- 针对多种条件生成一组回避速度并对其进行计分。请参见生成回避速度
- 选择要应用于给定帧的最合适的速度。请参见用于获取最终得分的实用工具函数
以下部分解释了动态回避过程。
收集碰撞对象
如果基于场景中的整个世界元素计算人物的回避,其成本会非常高。而且,这种方法并不管用,因为回避多为局部回避,并基于附近的实体。
由于时间的连贯性,将在给定帧中回避的实体也可能与后续帧中的大致相同。因此,您可以充分利用 NavMesh 传播结构来构建附近潜在碰撞对象的列表。您只需要以给定的帧速率更新此列表。下图显示了碰撞对象收集范围(显示可回避的实体)。
可以在 ColliderCollectorConfig 中配置此过程。参数如下:
- m_colliderCollectorRadius – 定义围绕人物的半径(以米为单位),将在该半径范围内收集潜在碰撞对象。
- m_colliderCollectorHalfHeight – 定义高于和低于人物海拔高度的高度(以米为单位),将在该高度范围内收集潜在碰撞对象。
- m_colliderCollectorFramesBetweenUpdates – 定义两次连续收集潜在碰撞对象之间的帧数。
生成回避速度
对于处于任意给定时间的人物,实体可达到较大范围的潜在速度。对于路径跟随以及为回避混乱行为,可以将回避速度集限制在某个固定范围以内。
首先,必须确定全局路径跟随方向。计算此方向以使其与路径跟随过程兼容。
- 捷径模式 – 获取支持路径上目标的当前路径边的方向。下图中显示回避的参考方向平行于当前路径边。
- 通道模式 – 获取当前通道截面中的方向。下图显示参考方向平行于当前截面的两个栅门之间的方向。
现在,围绕路径跟随方向生成 N 个回避速度的采样。下图显示了生成的速度采样,默认情况下,所有采样得分均为 1.0。
这些速度采样的速度与人物配置中的所需速度一致。可以在 AvoidanceConfig 中配置这些速度采样的数量和角度范围。参数如下:
- m_avoidanceAngleSpan – 回避速度的角度范围(以度为单位)。
- m_avoidanceSampleCount – 回避速度的采样计数。
现在可以执行计分过程以选择最佳速度。
碰撞时间
回避在空间和时间方面都是局部的。可以指定用作范围的时间限制,并使用针对每个采样收集的碰撞对象计算碰撞时间。下图显示了为给定帧计算的碰撞时间。
如果没有碰撞,或碰撞超出了配置的时间限制,可以将采样成本设置为时间限制。
NavMesh/通道边界
可以基于采样与 NavMesh/通道边界之间的距离来对采样计分。下图显示了 NavMesh 外的采样获得了较差的分数。
碰撞时间比例
可以将具有范围的碰撞时间进行拆分以计算 0.0 和 1.0f 之间的比例,其中 1.0f 是最安全的速度。下图将碰撞时间显示为比例。
可以在 AvoidanceConfig 中指定时间范围。参数如下:
- m_minimalTimeToCollision – 如果障碍物在 N 秒内与其他障碍物碰撞,在回避时应考虑此参数。
- m_safetyDistance – 围绕碰撞对象的安全距离,以避免移动得太近。可以按安全距离稍微展开碰撞对象的大小,以拾取与碰撞对象保持较远距离的速度。
平滑
采样可能不准确,因为有效采样与无效采样之间可能仅有几度之差。若要避免拾取不安全的采样,可以为每个速度采样及其相邻的采样计算平均碰撞时间比例。下图显示了平滑碰撞时间。
现在可以选择没有碰撞的安全速度。但是,有几种可能性,因此可以考虑其他两个条件来作出决定。
所需速度
路径跟随已产生所需速度。可以利用此速度来基于采样相对此速度的距离为采样计分。下图显示了如何将所需速度(绿色)用于基于采样相对此速度的距离为采样计分。
上一个速度
若要更进一步稳定,可以执行相对于先前已计算速度的类似计算。下图显示了如何基于上一个速度(红色)进行计分。
用于获取最终得分的实用工具函数
可以对每个采样使用以下实用工具函数并计算最终得分。
Final Score = (A * CollisionTimeRatio) + (B * DesiredVelocityDistance) + (C * PreviousVelocityDistance)
其中,A、B 和 C 是可以配置的常量(如果 A +B + C = 1.0 的话最容易理解)。在获得最终得分之后,只需返回其采样具有最高得分的速度。下图显示了针对回避输出的所选最终得分和最终速度。
可以在 AvoidanceConfig 中配置 A、B 和 C。参数如下:
- m_timeToCollisionInfluence – 选择回避速度时,时间对碰撞的影响。
- m_desiredVelocityInfluence – 选择回避速度时,所需速度的影响。
- m_previousVelocityInfluence – 选择回避速度时,前一个速度的影响。
停止
当没有好的回避解决方案时,如果下一个碰撞时间低于给定阈值,可以返回实体的零速度以停止。参数如下:
- m_stopCollisionTime – 如果无法在 stopCollisionTime 秒内回避碰撞,实体将停止。在停止后,最好将此决定维持一段时间,以避免不平稳的移动。
- m_stopWaitTime – 如果实体停止,等待 stopWaitTime 秒,然后再次移动。
在某些情况下,您可能希望首先降低速度,甚至禁用实体停止功能。参数如下:
- m_enableSlowingDown – 如果设置为 true,将考虑具有已降低速度的速度候选对象。否则,将只考虑具有 Bot::GetDesiredSpeed() 长度的速度候选对象。
- m_enableStop – 如果设置为 true,将考虑空速度候选对象。否则,AvoidanceSolver 将不会考虑停止人物,有时候这将强制通过碰撞对象。
如果受阻太久,您可能仍然想强制通行。参数如下:
- m_enableForcePassage – 如果设置为 true,在一段时间之后仍未发现其他解决方案时,将允许包含碰撞的解决方案。
- m_waitPassageTimeLimit – 如果 m_enableForcePassage 为 true,则将仅在延迟 m_waitPassageTimeLimit 秒后强制通行。
- m_forcePassageTimeLimit – 如果 m_enableForcePassage 设置为 true,则在延迟 m_waitPassageTimeLimit 秒后,进行最多 m_forcePassageTimeLimit 秒的强制通行。