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