CellHeight

CellHeight

#Overview

name: CellHeight

The value of this variable can be defined or overridden in .ini config files. 1 .ini config file referencing this setting variable.

It is referenced in 23 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of CellHeight is to define the vertical size of voxelization cells used in the generation of navigation meshes within Unreal Engine’s navigation system. It is a crucial parameter that affects the precision and performance of pathfinding and navigation in 3D environments.

CellHeight is primarily used by the Recast navigation mesh system, which is part of Unreal Engine’s navigation module. This variable is referenced in various parts of the engine, including:

  1. The Paper2D plugin for 2D sprite extraction
  2. The core navigation system, particularly in the RecastNavMesh and RecastNavMeshGenerator classes

The value of CellHeight is typically set in the ARecastNavMesh class, which inherits from ANavigationData. It can be configured through the Unreal Engine editor or programmatically.

CellHeight interacts with several other variables, including:

  1. CellSize (horizontal size of voxelization cells)
  2. AgentHeight (height of the navigating agent)
  3. AgentMaxStepHeight (maximum vertical step the agent can take)
  4. AgentMaxSlope (maximum slope the agent can traverse)

Developers must be aware that:

  1. CellHeight directly affects the vertical precision of the navigation mesh. Smaller values increase precision but also increase memory usage and generation time.
  2. It should be balanced with CellSize to maintain a reasonable aspect ratio for voxels.
  3. The value should be appropriate for the scale of your game world and the size of your agents.

Best practices when using CellHeight include:

  1. Adjust it in conjunction with other navigation parameters to achieve the desired balance between precision and performance.
  2. Use the NavMeshResolutionParams array to set different CellHeight values for different navigation data resolutions, allowing for more flexible and optimized navigation meshes.
  3. Ensure that CellHeight is small enough to capture important vertical features in your environment but large enough to maintain reasonable performance.
  4. Consider the relationship between CellHeight and AgentMaxStepHeight when configuring your navigation mesh.

#Setting Variables

#References In INI files

Location: <Workspace>/Engine/Config/BaseEngine.ini:2818, section: [/Script/NavigationSystem.RecastNavMesh]

#References in C++ code

#Callsites

This variable is referenced in the following C++ source code:

#Loc: <Workspace>/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/ExtractSprites/PaperExtractSpritesSettings.h:67

Scope (from outer to inner):

file
class        class UPaperExtractSpriteGridSettings : public UObject

Source code excerpt:

	// The height of each sprite in grid mode
	UPROPERTY(Category = Grid, EditAnywhere, meta = (UIMin = 1, ClampMin = 1))
	int32 CellHeight = 64;

	// Number of cells extracted horizontally. Can be used to limit the number of sprites extracted. Set to 0 to extract all sprites
	UPROPERTY(Category = Grid, EditAnywhere, meta = (UIMin = 0, ClampMin = 0))
	int32 NumCellsX;

	// Number of cells extracted vertically. Can be used to limit the number of sprites extracted. Set to 0 to extract all sprites

#Loc: <Workspace>/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/ExtractSprites/SPaperExtractSpritesDialog.cpp:163

Scope (from outer to inner):

file
function     void SPaperExtractSpritesDialog::Construct

Source code excerpt:

	ExtractSpriteGridSettings->AddToRoot();
	ExtractSpriteGridSettings->CellWidth = InSourceTexture->GetImportedSize().X;
	ExtractSpriteGridSettings->CellHeight = InSourceTexture->GetImportedSize().Y;

	PreviewExtractedSprites();

	FPropertyEditorModule& EditModule = FModuleManager::Get().GetModuleChecked<FPropertyEditorModule>("PropertyEditor");
	FDetailsViewArgs DetailsViewArgs;
	DetailsViewArgs.bAllowSearch = false;

#Loc: <Workspace>/Engine/Plugins/2D/Paper2D/Source/Paper2DEditor/Private/ExtractSprites/SPaperExtractSpritesDialog.cpp:364

Scope (from outer to inner):

file
function     void SPaperExtractSpritesDialog::PreviewExtractedSprites

Source code excerpt:


			const int32 EffectiveCellWidth = FMath::Clamp(ExtractSpriteGridSettings->CellWidth, 1, TextureWidth);
			const int32 EffectiveCellHeight = FMath::Clamp(ExtractSpriteGridSettings->CellHeight, 1, TextureHeight);

			int NumExtractedCellsY = 0;
			for (int32 Y = ExtractSpriteGridSettings->MarginY; Y + EffectiveCellHeight <= TextureHeight; Y += EffectiveCellHeight + ExtractSpriteGridSettings->SpacingY)
			{
				int NumExtractedCellsX = 0;
				for (int32 X = ExtractSpriteGridSettings->MarginX; X + EffectiveCellWidth <= TextureWidth; X += EffectiveCellWidth + ExtractSpriteGridSettings->SpacingX)

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:427

Scope (from outer to inner):

file
function     FRecastNavMeshGenerationProperties::FRecastNavMeshGenerationProperties

Source code excerpt:

	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;

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:459

Scope (from outer to inner):

file
function     FRecastNavMeshGenerationProperties::FRecastNavMeshGenerationProperties

Source code excerpt:

	
	CellSize = RecastNavMesh.GetCellSize(ENavigationDataResolution::Default);
	CellHeight = RecastNavMesh.GetCellHeight(ENavigationDataResolution::Default);
	AgentRadius = RecastNavMesh.AgentRadius;
	AgentHeight = RecastNavMesh.AgentHeight;
	AgentMaxSlope = RecastNavMesh.AgentMaxSlope;
	AgentMaxStepHeight = RecastNavMesh.GetAgentMaxStepHeight(ENavigationDataResolution::Default); //FRecastNavMeshGenerationProperties is getting deprecated 
	MinRegionArea = RecastNavMesh.MinRegionArea;
	MergeRegionSize = RecastNavMesh.MergeRegionSize;

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:685

Scope (from outer to inner):

file
function     void ARecastNavMesh::PostLoad

Source code excerpt:

	}

	// If needed, initialize CellHeight from the deprecated value.
	if (NavMeshVersion < NAVMESHVER_TILE_RESOLUTIONS_CELLHEIGHT)
	{
		for (int i = 0; i < (uint8)ENavigationDataResolution::MAX; ++i)
		{
			SetCellHeight((ENavigationDataResolution)i, CellHeight);
		}
	}

	// If needed, initialize AgentMaxStepHeight from the deprecated value.
	if (NavMeshVersion < NAVMESHVER_TILE_RESOLUTIONS_AGENTMAXSTEPHEIGHT)
	{

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:801

Scope (from outer to inner):

file
function     void ARecastNavMesh::PostInitProperties

Source code excerpt:

			}

			const float CurrentCellHeight = NavMeshResolutionParams[i].CellHeight;
			const float DefaultObjectCellHeight = DefOb->NavMeshResolutionParams[i].CellHeight;
			if (CurrentCellHeight != DefaultObjectCellHeight)
			{
				UE_LOG(LogNavigation, Warning, TEXT("%s param: CellHeight(%f) differs from config settings, forcing value %f so it can be used with voxel cache!"),
					*GetNameSafe(this), CurrentCellHeight, DefaultObjectCellHeight);

				NavMeshResolutionParams[i].CellHeight = DefaultObjectCellHeight;
			}

			const float CurrentAgentMaxStepHeight = NavMeshResolutionParams[i].AgentMaxStepHeight;
			const float DefaultObjectAgentMaxStepHeight = DefOb->NavMeshResolutionParams[i].AgentMaxStepHeight;
			if (CurrentAgentMaxStepHeight != DefaultObjectAgentMaxStepHeight)
			{

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:3251

Scope (from outer to inner):

file
function     void ARecastNavMesh::PostEditChangeChainProperty

Source code excerpt:

				}
			}
			else if (PropName == GET_MEMBER_NAME_CHECKED(FNavMeshResolutionParam, CellHeight))
			{
				PRAGMA_DISABLE_DEPRECATION_WARNINGS
				// Update the deprecated CellHeight to fit the default resolution CellHeight
				CellHeight = NavMeshResolutionParams[(uint8)ENavigationDataResolution::Default].CellHeight;
				PRAGMA_ENABLE_DEPRECATION_WARNINGS

				bRebuild = true;
			}

			if (bRebuild)

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMesh.cpp:3439

Scope (from outer to inner):

file
function     void ARecastNavMesh::UpdateGenerationProperties

Source code excerpt:


	CellSize = GenerationProps.CellSize;
	CellHeight = GenerationProps.CellHeight;

	AgentRadius = GenerationProps.AgentRadius;
	AgentHeight = GenerationProps.AgentHeight;
	AgentMaxSlope = GenerationProps.AgentMaxSlope;

	AgentMaxStepHeight = GenerationProps.AgentMaxStepHeight;

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:1579

Scope (from outer to inner):

file
function     void Create

Source code excerpt:

	}

	void Create(int32 FieldSize, FVector::FReal CellSize, FVector::FReal CellHeight)
	{
		if (RasterizeHF == NULL)
		{
			const FVector::FReal DummyBounds[3] = { 0 };

			RasterizeHF = rcAllocHeightfield();
			rcCreateHeightfield(NULL, *RasterizeHF, FieldSize, FieldSize, DummyBounds, DummyBounds, CellSize, CellHeight);
		}
	}

	void Reset()
	{
		rcResetHeightfield(*RasterizeHF);

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:2179

Scope (from outer to inner):

file
function     void FRecastTileGenerator::ApplyVoxelFilter

Source code excerpt:

		const int32 Height = HF->height;
		const FVector::FReal CellSize = HF->cs;
		const FVector::FReal CellHeight = HF->ch;
		const FVector::FReal BottomX = HF->bmin[0];
		const FVector::FReal BottomZ = HF->bmin[1];
		const FVector::FReal BottomY = HF->bmin[2];
		const int32 SpansCount = Width*Height;
		// we need to expand considered bounding boxes so that
		// it doesn't create "fake cliffs"

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:2208

Scope (from outer to inner):

file
function     void FRecastTileGenerator::ApplyVoxelFilter

Source code excerpt:

						if (s->data.area == RC_WALKABLE_AREA)
						{
							const FVector::FReal SpanMin = CellHeight * s->data.smin + BottomZ;
							const FVector::FReal SpanMax = CellHeight * s->data.smax + BottomZ;

							const FVector SpanMinV(SpanX-CellSize, SpanY-CellSize, SpanMin);
							const FVector SpanMaxV(SpanX, SpanY, SpanMax);

							if (BB.IsInside(SpanMinV) == false && BB.IsInside(SpanMaxV) == false)
							{

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:2249

Scope (from outer to inner):

file
function     void FRecastTileGenerator::ApplyVoxelFilter

Source code excerpt:

						if (s->data.area == RC_WALKABLE_AREA)
						{
							const FVector::FReal SpanMin = CellHeight * s->data.smin + BottomZ;
							const FVector::FReal SpanMax = CellHeight * s->data.smax + BottomZ;

							const FVector SpanMinV(SpanX-CellSize, SpanY-CellSize, SpanMin);
							const FVector SpanMaxV(SpanX, SpanY, SpanMax);

							bool bIsInsideAnyBB = false;
							const FBox* BB = Bounds.GetData();

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:4642

Scope (from outer to inner):

file
function     void FRecastNavMeshGenerator::SetupTileConfig

Source code excerpt:

	ensure(GetConfig().cs == GetOwner()->GetCellSize(ENavigationDataResolution::Default));
	const float CellSize = GetOwner()->GetCellSize(TileResolution);
	const float CellHeight = GetOwner()->GetCellHeight(TileResolution);
	const float AgentMaxStepHeight = GetOwner()->GetAgentMaxStepHeight(TileResolution);
	
	// Update all settings that depends directly or indirectly of the CellSize
	OutConfig.TileResolution = TileResolution;
	OutConfig.cs = CellSize;
	OutConfig.walkableRadius = FMath::CeilToInt(DestNavMesh->AgentRadius / CellSize);

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:4664

Scope (from outer to inner):

file
function     PRAGMA_ENABLE_DEPRECATION_WARNINGS void FRecastNavMeshGenerator::SetupTileConfig

Source code excerpt:

	OutConfig.TileCacheChunkSize = FMath::Max(1, OutConfig.tileSize / FMath::Max(1, DestNavMesh->RegionChunkSplits));

	// Update all settings that depends directly or indirectly of the CellHeight
	OutConfig.ch = CellHeight;
	OutConfig.walkableHeight = DestNavMesh->bMarkLowHeightAreas ? 1 : FMath::CeilToInt(DestNavMesh->AgentHeight / CellHeight);
	OutConfig.walkableClimb = FMath::CeilToInt(AgentMaxStepHeight / CellHeight);

	// Update all settings that depends directly or indirectly of AgentMaxStepHeight
	OutConfig.AgentMaxClimb = AgentMaxStepHeight;

	OutConfig.bIsTileSetupConfigCompleted = true;
}

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:4679

Scope (from outer to inner):

file
function     void FRecastNavMeshGenerator::ConfigureBuildProperties

Source code excerpt:

	// @TODO those variables should be tweakable per navmesh actor
	const float CellSize = DestNavMesh->GetCellSize(ENavigationDataResolution::Default);
	const float CellHeight = DestNavMesh->GetCellHeight(ENavigationDataResolution::Default);
	const float AgentHeight = DestNavMesh->AgentHeight;
	const float AgentMaxSlope = DestNavMesh->AgentMaxSlope;
	const float AgentMaxClimb = DestNavMesh->GetAgentMaxStepHeight(ENavigationDataResolution::Default);
	const float AgentRadius = DestNavMesh->AgentRadius;

	OutConfig.Reset();

	OutConfig.cs = CellSize;
	OutConfig.ch = CellHeight;
	OutConfig.walkableSlopeAngle = AgentMaxSlope;
	OutConfig.walkableHeight = FMath::CeilToInt(AgentHeight / CellHeight);
	OutConfig.walkableClimb = FMath::CeilToInt(AgentMaxClimb / CellHeight);
	OutConfig.walkableRadius = FMath::CeilToInt(AgentRadius / CellSize);
	OutConfig.maxStepFromWalkableSlope = OutConfig.cs * FMath::Tan(FMath::DegreesToRadians(OutConfig.walkableSlopeAngle));
	
	// For each navmesh resolutions, validate that AgentMaxStepHeight is high enough for the AgentMaxSlope angle
	for (int32 Index = 0; Index < (uint8)ENavigationDataResolution::MAX; Index++)
	{

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:7309

Scope (from outer to inner):

file
lambda-function

Source code excerpt:

								if (Verts.Num())
								{
									const float CellHeight = NavData->GetCellHeight(ENavigationDataResolution::Default);
									Snapshot->AddPulledConvex(
										Verts,
										InConvexNavAreaData.MinZ - CellHeight,
										InConvexNavAreaData.MaxZ + CellHeight,
										CategoryName, NavAreaVerbosity, PolygonColor.WithAlpha(255));
								}
							};

							if (ShapeType == ENavigationShapeType::Convex)
							{

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Private/NavMesh/RecastNavMeshGenerator.cpp:7443

Scope (from outer to inner):

file
lambda-function
lambda-function

Source code excerpt:

								if (ConvexVerts.Num())
								{
									const float CellHeight = NavData->GetCellHeight(ENavigationDataResolution::Default);
									ExportInfo.Convex.MinZ -= CellHeight;
									ExportInfo.Convex.MaxZ += CellHeight;

									ExportInfo.Convex.Points = UE::LWC::ConvertArrayType<FVector>(ConvexVerts);

									AreaExport.Add(ExportInfo);
								}								
							};

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h:346

Scope: file

Source code excerpt:

	/** vertical size of voxelization cell */
	UPROPERTY(EditAnywhere, Category = Generation, meta = (ClampMin = "1.0", ClampMax = "1024.0"))
	float CellHeight;

	/** Radius of largest agent that can freely traverse the generated navmesh */
	UPROPERTY(EditAnywhere, Category = Generation, meta = (ClampMin = "0.0"))
	float AgentRadius;

	/** Size of the tallest agent that will path with this navmesh. */

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h:633

Scope (from outer to inner):

file
function     bool IsValid

Source code excerpt:

	GENERATED_BODY()

	bool IsValid() const { return CellSize > 0.f && CellHeight > 0.f && AgentMaxStepHeight > 0.f; }
	
	/** Horizontal size of voxelization cell */
	UPROPERTY(EditAnywhere, Category = Generation, config, meta = (ClampMin = "1.0", ClampMax = "1024.0"))
	float CellSize = 25.f;

	/** Vertical size of voxelization cell */
	UPROPERTY(EditAnywhere, Category = Generation, config, meta = (ClampMin = "1.0", ClampMax = "1024.0"))
	float CellHeight = 10.f;

	/** Largest vertical step the agent can perform */
	UPROPERTY(EditAnywhere, Category = Generation, config, meta = (ClampMin = "0.0"))
	float AgentMaxStepHeight = 35.f;
};

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h:769

Scope (from outer to inner):

file
class        class ARecastNavMesh : public ANavigationData

Source code excerpt:

	UE_DEPRECATED(5.2, "Set the CellHeight for the required navmesh resolutions in NavMeshResolutionParams.")
	UPROPERTY(config)
	float CellHeight;

	/** Resolution params 
	 * If using multiple resolutions, it's recommended to chose the highest resolution first and 
	 * set it according to the highest desired precision and then the other resolutions. */
	UPROPERTY(EditAnywhere, Category = Generation, config)
	FNavMeshResolutionParam NavMeshResolutionParams[(uint8)ENavigationDataResolution::MAX];

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h:803

Scope: file

Source code excerpt:


	/** Maximum vertical deviation between raw contour points to allowing merging (in voxel).
	 * Use a low value (2-5) depending on CellHeight, AgentMaxStepHeight and AgentMaxSlope, to allow more precise contours (also see SimplificationElevationRatio).
	 * Use very high value to deactivate (Recast behavior). */
	UPROPERTY(EditAnywhere, Category = Generation, config, meta = (ClampMin = "0"))
	int MaxVerticalMergeError;
	
	/** How much navigable shapes can get simplified - the higher the value the more freedom */
	UPROPERTY(EditAnywhere, Category = Generation, config, meta = (ClampMin = "0.0"))
	float MaxSimplificationError;

#Loc: <Workspace>/Engine/Source/Runtime/NavigationSystem/Public/NavMesh/RecastNavMesh.h:1134

Scope: file

Source code excerpt:

	void SetCellSize(const ENavigationDataResolution Resolution, const float Size) { NavMeshResolutionParams[(uint8)Resolution].CellSize = Size; }

	/** Get the CellHeight for the given resolution. */
	float GetCellHeight(const ENavigationDataResolution Resolution) const { return NavMeshResolutionParams[(uint8)Resolution].CellHeight; }

	/** Set the CellHeight for the given resolution. */
	void SetCellHeight(const ENavigationDataResolution Resolution, const float Height) { NavMeshResolutionParams[(uint8)Resolution].CellHeight = Height; }

	/** Get the AgentMaxStepHeight for the given resolution. */
	float GetAgentMaxStepHeight(const ENavigationDataResolution Resolution) const { return NavMeshResolutionParams[(uint8)Resolution].AgentMaxStepHeight; }

	/** Set the AgentMaxStepHeight for the given resolution. */
	void SetAgentMaxStepHeight(const ENavigationDataResolution Resolution, const float MaxStepHeight) { NavMeshResolutionParams[(uint8)Resolution].AgentMaxStepHeight = MaxStepHeight; }