Moving a Streaming Level's static nav mesh

anonymous_user_cc989825
Fri, 15 Apr 2016 19:37:21 +0000
AI

I want to transform an instance of a sublevel including its nav mesh.

Why not use dynamic/runtime generation and move the nav mesh around? I’m assuming it is too slow. Nav mesh generation is not a cheap operation. It is likely far too expensive for a dedicated server handling 100s of clients running in and out of 100s of Areas.

Problem

Let me drill down from what I’m doing specifically to what I see as going on in the nav mesh code:

I have a game with randomly generated Areas.

The Areas are made of randomly placed Levels.

Levels can be instanced multiple times in the same Area at different positions and rotations.

Each level instance is loaded by adding a ULevelStreamingKismet to UWorld::StreamingLevels.

ULevelStreamingKismet inherits from ULevelStreaming - which has a LevelTransform. ULevelStreaming::LevelTransform moves almost everything through UWorld::AddToWorld() and FLevelUtils::ApplyLevelTransform(). This doesn’t transform the navmesh

In ARecastNavMesh::OnStreamingLevelAdded(ULevel* InLevel, UWorld* InWorld), it adds the URecastNavMeshDataChunk::Tiles to the global nav mesh using URecastNavMeshDataChunk::AttachTiles() and dtNavMesh::addTile().

Neither URecastNavMeshDataChunk::AttachTiles() nor dtNavMesh::addTile() respect nor see ULevelStreaming::LevelTransform.

Can’t avoid changing Unreal source

I’m not seeing a way to solve this without changing our fork of Unreal 4:

ARecastNavMesh::OnStreamingLevelAdded() is virtual and could be overriden, but…

URecastNavMeshDataChunk can’t be overriden and has almost nothing that is virtual.

URecastNavMeshDataChunk keeps the Tiles private.

Proposed Solution

So, (deep breath) I’m thinking that our solution needs to change several things in UE4:

ARecastNavMesh::OnStreamingLevelAdded() needs to respect the Level Transform. It should find the ULevelStreaming instance associated with this ULevel to get the LevelTransform - which isn’t stored in the ULevel.

Pass the LevelTransform into URecastNavMeshDataChunk::AttachTiles(). Update URecastNavMeshDataChunk::AttachTiles() so that it respects the transform when organizing the Tiles. Pass the LevelTransform to dtNavMesh::addTile().

Change dtNavMesh::addTile() so that it transforms its data. This looks rather daunting. There is a lot of data being wrangled in this function.

Questions:

Before diving into this, am I looking the problem correctly?

Am I misreading how a Level’s nav mesh is being loaded and integrated into the global nav mesh?

How fast is dynamic nav mesh generation? For a typical 1k by 1k level, are we talking milliseconds, seconds, 10s of seconds?

Can the nav mesh selectively regenerate? Or do we have to cast the nav mesh against the entire random level at once each time a level streams in or out?

Are we also going to need to make a copy of the URecastNavMeshDataChunk for each instance of a Level in order to transform it into place?

Epic, if I added this in as a pull request, would it be considered? Or is there a better approach that we should take?

For anyone who made it this far. Thanks! Let me know if I can/should clarify anything.

2 posts - 2 participants