由于我们的项目采用的寻路解决方案是:客户端使用 unity 原生的寻路系统,服务器采用 RecastNavigation 系统,而服务器的寻路数据来自于从 unity 导出的,所以理论上两边的寻路结果应该是一样的,可事实上并非如此,unity 无论如何寻路,都能表现出比较自然的结果,但是服务器却有时会出现比较奇怪的结果。

  由以上三张截图可以看到,起始点和终点稍微有点变化,结果就会出现较大的差异,寻路结果往往会“拐弯”,这种结果势必是不能接受的,unity 里不会出现这种情况,经过多次试验并仔细查看和分析,发现是因为寻路网格里出现了过于“细长”的三角形导致的,那如何修改呢,我在官方论坛里向作者(Mikko Mononen)提问(原帖地址点这里,自行解决 FanQiang 问题):1.我觉得 unity 的寻路系统是基于原作者的 RecastNavigation 系统编写的;2.这种结果是否是由“细长”三角形导致的,该如何解决呢?

  很开心作者很快就恢复了:1.unity 的寻路系统确实是基于 RecastNavigation 编写的,但是 Detour 系统已经被深度改写了,(后来发现作者的 twitter 简介是 unity 的 ai 程序员);2.这个问题确实由于“细长”三角形引起的,NavMesh 系统当遇到特别宽或者三边长度比特别大的三角形时会出问题。而作者很久前就在自己的博客里叙述过这个问题,并给出了解决方案,博客地址:

 
解决方法是:改变A*寻路结果中节点的放置处理,NavMesh 系统里默认使用多边形边的中点来作为路径通过的点,如果想要好看的结果,应该使用距离最近的点,即你有 A, A 两个点在一条线段 L 的两边,那么这个点应该是线段 AB 和线段 L 的交点。
 
 if (neighbourNode->flags == )
{
float sa[], sb[];
getPortalPoints(bestRef, bestPoly, bestTile,
neighbourRef, neighbourPoly, neighbourTile,
sa, sb);
float t = 0.5f;
dtDistancePtSegSqr2D(endPos, sa,sb, t);
t = dtClamp(t, 0.1f, 0.9f);
dtVlerp(neighbourNode->pos, sa,sb, t);
}

这段代码在:

 
也可以使用 "bestNode->pos" 替换 "endPos",这样就可以使用“最近”的点来替换当前 A* 里的“终点”,同时作者指出,像我这种客户端和服务器的解决方案都只能不断的调节调试去优化视觉上的结果,并不存在一个百分百准确的方案,不过很开心的是,这样修改完一实验,果然结果“正常”了,现在客户端和服务器的寻路90%的情况都能保持一致,极个别的情况还是会有差异,不过结果不会再特别“奇怪”,所以已经很满足了,太感谢原作者 mikko 同学了。
 
  题外话,上面这小段代码原来使用的是 getEdgeMidPoint 来求中点,作者用的 dtDistancePtSegSqr2D 这个函数是用来计算点 endPos 到线段 sa 和 sb 的垂直距离直线的交点 t,t 的数值就是线段 sa-t 和 线段 t-sb 的长度比值。当然这个结果不错了,但是还不是最好的,作者的原博客使用的是 dtIntersectSegSeg2D(ap, aq, bp, bq, s, t),计算的是线段 ap-aq 和线段 bp-bq 交点 m 在两条线段上的比值 s = ||ap-m|| / ||m-aq||,t = ||bp-m|| / ||m-bq||,这样一来计算出来的才是真正的最近距离,两点之间直线最短嘛;这个函数非常有意思,内部使用了 PertDotProduct 这个数学公式,这个才是最有意思的,但不太容易理解,就是向量 A 和向量 B 的 PertDotProduct 结果为:A 的法向量和向量B 的点乘积,几何意义是两条线段组成的平行四边形的面积(||a||.||b||.sina),而两条线段的交点分别在每个线段上的比值,正好可以通过计算 PertDotProduct 的比值来获得,因为他们组成了一个共底边的平行四边形,所以面积比等于高之比,而高正好分别就是其中一条线段的起点到交点的距离和起点到终点的距离。我自己的解决方案是选用的最后一种 dtIntersectSegSeg2D,效果也是最好的。
  最近一直太忙,都没更新,其实积累了很多心得在我的印象笔记里,慢慢补充到这里吧。
 
 

关于 RecastNavigation 寻路结果异常的问题。的更多相关文章

  1. 从 NavMesh 网格寻路回归到 Grid 网格寻路。

    上一个项目的寻路方案是客户端和服务器都采用了 NavMesh 作为解决方案,当时的那几篇文章(一,二,三)是很多网友留言和后台发消息询问最多的,看来这个方案有着广泛的需求.但因为是商业项目,我无法贴出 ...

  2. 如何制作RTS游戏的寻路系统?

    Q1:我们在做一个RTS游戏,开始用的是Unity自带的NavMesh的寻路,但发现这个并不适合RTS多人寻路,因为总会出现阻挡和闪跳的问题.看Asset Store上的A* path插件评论说在碰撞 ...

  3. CritterAI与Recast Navigation寻路

    版权声明:本文为博主吴欣伟原创文章,未经博主允许不得转载. 前言 这篇文章写于去年,由于工作需要,故写出这个研究文档,发现网上有关此寻路库的中文资源十分稀少,故发布出来与诸位共享交流,如文中有不对之处 ...

  4. RecastNavigation(3D场景建模、网格导航)

    一.RecastNavigation详解 RecastNavigation定义: RecastNavigation是一个导航寻路工具集,使用邻接的凸多边形集合描述一个3D场景,A*寻路算法使3D场景的 ...

  5. Recastnavigation 创建 off-mesh link 的潜规则

    Recastnavigation 在创建off-mesh link 时,发现有的off-mesh link 无法寻路(虽然在地图上能看到off-mesh link 的连线   在Google Grou ...

  6. alias导致virtualenv异常的分析和解法

    title: alias导致virtualenv异常的分析和解法 toc: true comments: true date: 2016-06-27 23:40:56 tags: [OS X, ZSH ...

  7. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  8. 记一次tomcat线程创建异常调优:unable to create new native thread

    测试在进行一次性能测试的时候发现并发300个请求时出现了下面的异常: HTTP Status 500 - Handler processing failed; nested exception is ...

  9. 使用JSONObject.fromObject的时候出现“There is a cycle in the hierarchy”异常 的解决办法

    在使用JSONObject.fromObject的时候,出现“There is a cycle in the hierarchy”异常.   意思是出现了死循环,也就是Model之间有循环包含关系: ...

随机推荐

  1. MYSQL命令cmd操作

    今天我们就来看一下数据库的各种命令,以下命令全部是从CMD命令窗口下的命令行输入指令,首先如果如果输入mysql,系统提示“mysql不是内部命 令或外部命令.那么这其实是环境变量没有设置好的原因,例 ...

  2. Ajax 异步 XMLHttpRequest

    1.GET方式             1.1设置参数             xhr.open("GET", "GetAreasByAjax.ashx?isAjax=1 ...

  3. 文件操作 系统备份和还原,压缩,解压 tar dump/restore

    基本操作命令: ls -a 显示指定目录下的目录和文件,包括隐藏的文件和目录 ls -l 将文件和目录详细列出来,包括文件状态,权限,拥有者,文件名,文件大小等 改变工作目录命令 cd cd .. 进 ...

  4. 非常实用的JQuery的选项卡切换源码

    <html> <head> <meta charset="utf-8"> <title>简单选项卡</title> &l ...

  5. echo和print语句

    在php中,有两种基本的输出方法:echo  和  print echo 和 print 之间的差异: echo——能够输出一个以上的字符串,无返回值 print——只能输出一个字符串,并始终返回值为 ...

  6. Python全栈开发-web框架之django

    一:web框架 什么是web框架? Web应用框架(Web application framework)是一种开发框架,用来支持动态网站.网络应用程序及网络服务的开发.这种框架有助于减轻网页开发时共通 ...

  7. load-store/register-memory/register-plus-memory比较

    在理解ARM的load-store架构时,我在百度上搜索了很长时间,但是始终找不到一篇像样的中文文章.最后,在用谷歌搜索的英文网站上终于找到了一些蛛丝马迹.让我们先看一下一篇英文资料. Process ...

  8. 警惕arm-linux-gcc编译器优化选项

    arm-linux-gcc的优化选项例如(-O2),可以加速我们的程序,使程序执行效率更高.但是,倘若我们就是需要程序慢一点运行,但是优化却把我们的延时函数优化的没有了的时候,这种优化却不是我们想要的 ...

  9. POJ 1472 Instant Complexity 应该叫它编程题。。

    题目:http://poj.org/problem?id=1472 这个题目是分到“模拟题”一类的,我觉得模拟的成分比较少,主要考察编程能力.独立写完这个题特别兴奋...所以我必须好好说一说,独家哦. ...

  10. 国内外最全的asp.net开源项目 (转)

    最近一些项目开始用到CMS系统,最开始是研究JAVA的,无奈国内JAVA的CMS开源系统还是比较少,最多最成熟的还是PHP的,当然现在.NET的也不少了,这里做一下汇总备忘,留待学习研究. 国内系统: ...