在上一篇文章介绍的RVO2算法中,提到了CombineCircle重叠导致Agent前进受到阻碍,无法绕开的问题。之所以无法绕行,是由于RVO2算法是局部避碰算法,全局信息的缺失导致无法得到全局最优解。此外,该算法在优化Agent的速度方向时,算法只考虑了单个Agent躲避其他Agent的最小避让方向,但却没有考虑多个避让方向之间是否存在矛盾冲突,这就是导致CombineCircle重叠问题导致的RVO2算法计算得到的速度越来越小的原因。
为了解决RVO2算法框架下,运动的Agent如何绕开静态Agent的问题,为静态的Agent建立绕行流场,并修改RVO2算法,在判断出Agent需要绕行时,从绕行流场中采样绕行方向,并朝着单一反向绕行。
静态Agent的绕行流场
绕行流场是一个全局的地图表示,只有静态的Agent会产生绕行流。绕行流场表示的是当Agent的位置在格子内无法通行时,选择绕行方向前进。如下图,绕行流的方向围绕着静态Agent,并朝着单一方向,并且多个静态Agent产生的绕行方向是叠加的,在两个静态Agent之间会得到走样的结果,但是只要这个间隔内不会有其他Agent闯入,就不需要担心。
在为RVO2算法引入绕行流场时,一般有以下几个问题需要解决:
- 地图的表示
- 流场的更新
- 绕行开始的条件
- 绕行方向的选择和采样
- 绕行状态结束的条件
绕行流场地图的表示
从上图可以很明显地看到,流场地图是使用格子地图表示的。在这种情况下,格子的大小是要比Agent的半径要小的。在表示相同大小的空间区域时,如果格子太小,要消耗更多的内存,太大会导致绕行方向不准确,因此要根据实际情况进行选择,上图中的格子大小是Agent半径的五分之二大小。
绕行流场的更新
流场的更新是在执行RVO2算法更新Agent速度之前。更新所有静态Agent周围的流场。主要的更新步骤为:
- 定位Agent的位置所在的格子
- 以Agent位置为圆心,在一定半径范围内计算覆盖到的格子
- 为每一个格子计算绕行方向
- 同一个格子的所有绕行方向叠加在一起作为该格子的绕行方向。
计算一个格子的绕行方向的方法是,取格子中心点到圆心的方向,将该方向逆时针旋转90°即可的得到绕行方向,每个格子都做该计算,就可以得到绕着Agent顺时针绕行的方向。计算伪代码如下
CenterDir = AgentCenter - GridCenter
AvoidDir = new Vector2(-CenterDir.y, CenterDir.x)
AvoidDir = normalize(AvoidDir)
只针对静态Agent进行处理。
更进一步地,在RVO2算法执行之后。对于由静止进入运动状态的Agent,要消除它对绕行流场的影响。
在最后给出的演示中,是对地图粗暴地进行清零操作。
绕行开始的条件
对于动态Agent而言,触发绕行的条件是当Agent距离目标点比较远,且RVO2算法在解线性规划时,得到的速度小于一定阈值则Agent进入绕行状态。
绕行方向的选择和采样
Agent在绕行状态下会采样绕行流场,获得一个平均的绕行方向,采样半径可以动态调节,采样点也可以往目标点方向靠近一点,这里就可以将这两个值用一个变量表示。方向的采样就是计算采样点所在格子附近一定半径范围内其他格子绕行方向和的平均值,这样可以使得处在绕行流场边缘处的Agent也可以获得绕行方向。
当通过采样仍然无法获得绕行方向时,可以根据Neighbor Agent的位置,估算一个绕行方向,估算的规则和绕行流场的生成类似,这里是为了获得一致的绕行方向。如下图所示,假设位于点P的Agent周围有4个静态的Agent,它的PrefVelocity是红色的箭头所指的方向。那么对于这4个静态Agent都计算他们的绕行方向,这里的例子依然是逆时针旋转。但是不是所有的方向都可选择,只有那些在PrefVelocity逆时针方向半圆区域内的方向是合法的,如下图,下方的箭头是需要剔除掉的,按半圆区域剔除的方法符合单方向绕行原则,这一点很重要,后面会介绍。
绕行方向的确定,以绕行流场采样的结果为主,而估算方法是作为补充的辅助方法,辅助方法也可以去掉,实测中发现,增加辅助方法后,Agent的路线会偏离比较远。
绕行状态结束的条件
Agent沿着绕行流场运行,何时结束也是一个需要解决的问题。如果仅仅只是判断Agent与目标点的距离小于一定阈值则停止,那么很可能Agent会环绕着静止的Agent运动,因为距离达不到阈值内。而仔细探究这个问题,需要回答的是一个Agent处于绕行状态时,在什么条件下恢复正常行进状态,沿着PrefVelocity的方向前进,并且能持续前进直到无法前进为止。因此可以肯定,是否要结束绕行状态,则要判断沿着PrefVelocity方向前进,是否可能会更好。
在本文给出的方案中,下面两个条件满足一个即可结束绕行状态:
- 绕行方向处于PrefVelocity方向的顺时针方向
- 绕行方向与PrefVelocity方向基本一致时
- 与目标点距离小于一定阈值
实测中发现,考虑第二个条件即可满足要求,但是偏差的夹角比较小。
当Agent沿着PrefVelocity方向前进时,再次遇到阻碍,会重新进入绕行状态。
单一方向绕行原则
单一方向绕行原则指的是绕行方向总是在PrefVelocity单面半圆内。如下图所示,当PrefVelocity向右,则绕行方向取上半平面的方向(上面的箭头),PrefVelocity指向左边时,绕行方向取下半平面的方向(下面的箭头)。这样在没有其他信息来判断哪个方向较好时,沿着单一的方向前进即可。当有其他信息可以判断出哪个方向更好时,可以去掉这个规则。
演示
下面的演示中,包含了上面所述的所有内容。