rvo动态避障算法源码分析

本文详细介绍了RVO(Reduced Velocity Obstacles)动态避障算法的原理,并通过源码分析了如何计算相对速度、调整速度以避免碰撞。文章探讨了线性规划方法用于在多智能体系统中选择合适的避障速度,确保速度方向接近最优目标速度的同时避免碰撞。此外,还讨论了代码中处理特殊情况的逻辑,如物体间已发生碰撞的情况。

rvo动态避障算法

源码: snape (Jamie Snape) · GitHub

文档: RVO2 Library - Reciprocal Collision Avoidance for Real-Time Multi-Agent Simulation

网友翻译的中文版文档:  导航动态避让算法RVO的优化ORCA(Optimal Reciprocal Collision Avoidance)_u012740992的专栏-优快云博客_orca算法

本文就rvo中动态避障的算法源码做一个简单分析

代码取自:https://github.com/warmtrue/RVO2-Unity 大约是2021-8-10这个时间取的,

是一个例子, 将rvo整合到unity里

rvo详可见上文链接

这里做一个简单的说明

RVO算法简要说明

运动的物体A与物体B,假设物体A的位置为坐标原点,并将A变成质点,

则B相应的半径增大,新的圆B记录CircleNew

如下图示,以原点为顶点,原点到CircleNew做切线,组成一个锥形区域(图中划横线的)

计算A,B之间的相对速度Va,如果Va位于锥形区域以外,则A B将不会发生碰撞,反之,则会在未来某个时间发生碰撞

进一步计算,假设时间取为t,

物体A的半径记为rA, B的半径记录rB, 位置分别为PA ,PB

CircleNew圆记位于PB - PA 半径为rA + rB,

对整个坐标系进行缩放1/t,这样速度的单位就变成秒

原来的大圆,就缩放为圆心 (PB-PA)/t 半径为(rA+rB)/t,这个新圆被称为截止圆cutoff-circle

可以看出速度的选择范围如以下右图所示,除了灰色圆头锥型区域以外,白色区域都是可选的相对速度Vr=Va-Vb(Va Vb分别为A,B的速度)方向以及大小.如图中的蓝色速度与红色速度

如果Vr速度位于灰色的锥型区,就需要调整速度至空白区域,即给速度加个分量

如下图的蓝色小箭头,这种情况下的相对速度,就需要往旁边调整,锥形区域中的切边,被称为leg

根据速度的方向大小,也有可能往cutoff-circle处调整或另一条leg处调整

如下图,往cutoff-circle处调整相对速度Vr,

这个调整的速度分量我们称之为u,

物体A调整后的速度为 Va-new = Va + u,

令A和B各负责一半的速度调整,则Va-new = Va + 0.5 *u

这样即可保证A B在t时间内不会碰撞

选取了u为调整分量后,可以发现,Va-new的取值是一个半平面,

这个半平面的分割线是以垂直向量u为方向,过点Va+0.5*u的直线,在此处称之为line

在这个半平面的一侧速度都可以为备选速度

### Unity RVO 动态避障算法的实现与使用 #### 1. 基础概念 RVO(Reciprocal Velocity Obstacles)是一种高效的动态避障算法,适用于多人或多物场景中的实时路径规划。该算法的核心在于计算每个物体的速度障碍区域,并通过调整速度来避免碰撞[^1]。 在Unity中实现RVO动态避障的关键步骤包括以下几个部分: - **初始化环境**:创建一个支持导航的地图或网格结构,通常可以通过Unity自带的NavMesh系统或者第三方插件(如A* Pathfinding Project)完成。 - **定义代理对象**:为每一个需要避障的对象设置属性,例如半径、最大速度和目标方向。 - **计算速度障碍**:对于每个代理对象,基于周围其他对象的位置和运动状态,计算出其速度障碍区域。 - **更新速度向量**:根据速度障碍的结果,重新计算并应用新的速度向量以避开潜在的冲突。 #### 2. 实现细节 以下是具体实现过程中的一些重要技术点及其说明: ##### (a) 初始化 NavMesh 或自定义地图 如果项目允许使用Unity官方的NavMesh组件,则可以直接利用`NavMeshAgent`类作为基础框架;但如果需要更高的灵活性,可以选择像A* Pathfinding这样的插件[^3]。 ```csharp // 使用 Unity 官方 NavMeshAgent 的简单配置 using UnityEngine; using UnityEngine.AI; public class RVODemo : MonoBehaviour { public Transform target; // 设置目标位置 private NavMeshAgent agent; void Start() { agent = GetComponent<NavMeshAgent>(); if (agent != null && target != null) agent.SetDestination(target.position); } } ``` ##### (b) 计算相对位置与速度障碍 为了有效执行RVO逻辑,需针对每一对相互作用的实体分别求解它们之间的相对距离以及由此产生的约束条件[^4]。 ```csharp private List<Vector2> ComputeRVOLines(List<GameObject> others, float radiusSum, Vector2 relPos) { var lines = new List<Vector2>(); foreach (var other in others) { var diff = this.transform.position - other.transform.position; var distSq = diff.sqrMagnitude; if (distSq > Mathf.Epsilon) { var leg = Mathf.Sqrt(distSq - radiusSum * radiusSum); // 构造线的方向矢量 var lineDirX = relPos.x * leg - relPos.y * radiusSum; var lineDirY = relPos.x * radiusSum + relPos.y * leg; lines.Add(new Vector2(lineDirX / distSq, lineDirY / distSq)); } } return lines; } ``` ##### (c) 调整最终速度 依据所得到的所有候选直线集合筛选最优解,并将其赋给对应角色的实际前进速率[^1]。 ```csharp void UpdateVelocity(Vector2 preferredVel, List<Vector2> rvoLines) { bool conflictFound = false; int bestIndex = -1; float minDistToLine = float.MaxValue; for(int i=0;i<rvoLines.Count;i++) { var projLen = Vector2.Dot(preferredVel, rvoLines[i]); if(projLen >= 0){ continue; // 不考虑正面投影的情况 }else{ // 找到最近的有效切分面 var tempDist = Math.Abs(projLen)/Mathf.Sqrt(1-Mathf.Pow(rvoLines[i].magnitude,2)); if(tempDist < minDistToLine){ minDistToLine = tempDist; bestIndex = i; conflictFound=true; } } } if(conflictFound){ // 更新至安全区域内最接近期望值的新速度 var adjustedSpeed = GetSafeVelocity(bestIndex,rvoLines,minDistToLine); rigidbody.velocity=new Vector3( adjustedSpeed.x, rigidbody.velocity.y,//保持垂直轴不变 adjustedSpeed.y ); } } Vector2 GetSafeVelocity(int index,List<Vector2> lines,float marginFactor){ ... } ``` 以上代码片段展示了如何逐步构建起完整的RVO机制,尽管实际部署时还需进一步优化性能及处理边界情况等问题。 --- ###
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值