Navmesh bounds are too large

当地图相当大,在生成导航时会有以下提示:

1
LogNavigation: Error: Navmesh bounds are too large! Limiting requested tiles count (5472000) to: (1048576) for RecastNavMesh /Game/Level/Map.Map:PersistentLevel.RecastNavMesh-Default

这是因为地图太大,超出了 Tile 的数量限制。
引擎中默认 Tile 的最大数量为 1<<20 也就是 1048576,这个值可以修改配置,但不能大于1<<30(因为它用 int32 存储)。

Source/Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h
1
2
3
4
5
6
7
8
9
10
11
12
UCLASS(config=Engine, defaultconfig, hidecategories=(Input,Rendering,Tags,"Utilities|Transformation",Actor,Layers,Replication), notplaceable)
class NAVIGATIONSYSTEM_API ARecastNavMesh : public ANavigationData
{
// ...
/** Absolute hard limit to number of navmesh tiles. Be very, very careful while modifying it while
* having big maps with navmesh. A single, empty tile takes 176 bytes and empty tiles are
* allocated up front (subject to change, but that's where it's at now)
* @note TileNumberHardLimit is always rounded up to the closest power of 2 */
UPROPERTY(EditAnywhere, Category = Generation, config, meta = (ClampMin = "1", UIMin = "1"), AdvancedDisplay)
int32 TileNumberHardLimit;
// ...
};

以及使用:

Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
FRecastNavMeshGenerationProperties::FRecastNavMeshGenerationProperties()
{
TilePoolSize = 1024;
TileSizeUU = 988.f;
CellSize = 19;
CellHeight = 10;
AgentRadius = 34.f;
AgentHeight = 144.f;
AgentMaxSlope = 44.f;
AgentMaxStepHeight = 35.f;
MinRegionArea = 0.f;
MergeRegionSize = 400.f;
MaxSimplificationError = 1.3f; // from RecastDemo
TileNumberHardLimit = 1 << 20;
RegionPartitioning = ERecastPartitioning::Watershed;
LayerPartitioning = ERecastPartitioning::Watershed;
RegionChunkSplits = 2;
LayerChunkSplits = 2;
bSortNavigationAreasByCost = false;
bPerformVoxelFiltering = true;
bMarkLowHeightAreas = false;
bUseExtraTopCellWhenMarkingAreas = true;
bFilterLowSpanSequences = false;
bFilterLowSpanFromTileCache = false;
bFixedTilePoolSize = false;
}

FRecastNavMeshGenerationProperties::FRecastNavMeshGenerationProperties(const ARecastNavMesh& RecastNavMesh)
{
TilePoolSize = RecastNavMesh.TilePoolSize;
TileSizeUU = RecastNavMesh.TileSizeUU;
CellSize = RecastNavMesh.CellSize;
CellHeight = RecastNavMesh.CellHeight;
AgentRadius = RecastNavMesh.AgentRadius;
AgentHeight = RecastNavMesh.AgentHeight;
AgentMaxSlope = RecastNavMesh.AgentMaxSlope;
AgentMaxStepHeight = RecastNavMesh.AgentMaxStepHeight;
MinRegionArea = RecastNavMesh.MinRegionArea;
MergeRegionSize = RecastNavMesh.MergeRegionSize;
MaxSimplificationError = RecastNavMesh.MaxSimplificationError;
TileNumberHardLimit = RecastNavMesh.TileNumberHardLimit;
RegionPartitioning = RecastNavMesh.RegionPartitioning;
LayerPartitioning = RecastNavMesh.LayerPartitioning;
RegionChunkSplits = RecastNavMesh.RegionChunkSplits;
LayerChunkSplits = RecastNavMesh.LayerChunkSplits;
bSortNavigationAreasByCost = RecastNavMesh.bSortNavigationAreasByCost;
bPerformVoxelFiltering = RecastNavMesh.bPerformVoxelFiltering;
bMarkLowHeightAreas = RecastNavMesh.bMarkLowHeightAreas;
bUseExtraTopCellWhenMarkingAreas = RecastNavMesh.bUseExtraTopCellWhenMarkingAreas;
bFilterLowSpanSequences = RecastNavMesh.bFilterLowSpanSequences;
bFilterLowSpanFromTileCache = RecastNavMesh.bFilterLowSpanFromTileCache;
bFixedTilePoolSize = RecastNavMesh.bFixedTilePoolSize;
}
ARecastNavMesh::ARecastNavMesh(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, bDrawFilledPolys(true)
, bDrawNavMeshEdges(true)
, bDrawNavLinks(true)
, bDrawOctreeDetails(true)
, bDrawMarkedForbiddenPolys(false)
, bDistinctlyDrawTilesBeingBuilt(true)
, DrawOffset(10.f)
, TilePoolSize(1024)
, MaxSimplificationError(1.3f) // from RecastDemo
, DefaultMaxSearchNodes(RECAST_MAX_SEARCH_NODES)
, DefaultMaxHierarchicalSearchNodes(RECAST_MAX_SEARCH_NODES)
, bPerformVoxelFiltering(true)
, bMarkLowHeightAreas(false)
, bUseExtraTopCellWhenMarkingAreas(true)
, bFilterLowSpanSequences(false)
, bFilterLowSpanFromTileCache(false)
, bStoreEmptyTileLayers(false)
, bUseVirtualFilters(true)
, bAllowNavLinkAsPathEnd(false)
, TileSetUpdateInterval(1.0f)
, NavMeshVersion(NAVMESHVER_LATEST)
, RecastNavMeshImpl(NULL)
{
HeuristicScale = 0.999f;
RegionPartitioning = ERecastPartitioning::Watershed;
LayerPartitioning = ERecastPartitioning::Watershed;
RegionChunkSplits = 2;
LayerChunkSplits = 2;
MaxSimultaneousTileGenerationJobsCount = 1024;
bDoFullyAsyncNavDataGathering = false;
TileNumberHardLimit = 1 << 20;

#if RECAST_ASYNC_REBUILDING
BatchQueryCounter = 0;
#endif // RECAST_ASYNC_REBUILDING


if (HasAnyFlags(RF_ClassDefaultObject) == false)
{
INC_DWORD_STAT_BY(STAT_NavigationMemory, sizeof(*this) );

FindPathImplementation = FindPath;
FindHierarchicalPathImplementation = FindPath;

TestPathImplementation = TestPath;
TestHierarchicalPathImplementation = TestHierarchicalPath;

RaycastImplementation = NavMeshRaycast;

RecastNavMeshImpl = new FPImplRecastNavMesh(this);

// add predefined areas up front
SupportedAreas.Add(FSupportedAreaData(UNavArea_Null::StaticClass(), RECAST_NULL_AREA));
SupportedAreas.Add(FSupportedAreaData(UNavArea_LowHeight::StaticClass(), RECAST_LOW_AREA));
SupportedAreas.Add(FSupportedAreaData(UNavArea_Default::StaticClass(), RECAST_DEFAULT_AREA));
}
}

TileNumberHardLimit的值可以通过配置文件进行设置:

DefaultEngine.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
[/Script/NavigationSystem.RecastNavMesh]
bDrawPolyEdges=False
bDistinctlyDrawTilesBeingBuilt=True
DrawOffset=10.000000
bFixedTilePoolSize=False
TilePoolSize=1024
TileSizeUU=1000.000000
CellSize=19.000000
CellHeight=10.000000
AgentRadius=34.000000
AgentHeight=144.000000
AgentMaxHeight=160.000000
AgentMaxSlope=44.000000
AgentMaxStepHeight=35.000000
MinRegionArea=0.000000
MergeRegionSize=400.000000
MaxSimplificationError=1.300000
MaxSimultaneousTileGenerationJobsCount=1024
TileNumberHardLimit=1048576
DefaultDrawDistance=5000.000000
DefaultMaxSearchNodes=2048.000000
DefaultMaxHierarchicalSearchNodes=2048.000000
RegionPartitioning=Watershed
LayerPartitioning=Watershed
RegionChunkSplits=2
LayerChunkSplits=2
bSortNavigationAreasByCost=False
bPerformVoxelFiltering=True
bMarkLowHeightAreas=False
bDoFullyAsyncNavDataGathering=False
bUseBetterOffsetsFromCorners=True
bUseVirtualFilters=True
bUseVoxelCache=False
TileSetUpdateInterval=1.000000
HeuristicScale=0.999000
VerticalDeviationFromGroundCompensation=0.000000
bForceRebuildOnLoad=True