CAINav是用于一个基于windows系统下为.net和unity3d工程提供的导航系统。他提供导航网格生成,寻路,本地操作功能。
NMGen:导航网格生成
可以遍历任何几何模型表面来生成多边形网格。
分离寻路和操作组件,提供更灵活的工作流程和分配方式。
构建简单,只需一个配置和一些几何源。
可根据需要定制构建过程。
各种网格序列化选项。
当然它也可以构建三角形网格。
NMQuery:寻路
A *和Dijsktra两种算法搜索路径。
快速在各种局部环境中查询,没有搜索行为。
易于管理的路径。
非标准运动网的不同地区之间的自定义连接。(Off-mesh connections。)
能为每一个代理(可以看为游戏角色)启动/关闭多边形运动。(Polygonfiltering)。
可以定义每个代理遍历多边形的运动的消耗。(路径越长消耗越大)
tiling和分层网格来处理巨大/很高的几何模型。
各种导航网格序列化选项。
NMCrowd:本地操作
为20个以上代理提供本地操作/碰撞回避功能。
每个代理能对面前的其他代理产生反应。
跟随和群体运动。
一.下载Download,这里有一个例子包,一个正式的开发包,我们下载cai-nav-0.3.0.zip。
解压后找到cai-nav-0.3.0\u3d\cai-nav-pro-0.3.0.unitypackage
二.导入,打开我们的unity项目,Assets->Import Package->Custom Package…找到包所在位置。
三.你会发现菜单里面多了两个子菜单项GameObject-> Create CAI 和Component->CAI.
导航网格生成
有多种方法来生成一个导航网格。但它们都遵循相同的基本过程:
1. 在场景上添加一个几何数据源组件并在上面添加GameObjects。
2. 添加一个NMGenBuildConfig组件到场景上。
3. 添加一个BakedPolyMesh组件到场景上,并指定几何模型和配置。
4. 根据自己的需要调整配置。
5. 烘焙网格
6. 如果需要,调整配置再烘烤,直到得到你想要的。
你可以手动添加每个组件到场景上,GameObject->Create CAI菜单项让事情变得简单,PolyMesh菜单项提供需要的NMGen组件来构建多边形和细节网格。Navigation Manger 和 Navmesh则提以使用CAINav导航功能所需要的额外组件。
如果你选择PolyMesh菜单项,你将看到下面的对话框:
如果你想手动指定game objects。选择MeshFilter (Array)。如果希望gameobject的选择基于一个或者多个标签,选择MeshFilter(Tagged)项。无论哪种情况,你只需选择或者创建最上层的game objects然后其所有子game object都会被MeshFilter递归检索到。
会生成类似下面的GameObject结构:
一个示例场景
在这个例子中,包含三个GameObjects,他们则包含了一个室内环境的所有模型。
在这种情况下,最好的选择是使用MeshFilter(Array)作为几何源。因此,从菜单中选择GameObject->Create CAI->PolyMesh,并使用默认配置。然后指定gameobjects的几何源。
这个特殊场景是按照正常人类的比例来缩放的,我们调整了一些重要的配置。其余的设置通常是基于源的几何模型的类型和大小。使用DeriveConfiguration 按钮,将得到一个良好的开始。
一切准备就绪,按下Bake Mesh按钮来生成多边形和细节网格。并根据需要修改配置后再烘焙。我们就能得到需要的导航网格。
启动和运行导航的基本步骤如下:
1. 添加一个BakedPolyMesh.
2. 添加一个NavmeshTileBridge组件到场景并且指定BakedPolyMesh给他。
3. 添加一个BakedNavmesh组件到场景并且指定NavmeshTileBridge给他
4. 烘焙导航网格
5. 添加一个NavSource组件到场景并且指定BakedNavmesh给他
在运行时,NavSource提供你的脚本使用下面的对象:
- U3DNavmeshQuery
- NavmeshQueryFilter
- Navmesh
- CrowdManager (Optional)
- An extents array. (Used by various query methods.)
选择GameObject->Create CAI->Navigation Source会看到
如果选择默认配置,会得到下面的结构:
U3DNavmeshQuery是一个非常重要的类,我们生成了导航网格的数据,这个类为我们在这些数据里面寻路提供了几乎所有必需的功能。
查询功能分为两大类:寻路和本地搜索。
寻路使用标准的A*和Dijkstra算法来找到两点之间的最佳路径。路径由多边形引动列表构成,包含了通道的开始到结束点。路径会被校正成为寻路点列表。
局部搜索特性提供了
许多查询方法需要一个NavmeshQueryFilter.Filters定义区域id的消耗成本(遍历成本)。
理解query类最好的方式就是使用他,Sample Pack包含的Query Explorer demo可以试验所有的查询特性。
在导航网格里面寻找一个点
不首先在导航网格上找到一个有效点,你将什么也不能做。所以第一步是找到这样一个点。
方法:GetNearestPoly(Vector3,Single[], NavmeshQueryFilter, NavmeshPoint)
// 这里的'query'是一个U3DNavmeshQuery 对象,'filter'是一个NavmeshQueryFilter 对象.
NavmeshPoint result;
float[] extents = new float[3] { 1, 1, 1 }; // Keep this to the minimum extentspractical.
NavStatus status = query.GetNearestPoly(point
,extents, filter
, outresult);
if (result.polyRef == 0)
{
// Handle error. Could not find a result.
// 这个状态可以检查下是否有什么错误,如果没有
// 则可能是搜索区域不在任何多边形内。
}
// Use the result point, which includes a vectorposition and the reference id of
// the polygon that contains the point.
基本寻路
如果你想使用PathCorridor或者CrowdManager,你总是需要长远规划使用NavmeshQuery的基本特性。首先,找到一条路径,然后,校正他。
//这里的'query'是一个U3DNavmeshQuery 对象,'filter'是一个NavmeshQueryFilter 对象.
// 'start' 和 'end' 是 NavmeshPoint 在导航网格上.
int pathCount;
// 该路径将是多边形引用列表.
uint[] path = new uint[100]; // 最大路径长度
NavStatus status;
if (start.polyRef == end.polyRef)
{
// Noneed to do any planning.
pathCount = 1;
path.path[0] = start.polyRef;
}
else
{
status= query.FindPath(start
, end
, filter
, path
, out pathCount);
if(NavUtil.Failed(status)
|| path.pathCount == 0)
{
// 寻路失败处理.
}
else if(end.polyRef != path[pathCount - 1])
{
// 处理一部分路径.
// 也许查询无法找到终点,
// 或者路径缓冲太小无法保存整个路径
// (检测 'status' 可以发现是否是缓冲太小)
}
}
// 如果需要矫正路径...
const int MaxStraightPath = 4; // Just getting the first 4 waypoints.
int wpCount;
// The waypoints. (x, y, z) * wpCount;
float[] wpPoints = new float[MaxStraightPath * 3];
WaypointFlag[] wpFlags = newWaypointFlag[MaxStraightPath];
// A list of polygon references. (The polygon being entered at the waypoint.)
uint[] wpPath = new uint[MaxStraightPath];
status = query.GetStraightPath(start.point
,goal.point
, path
,0 // The index of thestart of the path.
,pathCount // The length of thepath.
,wpPoints
,wpFlags
,wpPath
, outwpCount);
if (NavUtil.Failed(status) || wpCount == 0)
{
//Handle the failure. There should alwaysbe at least one waypoint,
thegoal point, for a valid point/path combination,
}
// Use the path and waypoints.