游戏思考17:寻路引擎recast和detour学习二:recast导航网格生成流程\源码剖析流程\局限性,附录计算点线面举例代码

本文详尽探讨了RecastNavigation的使用,包括体素化、过滤可行走面、构建高度场、区域划分、轮廓线生成、三角剖分和寻路算法。讲解了从模型到导航网格的转换过程,以及Detour如何利用导航网格进行A*寻路和漏斗算法平滑路径。此外,还讨论了RecastNavigation的局限性和与其他寻路方法的对比。

一、recastnavigation使用介绍

在这里插入图片描述
在这里插入图片描述

1)模式选择

Solo Mesh:单块生成
Tile Mesh:分块生成
Temp Obstacles:分块并支持动态阻挡

这里测试的话选单块生成

2)模型选择

官方自带3块地图,这里测试选择 nav_test.obj,点击build,生成NavMesh

在这里插入图片描述

二、导航网格介绍

  • 基础概念介绍
    一个导航网格是由多个凸多边形(Convex Polygon, Poly Mesh)组成的。Poly Mesh 有些时候也会简称为 Poly,即上图中的一个个色块部分。
  • 单位
    在导航网格中的寻路是以 Poly 为单位的。
  • 寻路简述
    在同个 Poly 中的两点,在忽略地形高度的情况下, 是可以直线到达的;如果两个点位于不同的 Poly,那么就会利用导航网格 + 寻路算法(比如A*算法)算出需要经过的 Poly,再算出具体路径。

1)子集介绍

  • 1.Recast:负责根据提供的模型生成导航网格。
  • 2.Detour:利用导航网格做寻路操作。这里的导航网格可以是 Recast 生成的,也可以是其他工具生成的。
  • 3.DetourCrowd:提供了群体寻路行为的功能。
  • 4.Recast Demo:一个很完善的 Demo,基本上将 Recast 、 Detour 提供的功能都很好地展现了出来。弄懂了这个 Demo 的功能,基本也就了解了 RecastNavigation 究竟可以干什么事。

2)导航网格的生成分为以下几个步骤:(目前生成Navmesh数据主要有两种方式:多边形裁剪和体素化,这里讲体素化)

  • 生成navmesh的两种方式
    1)多边形裁剪
    多边形裁剪是直接对地形的多边形网格数据进行裁剪及合并,从而生成导航网格。方法比较直观,但难度更高,目前havok引擎使用了此方法。
    2)体素化
    体素化是对地形多边形网格进行栅格化,然后用这些“格子”重新生成导航网格,方法更复杂,但难度更低,Recast使用了此方案,而UE4使用了Recast

3)recast流程介绍

  • 总体概述
    将以三角形集合形式表示的空间场景转化为可供寻路使用的导航数据(navmesh)

recast导航网格的生成会分为下面几个步骤:

1、场景模型体素化(Voxelization),或者叫“栅格化”(Rasterization)。
2、过滤出可行走面(Walkable Suface)
3、生成 Region
4、生成 Contour(边缘)
5、生成 Poly Mesh
6、生成 Detailed Mesh
  • 部分参数显示
cellSize------x、z方向上的体素精度
walkableSlopeAngle------agent的可行走最大坡度
walkableHeight------agent的可行走的最小高度空间
walkableClimb------agent的可攀爬高度
walkableRadius------agent的行走半径
float* bmin和float* bmax------场景的AABB包围盒
int* tris数组------场景的三角形序列
ntris------场景的三角形个数
float* verts------场景三角形各个顶点的坐标
nverts------场景三角形的顶点总数
  • 用图举例
    在这里插入图片描述
  • 上图参数介绍
    (如上图这个场景,包含3个三角形和5个顶点)
1)5个顶点的坐标用float* verts[3 * nverts]数组存储,分别表示nverts个顶点的x、y、z坐标,
nverts的值为5;
2)3个三角形用int* tris[3 * ntris]数组存储,分别表示ntris个三角形的3*ntris个顶点在verts数组中
的下标,ntris的值为3。
3)在这个例子中,verts[3 * nverts]数组的内容是
[x1,y1,z1,x2,y2,z2,x3,y3,z3,x4,y4,z4,x5,y5,z5],而tris[3 * ntris]数组的内容是
[0,1,2,1,2,4,2,3,4]。

(1)体素化

  • 简单介绍
    就是将整个场景模型,都转化为体素(Voxel)。

  • 过程介绍
    这一步处理和 GPU 渲染管线的光栅化流程概念是一样的,都是将矢量的模型信息(三角形),转化为点阵信息(像素或者体素)。开个脑洞, 假设将来有个全息显示器,可以在一个空间内渲染出制定的模型内容,渲染的最基本单位是体素而不是像素。那么到时的“显卡”很可能就是采取类似的模型体素化过程。
    在这里插入图片描述

在讲体素化之前,我们先来看下如何将一个凸多边形分隔成两个凸多边形。如下图的五边形,我们分析下 V6-V7 这条切割线分隔凸多边形的流程。
在这里插入图片描述
在这里插入图片描述
当遍历完所有边之后,我们就得到了两个子凸多边形 V1-V6-V7-V5和V6-V2-V3-V4-V7 。对应的代码为:

convex polygon 凸多边形
// divides a convex polygons into two convex polygons on both sides of a line
static void dividePoly(const float* in, int nin,
					  float* out1, int* nout1,
					  float* out2, int* nout2,
					  float x, int axis)
{
   
   
	float d[12];
	for (int i = 0; i < nin; ++i)
		d[i] = x - in[i*3+axis];

	int m = 0, n = 0;
	for (int i = 0, j = nin-1; i < nin; j=i, ++i)
	{
   
   
		bool ina = d[j] >= 0;
		bool inb = d[i] >= 0;
		if (ina != inb)
		{
   
   
			float s = d[j] / (d[j] - d[i]);
			out1[m*3+0] = in[j*3+0] + (in[i*3+0] - in[j*3+0])*s;
			out1[m*3+1] = in[j*3+1] + (in[i*3+1] - in[j*3+1])*s;
			out1[m*3+2] = in[j*3+2] + (in[i*3+2] - in[j*3+2])*s;
			rcVcopy(out2 + n*3, out1 + m*3);
			m++;
			n++;
			// add the i'th point to the right polygon. Do NOT add points that are on the dividing line
			// since these were already added above
			if (d[i] > 0)
			{
   
   
				rcVcopy(out1 + m*3, in + i*3);
				m++;
			}
			else if (d[i] < 0)
			{
   
   
				rcVcopy(out2 + n*3, in + i*3);
				n++;
			}
		}
		else // same side
		
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值