PlayAreaHeight
PlayAreaHeight
#Overview
name: PlayAreaHeight
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 14
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of PlayAreaHeight is to define the height of visibility cells used in Unreal Engine’s precomputed visibility system. This setting is part of the rendering system, specifically the precomputed visibility optimization.
This setting variable is primarily used in the Unreal Engine’s lightmass and precomputed visibility subsystems. It is referenced in the UnrealEd module, particularly in the Lightmass exporter and processor.
The value of this variable is typically set in the engine’s configuration files, specifically in the “DevOptions.PrecomputedVisibility” section of the GLightmassIni file. It is read using the GConfig->GetFloat() function.
PlayAreaHeight interacts with other visibility-related variables such as CellSize, VisibilityCellSize, and various other precomputed visibility settings.
Developers must be aware that this variable directly affects the size and placement of visibility cells in the z-dimension. It influences how visibility is calculated and can impact performance and visual quality.
Best practices when using this variable include:
- Carefully tuning the value to balance between visibility accuracy and performance.
- Considering the typical vertical scale of your game environments when setting this value.
- Testing different values to find the optimal setting for your specific game.
- Coordinating this setting with other visibility-related variables for best results.
- Being mindful of how changes to this value might affect existing level designs and visibility calculations.
#Setting Variables
#References In INI files
Location: <Workspace>/Engine/Config/BaseLightmass.ini:111, section: [DevOptions.PrecomputedVisibility]
- INI Section:
DevOptions.PrecomputedVisibility
- Raw value:
220
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:2282
Scope (from outer to inner):
file
function void FLightmassExporter::WriteSceneSettings
Source code excerpt:
Scene.PrecomputedVisibilitySettings.CellSize = World->GetWorldSettings()->VisibilityCellSize;
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("NumCellDistributionBuckets"), Scene.PrecomputedVisibilitySettings.NumCellDistributionBuckets, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PrecomputedVisibility"), TEXT("PlayAreaHeight"), Scene.PrecomputedVisibilitySettings.PlayAreaHeight, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PrecomputedVisibility"), TEXT("MeshBoundsScale"), Scene.PrecomputedVisibilitySettings.MeshBoundsScale, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("MinMeshSamples"), Scene.PrecomputedVisibilitySettings.MinMeshSamples, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("MaxMeshSamples"), Scene.PrecomputedVisibilitySettings.MaxMeshSamples, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("NumCellSamples"), Scene.PrecomputedVisibilitySettings.NumCellSamples, GLightmassIni));
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("NumImportanceSamples"), Scene.PrecomputedVisibilitySettings.NumImportanceSamples, GLightmassIni));
}
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3660
Scope (from outer to inner):
file
function void SpreadVisibilityCell
Source code excerpt:
void SpreadVisibilityCell(
float CellSize,
float PlayAreaHeight,
const FUncompressedPrecomputedVisibilityCell& OtherCell,
FUncompressedPrecomputedVisibilityCell& VisibilityCell,
int32& QueriesVisibleFromSpreadingNeighbors)
{
// Determine whether the cell is a world space neighbor
if (!(OtherCell.Bounds.Min == VisibilityCell.Bounds.Min && OtherCell.Bounds.Max == VisibilityCell.Bounds.Max)
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3670
Scope (from outer to inner):
file
function void SpreadVisibilityCell
Source code excerpt:
&& FMath::Abs(VisibilityCell.Bounds.Min.Y - OtherCell.Bounds.Min.Y) < CellSize + KINDA_SMALL_NUMBER
// Don't spread from cells below, they're probably below the ground and see too much
&& OtherCell.Bounds.Min.Z - VisibilityCell.Bounds.Min.Z > -PlayAreaHeight * 0.5f
// Only spread from one cell above
&& OtherCell.Bounds.Min.Z - VisibilityCell.Bounds.Min.Z < PlayAreaHeight * 1.5f)
{
// Combine the neighbor's visibility with the current cell's visibility
// This reduces visibility errors at the cost of less effective culling
QueriesVisibleFromSpreadingNeighbors += AccumulateVisibility(OtherCell.VisibilityData, VisibilityCell.VisibilityData);
}
}
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3703
Scope (from outer to inner):
file
function void FLightmassProcessor::ApplyPrecomputedVisibility
Source code excerpt:
VERIFYLIGHTMASSINI(GConfig->GetBool(TEXT("DevOptions.PrecomputedVisibility"), TEXT("bCompressVisibilityData"), bCompressVisibilityData, GLightmassIni));
const float CellSize = System.GetWorld()->GetWorldSettings()->VisibilityCellSize;
float PlayAreaHeight = 0;
VERIFYLIGHTMASSINI(GConfig->GetFloat(TEXT("DevOptions.PrecomputedVisibility"), TEXT("PlayAreaHeight"), PlayAreaHeight, GLightmassIni));
int32 CellBucketSize = 0;
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("CellRenderingBucketSize"), CellBucketSize, GLightmassIni));
int32 NumCellBuckets = 0;
VERIFYLIGHTMASSINI(GConfig->GetInt(TEXT("DevOptions.PrecomputedVisibility"), TEXT("NumCellRenderingBuckets"), NumCellBuckets, GLightmassIni));
int32 TotalNumQueries = 0;
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3776
Scope: file
Source code excerpt:
{
const FUncompressedPrecomputedVisibilityCell& OtherCell = CurrentSortCell[VisibilityCellIndex];
SpreadVisibilityCell(CellSize, PlayAreaHeight, OtherCell, CurrentCell, QueriesVisibleFromSpreadingNeighbors);
}
}
}
}
}
}
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3796
Scope (from outer to inner):
file
function void FLightmassProcessor::ApplyPrecomputedVisibility
Source code excerpt:
const FUncompressedPrecomputedVisibilityCell& OtherCell = OriginalPrecomputedVisibilityCells[OtherCellIndex];
SpreadVisibilityCell(CellSize, PlayAreaHeight, OtherCell, CurrentCell, QueriesVisibleFromSpreadingNeighbors);
}
}
}
}
const FVector2D CellBucketOriginXY(CombinedPrecomputedVisibilityCells[0].Bounds.Min.X, CombinedPrecomputedVisibilityCells[0].Bounds.Min.Y);
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3830
Scope (from outer to inner):
file
function void FLightmassProcessor::ApplyPrecomputedVisibility
Source code excerpt:
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityCellBucketOriginXY = CellBucketOriginXY;
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityCellSizeXY = CellSize;
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityCellSizeZ = PlayAreaHeight;
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityCellBucketSizeXY = CellBucketSize;
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityNumCellBuckets = NumCellBuckets;
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityCellBuckets.Empty(NumCellBuckets * NumCellBuckets);
System.GetWorld()->PersistentLevel->PrecomputedVisibilityHandler.PrecomputedVisibilityCellBuckets.AddZeroed(NumCellBuckets * NumCellBuckets);
// Split visibility data into ~32Kb chunks, to limit decompression time
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Lightmass/Lightmass.cpp:3852
Scope (from outer to inner):
file
function void FLightmassProcessor::ApplyPrecomputedVisibility
Source code excerpt:
NewCell.Min = CurrentCell.Bounds.Min;
// We're only storing Min per cell with a shared SizeXY and SizeZ for reduced memory storage
checkSlow(CurrentCell.Bounds.Max.Equals(CurrentCell.Bounds.Min + FVector(CellSize, CellSize, PlayAreaHeight), KINDA_SMALL_NUMBER * 10.0f));
NewCell.ChunkIndex = ChunkIndex;
NewCell.DataOffset = UncompressedVisibilityData.Num();
OutputBucket.Cells.Add(NewCell);
UncompressedVisibilityData.Append(CurrentCell.VisibilityData);
// Create a new chunk if we've reached the size limit or this is the last cell in a bucket
if (UncompressedVisibilityData.Num() > ChunkSizeTarget || CellIndex == CellRenderingBuckets[BucketIndex].Num() - 1)
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PrecomputedVisibility.cpp:328
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::SetupPrecomputedVisibility
Source code excerpt:
// Place a new cell if this is the highest height
if (HeightIndex + 1 == Cell.HitTriangles.Num()
// Or if there's a gap above this height of size PlayAreaHeight
|| ((Cell.HitTriangles[HeightIndex + 1].HeightRange.Y - CurrentMaxHeight) > PrecomputedVisibilitySettings.PlayAreaHeight
// And this height is not within a cell that was just placed
&& CurrentMaxHeight - LastSampleHeight > PrecomputedVisibilitySettings.PlayAreaHeight))
{
FPrecomputedVisibilityCell NewCell;
NewCell.Bounds = FBox3f(
FVector4f(
CurrentPosition.X - PrecomputedVisibilitySettings.CellSize / 2,
CurrentPosition.Y - PrecomputedVisibilitySettings.CellSize / 2,
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PrecomputedVisibility.cpp:342
Scope (from outer to inner):
file
function void FStaticLightingSystem::SetupPrecomputedVisibility
Source code excerpt:
CurrentPosition.X + PrecomputedVisibilitySettings.CellSize / 2,
CurrentPosition.Y + PrecomputedVisibilitySettings.CellSize / 2,
CurrentMaxHeight + PrecomputedVisibilitySettings.PlayAreaHeight));
AllPrecomputedVisibilityCells.Add(NewCell);
LastSampleHeight = CurrentMaxHeight;
PlacedHeightRanges.Add(FVector2f(NewCell.Bounds.Min.Z, NewCell.Bounds.Max.Z));
}
}
// Fractions of PrecomputedVisibilitySettings.PlayAreaHeight to guarantee have cell coverage
float TestHeights[3] = {.4f, .6f, .8f};
// Pass 2 - make sure the space above every triangle is covered by precomputed visibility cells, even if the cells are placed poorly (intersecting the floor)
for (int32 HeightIndex = 0; HeightIndex < Cell.HitTriangles.Num() - 1; HeightIndex++)
{
for (int32 ExtremaIndex = 0; ExtremaIndex < 2; ExtremaIndex++)
{
const float CurrentMaxHeight = ExtremaIndex == 0 ? Cell.HitTriangles[HeightIndex].HeightRange.X : Cell.HitTriangles[HeightIndex].HeightRange.Y;
const float CompareHeight = CurrentMaxHeight + .5f * PrecomputedVisibilitySettings.PlayAreaHeight;
for (int32 TestIndex = 0; TestIndex < UE_ARRAY_COUNT(TestHeights); TestIndex++)
{
const float TestHeight = CurrentMaxHeight + TestHeights[TestIndex] * PrecomputedVisibilitySettings.PlayAreaHeight;
int32 ClosestCellInZIndex = -1;
float ClosestCellInZDistance = FLT_MAX;
bool bInsideCell = false;
for (int32 PlacedHeightIndex = 0; PlacedHeightIndex < PlacedHeightRanges.Num(); PlacedHeightIndex++)
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PrecomputedVisibility.cpp:403
Scope: file
Source code excerpt:
if (CompareHeight < NearestCellCompareHeight)
{
DesiredCellBottom = FMath::Min(DesiredCellBottom, NearestCellHeightRange.X - PrecomputedVisibilitySettings.PlayAreaHeight);
}
else if (CompareHeight > NearestCellCompareHeight)
{
DesiredCellBottom = FMath::Max(DesiredCellBottom, NearestCellHeightRange.Y);
}
}
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PrecomputedVisibility.cpp:419
Scope: file
Source code excerpt:
CurrentPosition.X + PrecomputedVisibilitySettings.CellSize / 2,
CurrentPosition.Y + PrecomputedVisibilitySettings.CellSize / 2,
DesiredCellBottom + PrecomputedVisibilitySettings.PlayAreaHeight));
AllPrecomputedVisibilityCells.Add(NewCell);
PlacedHeightRanges.Add(FVector2f(NewCell.Bounds.Min.Z, NewCell.Bounds.Max.Z));
}
}
}
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Private/Lighting/PrecomputedVisibility.cpp:467
Scope (from outer to inner):
file
namespace Lightmass
function void FStaticLightingSystem::SetupPrecomputedVisibility
Source code excerpt:
SnappedPosition.X,
SnappedPosition.Y,
SnappedPosition.Z - .5f * PrecomputedVisibilitySettings.PlayAreaHeight),
FVector4f(
SnappedPosition.X + PrecomputedVisibilitySettings.CellSize,
SnappedPosition.Y + PrecomputedVisibilitySettings.CellSize,
SnappedPosition.Z + .5f * PrecomputedVisibilitySettings.PlayAreaHeight));
AllPrecomputedVisibilityCells.Add(NewCell);
// Verify that the camera track position is inside the placed cell
checkSlow(NewCell.Bounds.IsInside(CurrentPosition));
}
#Loc: <Workspace>/Engine/Source/Programs/UnrealLightmass/Public/SceneExport.h:397
Scope (from outer to inner):
file
namespace Lightmass
class class FPrecomputedVisibilitySettings
Source code excerpt:
/** World space size of visibility cells in the z dimension. */
float PlayAreaHeight;
/** Amount to increase the bounds of meshes when querying their visibility. Larger scales reduce visibility errors at the cost of less effective culling. */
float MeshBoundsScale;
/** Minimum number of samples on the mesh for each cell - mesh query. Small meshes use less samples. */
int32 MinMeshSamples;