关于UE引擎层面的东西:
  1. 在向场景重拖入一个NavMeshBoundsVolume时(或者修改时). 会调用
void UNavigationSystemV1::PerformNavigationBoundsUpdate(const TArray& UpdateRequests)
然后会 创建/更新 一个NavigationData Actor对象到场景中, 名字默认是RecastNavMesh-Default
  1. 在增加NavMeshBoundsVolume后的调用堆栈如下. 可以看到最后是把请求放到了PendingDirtyTiles里了. 走异步烘培
void UNavigationSystemV1::PerformNavigationBoundsUpdate
void ANavigationData::OnNavigationBoundsChanged
NavDataGenerator->OnNavigationBoundsChanged();
void FRecastNavMeshGenerator::OnNavigationBoundsChanged()
void FRecastNavMeshGenerator::MarkDirtyTiles -> PendingDirtyTiles
  1. 异步烘培的驱动堆栈如下, 可以看到是从World的Tick到ProcessTileTasksAsyncAndGetUpdatedTiles函数里. 这个函数里取出来PendingDirtyTiles里记录的异步请求. 执行
TArray FRecastNavMeshGenerator::ProcessTileTasksAsyncAndGetUpdatedTiles
TArray FRecastNavMeshGenerator::ProcessTileTasksAndGetUpdatedTiles
void FRecastNavMeshGenerator::TickAsyncBuild(float DeltaSeconds)
void UNavigationSystemV1::Tick
void UWorld::Tick
  1. 在ProcessTileTasksAsyncAndGetUpdatedTiles函数里创建了一个TileTask(调用CreateTileGenerator函数构造一个Generator初始化了Task)
上面这一行很关键,一点点的解释下;
1) 查看FRecastTileGeneratorTask的定义, 可以看到FRecastTileGeneratorTask其实是一个FAsyncTask
2) MakeUnique 是个模板函数, 功能是首先调用CreateTileGenerator(PendingElement.Coord, PendingElement.DirtyAreas)这个函数, 用它的返回值作为参数构造FRecastTileGeneratorTask
也就是构造FAsyncTask
 
3) FRecastNavMeshGenerator::CreateTileGenerator这个函数接受了coord和dirtyAreas作为参数, 调用了另外一个模板函数ConstuctTileGeneratorImpl. 返回一个TSharedRef 类型
4) 接着看ConstuctTileGeneratorImpl模板函数, 使用this指针, 也就是FRecastNavMeshGenerator和Coord参数构造了一个FRecastTileGenerator, 并调用了FRecastTileGenerator的Setup函数, 传入了this和DirtyAreas参数.
然后把完成初始化的FRecastTileGenerator返回出去.
5) 然后回到2)步里创建Task的过程里. 使用CreateTileGenerator返回的TSharedRef作为参数构造了FAsyncTask
然后看FAsyncTask的构造函数, 可以看到FAsyncTask是一个模板类, 含有一个TTask Task成员, 就是模板的类型FRecastTileGeneratorWrapper, 构造函数里把接收到的参数传递给了Task的构造函数
也就是FRecastTileGeneratorWrapper的构造函数, FRecastTileGeneratorWrapper里的TileGenerator成员就被初始化成4)里构造并调用过Setup的FRecastTileGenerator对象了.
6) 综上, 就完成了一个FAsyncTask的构建, 其中持有了一个FRecastTileGenerator的实例. 也就是TileGenerator成员.
7) 构造完成后, 通过调用TileTask.Release方法, 从智能指针处获得FRecastTileGeneratorTask* 指针. 赋值给RunningElement的AsyncTask对象.
然后就可以拿AsyncTask来调用同步或者异步接口. 调用完成后把RunningElement塞到RunningDirtyTiles里缓存. 并从PendingDiryTiles里移除.
 
8) 然后就是FAsyncTask的异步Work调度逻辑了
 
异步的话
9) 由于Task是FRecastTileGeneratorWrapper 所以是调用了这里.
然后是FRecastTileGenerator的这里
然后是这里. 调用GenerateNavigationData
 
具体的烘培逻辑
  1. UE的NavMesh烘培代码入口在 bool FRecastTileGenerator::GenerateTile()
  2. 主要烘培代码:
bool FRecastTileGenerator::GenerateNavigationData(FNavMeshBuildContext& BuildContext)
bool FRecastTileGenerator::GenerateNavigationDataLayer(FNavMeshBuildContext& BuildContext, FTileCacheCompressor& TileCompressor, FTileCacheAllocator& GenNavAllocator, FTileGenerationContext& GenerationContext, int32 LayerIdx)
  1. 烘培完成后数据存储:
  1. 逻辑流程参考Recast是走的Sample_TempObstacles流程, 烘培区域选择的算法是RC_REGION_WATERSHED
 
 
 
 

2024.4.3 补充

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
RebuildAll 逻辑流程.

  1. 在NavigationSystemV1 Build函数里调用NavData的RebuildAll, 实际会转发调用到FRecastNavMeshGenerator::RebuildAll()
  2. z在Generator的RebuildAll里先根据Bounds 标记所有的DirtyArea: MarkNavBoundsDirty()
  3. 然后通过EnsureBuildCompletion函数(图1, 图3)确保收集每次要处理的Tile任务和确保这些Tile任务执行EnsureCompletion, 完成Build (图3)
  4. 然后在Task的EnsureCompletion里, 调用的就是Task的DoWork, Task可以参考前面的分析.

 
 
 

过一遍后续的烘培流程 (以Tile为单位, 整个NavMesh是由n*m个tile组成. 多线程烘培. 同时最多进行MaxTileGeneratorTasks个Tile烘培任务):

从这里开始 bool FRecastTileGenerator::DoWork()   →  bool FRecastTileGenerator::GenerateTile()

具体:

  1. 先调用GenerateCompressedLayers 生成CompressedLayers,  这里有完整的烘培流程的前半部分
    1. 构造高度场 CreateHeightField
    2. 栅格化并标记NavModify. ComputeRasterizationMasks
    3. 栅格化网格, RasterizeTriangles → RasterizeGeometry / RasterizeGeometryRecast → rcRasterizeTriangles
    4. 过滤一些无效的span. ApplyVoxelFilter + GenerateRecastFilter → rcFilterLowHangingWalkableObstacles + rcFilterLedgeSpans + rcFilterWalkableLowHeightSpans
    5. 构造Compact高度场 BuildCompactHeightField
    6. Erode 一下寻路Span. RecastErodeWalkable → rcErodeWalkableAndLowAreas + rcErodeWalkableArea
    7. 重头戏, 烘培nav Layer: RecastBuildLayers → RC_REGION_WATERSHED → rcBuildDistanceField + rcBuildHeightfieldLayers → rcGatherRegionsNoFilter
    8. 构造dtBuildTileCacheLayer, 压缩Layer: RecastBuildTileCache
  2. 在得到CompressedLayers之后,  我们只是完成了NavMesh烘培的前半部分, 即完成BuildRegion阶段.  后续还需要做区域优化, 形成轮廓,  简化轮廓,  构建PolyMesh, 生成DetailPolyMesh
  3. 上面提到的步骤,紧接着GenerateCompressedLayers之后调用GenerateNavigationData实现.
    1. GenerateNavigationData()
    2. GenerateNavigationDataLayer
      1. 解压缩 dtDecompressTileCacheLayer
      2. Rasterize obstacles 处理动态阻挡. MarkDynamicAreas(*GenerationContext.Layer);
      3. 重新烘培区域, 类似上面的步骤g: dtBuildTileCacheDistanceField + dtBuildTileCacheRegions → filterSmallRegions
      4. 构建轮廓 dtBuildTileCacheContours
      5. 构建PolyMesh, dtBuildTileCachePolyMesh
      6. 构建PolyMeshDetail, dtBuildTileCachePolyMeshDetail
      7. 处理offmeshLinks
      8. 最后完成NavMeshData的构建: dtCreateNavMeshData(&Params, &NavData, &NavDataSize))
      9. 构建UE的NavMesh对象FNavMeshTileData: GenerationContext.NavigationData.Add(FNavMeshTileData(NavData, NavDataSize, LayerIdx, CompressedData.LayerBBox));

从上面可以看出来, Recast的Sample_TempObstacles和Sample_TileMesh关键的区别就在于. TempObstacles会先把烘培的前半部分数据Compress一下, 会有CompressedLayers

这部分数据是场景Mesh得到的原始数据,再加上动态阻挡的部分之后. 再重新烘培区域, 简化区域, 烘培细节网格. 得到最终的NavMesh.

这样做的原因不难理解: 场景不变的数据, 先烘培好压缩保存起来, 如果这里出现了动态阻挡, 则把场景不变的数据解压出来, 叠加动态阻挡, 再重新烘培一下区域. 形成更新的Navmesh.

所以这就是Sample_TempObstacles烘培的是支持动态阻挡的Dynamic NavMesh和Sample_TileMesh烘培的不支持动态阻挡的Static NavMesh 之间的区别. UE亦是如此.

 
 
 
 
 
 
 

UE 5 NavMesh 烘培 逻辑流程的更多相关文章

  1. 在Salesforce中通过 Debug Log 方式 跟踪逻辑流程

    在Salesforce中通过 Debug Log方式 跟踪逻辑流程 具体位置如下所示: Setup ---> Logs ---> Debug Logs ---> Monitored ...

  2. Unity3D研究院之动态修改烘培贴图的大小&脚本烘培场景

    Unity默认烘培场景以后每张烘培贴图的大小是1024.但是有可能你的场景比较简单,用1024会比较浪费.如下图所示,这是我的一个场景的烘培贴图,右上角一大部分完全是没有用到,但是它却占着空间.  有 ...

  3. 【翻译】CEDEC2012 SQUARE ENIX GPGPU实现高速GI烘培工具的方法

     虽然实时GI技术已经趋于成熟了,但出于对不同平台的性能和质量的考虑, 更倾向搭配一些预计算的渲染技术来实现,如给静态物体提供GI的LightMap, 给动态物体提供GI的Irradiance Vol ...

  4. Unity3D 5.1烘培 操作

    http://blog.csdn.net/asd237241291/article/details/48056575 原创文章如需转载请注明:转载自 脱莫柔Unity3D学习之旅 Unity3D引擎技 ...

  5. HDFS追本溯源:HDFS操作的逻辑流程与源码解析

    本文主要介绍5个典型的HDFS流程,这些流程充分体现了HDFS实体间IPC接口和stream接口之间的配合. 1. Client和NN Client到NN有大量的元数据操作,比如修改文件名,在给定目录 ...

  6. 3DMAX 烘培技术

    烘培是指,把光照信息渲染成贴图,而后把这个烘培后的贴图再贴回到场景中去的技术.烘培技术把光照计算的结果提前写入到了贴图中,因此在实时渲染中不需要进行耗时的光照计算,大大提高了实时渲染的效率. 烘培和渲 ...

  7. Unity3d 烘培lightingmap 注意的2点.

    1.在Qulity里面设置合适的灯光数量.否则,你会发现烘培出来的场景,有些灯光没有起作用. 2.在导入模型时候,注意勾选:Generate Lightingmap .  否则,模型没办法烘培. 3. ...

  8. Laravel5 快速认证逻辑流程分析

    Laravel5本身自带一套用户认证功能,只需在新项目下,使用命令行php artisan make:auth 和 php artisan migrate就可以使用自带的快速认证功能. 以下为分析登录 ...

  9. 【一起学源码-微服务】Hystrix 源码二:Hystrix核心流程:Hystix非降级逻辑流程梳理

    说明 原创不易,如若转载 请标明来源! 欢迎关注本人微信公众号:壹枝花算不算浪漫 更多内容也可查看本人博客:一枝花算不算浪漫 前言 前情回顾 上一讲我们讲了配置了feign.hystrix.enabl ...

  10. Nginx(二): worker 进程处理逻辑-流程框架

    Nginx 启动起来之后,会有几个进程运行:1. master 进程接收用户命令并做出响应; 2. worker 进程负责处理各网络事件,并同时接收来自master的处理协调命令: master 主要 ...

随机推荐

  1. [FAQ] Win10 WSL Ubuntu 根目录实际位置

    1. 运行(win+R),直接输入 \\wsl$ 进入Ubuntu的目录. 2. 或者文件夹里同样输入  \\wsl$ 进行查找. Refer:Win10 WSL 路径 Link:https://ww ...

  2. [FE] Quasar 变通 loading 单纯使用遮罩效果的方法

    Quasar 的 loading 组件是提供加载中的遮罩效果的. 如果你不想要 loading 的效果,只想保留遮罩效果,那么你可以通过 show() 方法的参数进行调整. 把 spinnerSize ...

  3. WPF 关于将 ManipulationDeltaEventArgs 的 Manipulators 属性返回值修改为 ReadOnlyCollection 类型的提议

    这是一个 WPF 框架的 API 变更提议,记录一下博客 讨论的地方是: How about change the type of ManipulationDeltaEventArgs.Manipul ...

  4. 2019-7-2-WPF-通过-ReadyToRun-提升性能

    title author date CreateTime categories WPF 通过 ReadyToRun 提升性能 lindexi 2019-07-02 10:29:55 +0800 201 ...

  5. go和c#实现斐波那契数列

    首先通过C#实现斐波那契数列: using System.Threading.Channels; namespace App001 { internal class Program { static ...

  6. vue-单独引入js文件,构造全局方法-取某个范围的随机数(百分比)案例

    1.项目下建文件夹commonFunction->random.js 这个js文件内复制代码: export default{     randomPercentage:function(a,b ...

  7. 🔥httpsok彻底告别SSL证书续期烦扰

    httpsok彻底告别SSL证书续期烦扰 介绍 httpsok 是一个便捷的 HTTPS 证书自动续签工具,专为 Nginx .OpenResty 服务器设计.已服务众多中小企业,稳定.安全.可靠. ...

  8. 记一次Nacos漏洞的复现 --> 身份认证绕过漏洞(QVD-2023-6271)

    前记 端午前两天,遇到公司某客户的站点是Nacos,随后就是网上搜一波漏洞,搜到 QVD-2023-6271,故做以下记录 漏洞复现 漏洞描述 漏洞原理为开源服务管理平台 Nacos在默认配置下未对 ...

  9. 深入Django项目实战与最佳实践

    title: 深入Django项目实战与最佳实践 date: 2024/5/19 21:41:38 updated: 2024/5/19 21:41:38 categories: 后端开发 tags: ...

  10. 多个 GPU 上运行

    默认情况下,Easy Diffusion 自动在多个 GPU 上运行(如果您的电脑有多个 GPU).例如,两个任务将在两个 GPU 上并行运行(如果有的话). 我该如何使用这个? 如果您的电脑有多个 ...