Unreal RecastNavigation 开源项目详解
0 前言
Recastnavigation是一个游戏AI导航库,像Unity,UE引擎中都集成了这个开源项目, HALO中使用的也是这个开源库。导航最重要的就是为NPC寻路,以及其他的寻路需求。
需要注明的是,这个寻路库虽然厉害。但是他的核心是 平面寻路。也就是重力方向一直朝着 -Y
方向。如果是星球地形,既重力方向朝向球心,在任何一点重力方向都是不同的。那么这个开源库就不能使用了。
1 Recastnavigation 下载与编译
主页: https://github.com/recastnavigation/recastnavigation/tree/main?tab=readme-ov-file
编译: https://github.com/recastnavigation/recastnavigation/blob/main/Docs/_2_BuildingAndIntegrating.md
编译细节
这个项目 Recast and Detour 不依赖其他的一些库,但是 RecastDemo 即可视化的示例是需要SDL2库的,SDL2库可以理解为创建窗口应用程序所需要的库。所以我们需要下载SDL。
同时也需要 premake5 编译工具。
1.1 Windows
- Grab the latest SDL2 development library release from https://github.com/libsdl-org/SDL and unzip it into RecastDemo/Contrib. Rename the SDL folder such that the path RecastDemo/Contrib/SDL/lib/x86 is valid.
SDL2-devel-2.28.2-VC.zip 像这样的文件名的release才可以,不要直接下载 source code
// 成功后的文件夹应该是这个样子。
RecastDemo/Contrib
fastlz
readme-sdl.txt
SDL
stb_truetype.h
●Navigate to the RecastDemo
folder and run premake5 vs2022
●Open Build/vs2022/recastnavigation.sln in Visual Studio 2022 or Jetbrains Rider.
●Set RecastDemo as the startup project, build, and run.
2. 代码详解
// Figure out how big the raster voxel grid will be based on the input geometry bounds.
rcCalcGridSize
// Voxelize the input geometry
rcAllocHeightfield
rcCreateHeightfield
rcMarkWalkableTriangles
rcRasterizeTriangles
// Clean up the voxel data and filter out non-walkable areas.
rcFilterLowHangingWalkableObstacles
rcFilterLedgeSpans
rcFilterWalkableLowHeightSpans
// Consolidate the voxel data into a more compact representation
rcAllocCompactHeightfield
rcBuildCompactHeightfield
// Further refine the voxel representation
rcErodeWalkableArea
rcBuildDistanceField
rcBuildRegions
// Triangulate the navmesh polygons from the voxel data
rcAllocContourSet
rcBuildContours
rcAllocPolyMesh
rcBuildPolyMesh
// Package the mesh with additional metadata that's useful at runtime.
rcAllocPolyMeshDetail
rcBuildPolyMeshDetail
// Cleanup
rcFreeHeightField
rcFreeCompactHeightfield
rcFreeContourSet
代码详解主要为2个部分。
- 数据载入
- 高度场建立
2.1 数据载入
首先Sample_SoloMesh::handleBuild()
会调用InputGeom::getMesh()
那么Mesh数据从哪里来呢?
InputGeom::loadMesh()
InputGeom::load()
rcMeshLoaderObj::addVertex(float x, float y, float z, int& cap)
其中cap是顶点的内存容量,以存8个顶点为开始,内存短缺后以2倍速度扩大。存储皆为1维数组,顶点与顶点之间的stride==3
。void rcMeshLoaderObj::addTriangle(int a, int b, int c, int& cap)
有了Mesh之后,开始计算xz平面的栅格数量,设置为 *sizeX = &m_cfg.width, *sizeZ = &m_cfg.height
。平面边缘,只要占到一半以上的cellSize
,就认为是一个cell。
void rcCalcGridSize(const float* minBounds, const float* maxBounds, const float cellSize, int* sizeX, int* sizeZ)
{ // (0, 0.5) + 0.5 -> 0
// [0.5, 0.999) + 0.5 -> 1
*sizeX = (int)((maxBounds[0] - minBounds[0]) / cellSize + 0.5f);
*sizeZ = (int)((maxBounds[2] - minBounds[2]) / cellSize + 0.5f);
}
rcCreateHeightfield(m_ctx, *m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)
相当于构造函数,初始化高度场信息HeightField or HeightMap
。
m_triareas = new unsigned char[ntris];
角色代理可以走的三角形。
rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, verts, nverts, tris, ntris, m_triareas);
这个的关键就是三角形的法向量的 y
分量,等于三角形面与 x-z
平面的夹角 cos
值。运用相似三角形。
2.2 高度场建立
主要就是利用x-z平面的网格与映射到平面上的三角形的交点,通过相似三角形获得这个交点 (x-z)-> Y
在三维三角形的高度。
这个切割方法是 Sutherland-Hodgman polygon-clipping algorithm
的变种。
Sutherland-Hodgman polygon-clipping algorithm
- 这个算法最重要的就是判断顶点在 切割窗口某一条 Edge 两侧的哪一侧。
- Edge存在切割窗口的那一侧是 in, 不存在则是 out.
https://stackoverflow.com/questions/21638509/determine-voxels-that-a-triangle-is-in
Abhishek Sharma : https://www.youtube.com/watch?v=OGW9Cqr5RRg&t=333s&pp=ygUTIFN1dGhlcmxhbmQtSG9kZ21hbg%3D%3D
2.2.1 高度场建立的核心函数。
bool rcRasterizeTriangles(rcContext* context,
const float* verts, const int /*nv*/,
const int* tris, const unsigned char* triAreaIDs, const int numTris,
rcHeightfield& heightfield, const int flagMergeThreshold)
{
rcAssert(context != NULL);
rcScopedTimer timer(context, RC_TIMER_RASTERIZE_TRIANGLES);
// Rasterize the triangles.
const float inverseCellSize = 1.0f / heightfield.cs;
const float inverseCellHeight = 1.0f / heightfield.ch;
for (int triIndex = 0; triIndex < numTris; ++triIndex)
{
const float* v0 = &verts[tris[triIndex * 3 + 0] * 3];
const float* v1 = &verts[tris[triIndex * 3 + 1] * 3];
const float* v2 = &verts[tris[triIndex * 3 + 2] * 3];
if (!rasterizeTri(v0, v1, v2, triAreaIDs[triIndex], heightfield, heightfield.bmin, heightfield.bmax, heightfield.cs, inverseCellSize, inverseCellHeight, flagMergeThreshold))
{
context->log(RC_LOG_ERROR, "rcRasterizeTriangles: Out of memory.");
return false;
}
}
return true;
}
2.2.2 图解
每个 cell
上面是一个 spanList
。 他存储着所有在这个cell上面的 所有 三角形在这个cell上的高度信息。
X. Ref
- A* : https://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#heuristics-for-grid-maps
- UE DOC: https://www.unrealdoc.com/p/navigation-mesh
Unreal RecastNavigation 开源项目详解的更多相关文章
- eclipse里面构建maven项目详解(转载)
本文来源于:http://my.oschina.net/u/1540325/blog/548530 eclipse里面构建maven项目详解 1 环境安装及分配 Maven是基于项目对象模 ...
- JAVA Eclipse使用Maven构建web项目详解(SSM框架)
tips: 启动项目后,welcome-file的链接即为测试用例 部署maven web项目 Eclipse使用Maven构建web项目详解 pom.xml添加webapp依赖: <depen ...
- [转帖](整理)GNU Hurd项目详解
(整理)GNU Hurd项目详解 http://www.ha97.com/3188.html 发表于: 开源世界 | 作者: 博客教主 标签: GNU,Hurd,详解,项目 Hurd原本是要成为GNU ...
- Redis 配置文件 redis.conf 项目详解
Redis.conf 配置文件详解 # [Redis](http://yijiebuyi.com/category/redis.html) 配置文件 # 当配置中需要配置内存大小时,可以使用 1k, ...
- Mac下Intellij IDea发布Web项目详解一
Mac下Intellij IDea发布Web项目详解一 Mac下Intellij IDea发布Java Web项目(适合第一次配置Tomcat的家伙们)详解二 Mac下Intellij IDea发布J ...
- Mac下Intellij IDea发布Java Web项目详解五 开始测试
测试前准备工作目录 Mac下Intellij IDea发布Web项目详解一 Mac下Intellij IDea发布Java Web项目(适合第一次配置Tomcat的家伙们)详解二 Mac下Intell ...
- 利用Intellij+MAVEN搭建Spring+Mybatis+MySql+SpringMVC项目详解
http://blog.csdn.net/noaman_wgs/article/details/53893948 利用Intellij+MAVEN搭建Spring+Mybatis+MySql+Spri ...
- tomcat通过tomcat 安装根目录下的conf-Catalina-localhost目录发布项目详解
tomcat通过conf-Catalina-localhost目录发布项目详解 Tomcat发布项目的方式大致有三种,但小菜认为通过在tomcat的conf/Catalina/localhost目 ...
- python选课系统项目详解
选课系统项目详解 选课系统简介及分析 选课系统架构设计分析 选课系统目录设计 管理员视图 注册 登录 创建学校 创建课程 创建讲师 学生视图 注册 登录 选择学校 选择课程 查看分数 教师视图 登录 ...
- Usage、Usage Minimum和Usage Maximum项目详解
(1)一个产生多个数据域(Report Count>1)的主项目之前有一个以上的[用途]时,每个[用途]与一个数据域依次对应,如果数据域个数(Report Count)超过[用途]的个数,则剩余 ...
随机推荐
- 一群伪专家讨论“motherland”和“fatherland”,说说个人的观点
看了一个视频: 中国的文化里在找妈,美国的文化里在找爸!如何真正教育子女? ============================================= ================ ...
- Linux的netns使用总结
转载请注明出处: Linux的netns(Network Namespace)是Linux内核提供的一项强大的网络隔离功能,它能够创建多个独立的网络空间,每个空间都拥有自己独立的网络协议栈,包括网络接 ...
- br4gOnB4ll靶机笔记
br4gOnB4ll靶机笔记 这是一台vulnhub上的免费靶机,比较简单. 1.主机发现 主机发现 -sn 只做ping扫描,不做端口扫描 nmap -sn 192.168.84.1/24 Star ...
- SCC缩点模板
struct SCC { int top = 0, cntscc = 0, dfncnt = 0, n; vector<int> dfn, low, stk, instk; vector& ...
- check Str's Character appearence frequence is ge 1
import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; import java.util.*; public class HackerRa ...
- 2024-08-24:用go语言,给定一个下标从1开始,包含不同整数的数组 nums,数组长度为 n。 你需要按照以下规则进行 n 次操作,将数组 nums 中的所有元素分配到两个新数组 arr1 和
2024-08-24:用go语言,给定一个下标从1开始,包含不同整数的数组 nums,数组长度为 n. 你需要按照以下规则进行 n 次操作,将数组 nums 中的所有元素分配到两个新数组 arr1 和 ...
- BooleanBuilder 如何根据自定义列名 模糊查询 使用PathBuilder
// 动态传参 // 1. 声明 PathBuilder:MyTable 为类名称,"myTable" 为首字母小写后的类名 PathBuilder<MyTable> ...
- vue serve 部署 步骤说明
1. 构建镜像 docker build -t 镜像名称:镜像TAG --build-arg URL=http://localhost:8081 --build-arg PORT=2000 --bui ...
- 中国信通院高质量数字化转型产品及服务全景图发布,合合信息多项AI产品入选
随着5G.人工智能.大数据等新一代技术的发展,企业在商业竞争中正面临更多不确定性.中国信通院高度关注企业数字化转型中遇到的痛点,发起"铸基计划-高质量数字化转型行动",链接企业数字 ...
- OCR技术的昨天今天和明天!2023年最全OCR技术指南!
OCR是一项科技革新,通过自动化大幅减少人工录入的过程,帮助用户从图像或扫描文档中提取文字,并将这些文字转换为计算机可读格式.这一功能在许多需要进一步处理数据的场景中,如身份验证.费用管理.自动报销. ...