Foliage
Foliage
#Overview
name: Foliage
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 24
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of the “Foliage” variable in Unreal Engine 5 is to manage and categorize foliage-related assets and components within the engine. It is primarily used for organizing and identifying assets related to vegetation and landscape elements in the game development process.
This variable is utilized by several Unreal Engine subsystems and modules, including:
- Asset Definition system
- Foliage system
- Landscape system
- Rendering system
- Nanite system
The value of this variable is typically set as a constant or enum value in various parts of the engine, such as in the EAssetCategoryPaths
and EHISMViewRelevanceType
enumerations.
Other variables that interact with the Foliage variable include:
EFilterFlags::Foliage
in the Nanite systemEngineShowFlags.InstancedFoliage
for rendering visibilityViewRelevanceType
in foliage components
Developers should be aware of the following when using this variable:
- It is used to categorize assets in the content browser and asset management systems.
- It affects the visibility and rendering of foliage elements in the game.
- It interacts with the Hierarchical Instanced Static Mesh (HISM) system for efficient rendering of multiple instances.
Best practices when using this variable include:
- Properly categorize foliage-related assets using the appropriate asset categories.
- Consider performance implications when working with large amounts of foliage, especially in relation to the Nanite and HISM systems.
- Be aware of how foliage interacts with other systems like landscapes and lighting.
- Use the appropriate flags and settings when creating or modifying foliage components to ensure proper rendering and performance.
By understanding and correctly utilizing the Foliage variable and related systems, developers can create more efficient and visually appealing vegetation in their Unreal Engine 5 projects.
#Setting Variables
#References In INI files
Location: <Workspace>/Engine/Config/BaseEngine.ini:2416, section: [StaticMeshLODSettings]
- INI Section:
StaticMeshLODSettings
- Raw value:
(NumLODs=1,MaxNumStreamedLODs=0,bSupportLODStreaming=0,Name=LOCTEXT("FoliageLOD","Foliage"))
- Is Array:
False
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Plugins/Editor/EngineAssetDefinitions/Source/Private/AssetDefinition_ActorFoliageSettings.h:19
Scope (from outer to inner):
file
class class UAssetDefinition_ActorFoliageSettings : public UAssetDefinitionDefault
function virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories
Source code excerpt:
virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories() const override
{
static const auto Categories = { EAssetCategoryPaths::Foliage };
return Categories;
}
// UAssetDefinition End
};
#Loc: <Workspace>/Engine/Plugins/Editor/EngineAssetDefinitions/Source/Private/AssetDefinition_InstancedFoliageSettings.h:19
Scope (from outer to inner):
file
class class UAssetDefinition_InstancedFoliageSettings : public UAssetDefinitionDefault
function virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories
Source code excerpt:
virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories() const override
{
static const auto Categories = { EAssetCategoryPaths::Foliage };
return Categories;
}
// UAssetDefinition End
};
#Loc: <Workspace>/Engine/Plugins/Editor/EngineAssetDefinitions/Source/Private/AssetDefinition_LandscapeGrassType.h:19
Scope (from outer to inner):
file
class class UAssetDefinition_LandscapeGrassType : public UAssetDefinitionDefault
function virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories
Source code excerpt:
virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories() const override
{
static const auto Categories = { EAssetCategoryPaths::Foliage };
return Categories;
}
// UAssetDefinition End
};
#Loc: <Workspace>/Engine/Plugins/Editor/EngineAssetDefinitions/Source/Private/AssetDefinition_ProceduralFoliageSpawner.h:19
Scope (from outer to inner):
file
class class UAssetDefinition_ProceduralFoliageSpawner : public UAssetDefinitionDefault
function virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories
Source code excerpt:
virtual TConstArrayView<FAssetCategoryPath> GetAssetCategories() const override
{
static const auto Categories = { EAssetCategoryPaths::Foliage };
return Categories;
}
//bool FAssetTypeActions_ProceduralFoliageSpawner::CanFilter()
//{
// return GetDefault<UEditorExperimentalSettings>()->bProceduralFoliage;
//}
#Loc: <Workspace>/Engine/Plugins/VirtualProduction/LevelSnapshots/Source/FoliageSupport/Private/FoliageSupport/FoliageSupport.cpp:63
Scope (from outer to inner):
file
namespace UE::LevelSnapshots::Foliage::Private
function static UFoliageType* FindFoliageInfoFor
Source code excerpt:
static UFoliageType* FindFoliageInfoFor(UHierarchicalInstancedStaticMeshComponent* Component)
{
AInstancedFoliageActor* Foliage = Cast<AInstancedFoliageActor>(Component->GetOwner());
if (!LIKELY(Foliage))
{
return nullptr;
}
for (auto FoliageIt = Foliage->GetFoliageInfos().CreateConstIterator(); FoliageIt; ++FoliageIt)
{
if (FoliageIt->Value->Implementation->IsOwnedComponent(Component))
{
return FoliageIt->Key;
}
}
#Loc: <Workspace>/Engine/Source/Editor/AssetDefinition/Private/AssetDefinition.cpp:18
Scope: file
Source code excerpt:
FAssetCategoryPath EAssetCategoryPaths::Blueprint(LOCTEXT("Blueprint", "Blueprint"));
FAssetCategoryPath EAssetCategoryPaths::Texture(LOCTEXT("Texture", "Texture"));
FAssetCategoryPath EAssetCategoryPaths::Foliage(LOCTEXT("Foliage", "Foliage"));
FAssetCategoryPath EAssetCategoryPaths::Input(LOCTEXT("Input", "Input"));
FAssetCategoryPath EAssetCategoryPaths::FX(LOCTEXT("FX", "FX"));
FAssetCategoryPath EAssetCategoryPaths::Cinematics(LOCTEXT("Cinematics", "Cinematics"));
FAssetCategoryPath EAssetCategoryPaths::Media(LOCTEXT("Media", "Media"));
FAssetCategoryPath EAssetCategoryPaths::World(LOCTEXT("World", "World"));
#Loc: <Workspace>/Engine/Source/Editor/AssetDefinition/Public/AssetDefinition.h:267
Scope: file
Source code excerpt:
static FAssetCategoryPath Blueprint;
static FAssetCategoryPath Cinematics;
static FAssetCategoryPath Foliage;
static FAssetCategoryPath FX;
static FAssetCategoryPath Gameplay;
static FAssetCategoryPath AI;
static FAssetCategoryPath Input;
static FAssetCategoryPath Material;
static FAssetCategoryPath Media;
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Classes/Components/HierarchicalInstancedStaticMeshComponent.h:18
Scope: file
Source code excerpt:
{
Grass,
Foliage,
HISM
};
// Due to BulkSerialize we can't edit the struct, so we must deprecated this one and create a new one
USTRUCT()
struct FClusterNode_DEPRECATED
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp:873
Scope (from outer to inner):
file
function FPrimitiveViewRelevance FHierarchicalStaticMeshSceneProxy::GetViewRelevance
Source code excerpt:
bShowInstancedMesh = View->Family->EngineShowFlags.InstancedGrass;
break;
case EHISMViewRelevanceType::Foliage:
bShowInstancedMesh = View->Family->EngineShowFlags.InstancedFoliage;
break;
case EHISMViewRelevanceType::HISM:
bShowInstancedMesh = View->Family->EngineShowFlags.InstancedStaticMeshes;
break;
default:
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Rendering/NaniteResources.cpp:948
Scope (from outer to inner):
file
namespace Nanite
function FSceneProxy::FSceneProxy
Source code excerpt:
bIsLandscapeGrass = true;
break;
case EHISMViewRelevanceType::Foliage:
FilterFlags = EFilterFlags::Foliage;
break;
default:
FilterFlags = EFilterFlags::InstancedStaticMesh;
break;
}
FilterFlags |= Component->Mobility == EComponentMobility::Static ? EFilterFlags::StaticMobility : EFilterFlags::NonStaticMobility;
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/NaniteSceneProxy.h:151
Scope (from outer to inner):
file
namespace Nanite
Source code excerpt:
StaticMesh = (1u << 0u),
InstancedStaticMesh = (1u << 1u),
Foliage = (1u << 2u),
Grass = (1u << 3u),
Landscape = (1u << 4u),
StaticMobility = (1u << 5u),
NonStaticMobility = (1u << 6u),
All = 0xFF
};
#Loc: <Workspace>/Engine/Source/Runtime/Foliage/Private/FoliageModule.cpp:3
Scope: file
Source code excerpt:
#include "Modules/ModuleManager.h"
IMPLEMENT_MODULE( IFoliageModule, Foliage );
#Loc: <Workspace>/Engine/Source/Runtime/Foliage/Private/InstancedFoliage.cpp:4338
Scope (from outer to inner):
file
function void AInstancedFoliageActor::Serialize
Source code excerpt:
void AInstancedFoliageActor::Serialize(FArchive& Ar)
{
LLM_SCOPE_BYNAME(TEXT("Foliage"));
Super::Serialize(Ar);
Ar.UsingCustomVersion(FFoliageCustomVersion::GUID);
#if WITH_EDITORONLY_DATA
if (!Ar.ArIsFilterEditorOnly && Ar.CustomVer(FFoliageCustomVersion::GUID) >= FFoliageCustomVersion::CrossLevelBase)
#Loc: <Workspace>/Engine/Source/Runtime/Foliage/Private/InstancedFoliage.cpp:5784
Scope (from outer to inner):
file
function UFoliageInstancedStaticMeshComponent::UFoliageInstancedStaticMeshComponent
Source code excerpt:
bEnableAutoLODGeneration = false;
ViewRelevanceType = EHISMViewRelevanceType::Foliage;
}
void UFoliageInstancedStaticMeshComponent::ReceiveComponentDamage(float DamageAmount, FDamageEvent const& DamageEvent, AController* EventInstigator, AActor* DamageCauser)
{
Super::ReceiveComponentDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Classes/LandscapeProxy.h:263
Scope: file
Source code excerpt:
{
FGrassCompKey Key;
TWeakObjectPtr<UHierarchicalInstancedStaticMeshComponent> Foliage;
TWeakObjectPtr<UHierarchicalInstancedStaticMeshComponent> PreviousFoliage;
TArray<FBox> ExcludedBoxes;
uint32 LastUsedFrameNumber;
uint32 ExclusionChangeTag;
double LastUsedTime;
bool Pending;
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Classes/LandscapeProxy.h:318
Scope (from outer to inner):
file
class class FAsyncGrassTask : public FNonAbandonableTask
Source code excerpt:
FAsyncGrassBuilder* Builder;
FCachedLandscapeFoliage::FGrassCompKey Key;
TWeakObjectPtr<UHierarchicalInstancedStaticMeshComponent> Foliage;
FAsyncGrassTask(FAsyncGrassBuilder* InBuilder, const FCachedLandscapeFoliage::FGrassCompKey& InKey, UHierarchicalInstancedStaticMeshComponent* InFoliage);
void DoWork();
FORCEINLINE TStatId GetStatId() const
{
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp:2341
Scope (from outer to inner):
file
function void ALandscapeProxy::FlushGrassComponents
Source code excerpt:
if (Component == nullptr || OnlyForComponents->Contains(Component))
{
UHierarchicalInstancedStaticMeshComponent *Used = (*Iter).Foliage.Get();
if (Used)
{
SCOPE_CYCLE_COUNTER(STAT_FoliageGrassDestoryComp);
Used->ClearInstances();
Used->DetachFromComponent(FDetachmentTransformRules(EDetachmentRule::KeepRelative, false));
Used->DestroyComponent();
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp:2767
Scope: file
Source code excerpt:
{
bRebuildForBoxes = true;
NewComp.PreviousFoliage = Existing->Foliage;
Existing->PendingRemovalRebuild = true;
}
else
{
Existing->ExclusionChangeTag = GGrassExclusionChangeTag;
}
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp:2828
Scope: file
Source code excerpt:
GrassInstancedStaticMeshComponent = NewObject<UGrassInstancedStaticMeshComponent>(this, NAME_None, RF_Transient);
}
NewComp.Foliage = GrassInstancedStaticMeshComponent;
FoliageCache.CachedGrassComps.Add(NewComp);
GrassInstancedStaticMeshComponent->Mobility = EComponentMobility::Static;
GrassInstancedStaticMeshComponent->SetStaticMesh(GrassVariety.GrassMesh);
GrassInstancedStaticMeshComponent->MinLOD = GrassVariety.MinLOD;
GrassInstancedStaticMeshComponent->bSelectable = false;
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp:2954
Scope (from outer to inner):
file
function void ALandscapeProxy::UpdateGrass
Source code excerpt:
{
const FCachedLandscapeFoliage::FGrassComp& GrassItem = *Iter;
UHierarchicalInstancedStaticMeshComponent *Used = GrassItem.Foliage.Get();
UHierarchicalInstancedStaticMeshComponent *UsedPrev = GrassItem.PreviousFoliage.Get();
bool bOld =
!GrassItem.Pending &&
(
!GrassItem.Key.BasedOn.Get() ||
!GrassItem.Key.GrassType.Get() ||
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp:3036
Scope (from outer to inner):
file
function void ALandscapeProxy::ProcessAsyncGrassInstanceTasks
Source code excerpt:
// We need to preserve the order here, otherwise we'll have new jobs that are added to the end jumping up in front of the queue and an original second job would be updated the last
AsyncFoliageTasks.RemoveAt(Index--);
UGrassInstancedStaticMeshComponent* GrassISMComponent = Cast<UGrassInstancedStaticMeshComponent>(Inner.Foliage.Get());
int32 NumBuiltRenderInstances = Inner.Builder->InstanceBuffer.GetNumInstances();
//UE_LOG(LogCore, Display, TEXT("%d instances in %4.0fms %6.0f instances / sec"), NumBuiltRenderInstances, 1000.0f * float(Inner.Builder->BuildTime), float(NumBuiltRenderInstances) / float(Inner.Builder->BuildTime));
FCachedLandscapeFoliage::FGrassCompKey& InnerKey = Inner.Key;
UE_LOG(LogGrass, Verbose, TEXT("ASYNC GRASS INSTANCES COMPLETE %s %s %d %d (%d)"),
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeGrass.cpp:3094
Scope (from outer to inner):
file
function FAsyncGrassTask::FAsyncGrassTask
Source code excerpt:
: Builder(InBuilder)
, Key(InKey)
, Foliage(InFoliage)
{
}
void FAsyncGrassTask::DoWork()
{
Builder->Build();
#Loc: <Workspace>/Engine/Source/Runtime/Landscape/Private/LandscapeLight.cpp:766
Scope (from outer to inner):
file
function void ULandscapeComponent::InvalidateLightingCacheDetailed
Source code excerpt:
const ULandscapeGrassType* GrassType = GrassKey.GrassType.Get();
const ULandscapeComponent* BasedOn = GrassKey.BasedOn.Get();
UHierarchicalInstancedStaticMeshComponent* GrassComponent = Iter->Foliage.Get();
if (BasedOn == this && GrassType && GrassComponent &&
GrassType->GrassVarieties.IsValidIndex(GrassKey.VarietyIndex) &&
GrassType->GrassVarieties[GrassKey.VarietyIndex].bUseLandscapeLightmap)
{
// Remove this grass component from the cache, which will cause it to be replaced
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/Nanite/NaniteCullRaster.cpp:3030
Scope (from outer to inner):
file
namespace Nanite
function void FRenderer::AddPass_PrimitiveFilter
Source code excerpt:
if (!SceneView.Family->EngineShowFlags.InstancedFoliage)
{
HiddenFilterFlags |= EFilterFlags::Foliage;
}
if (!SceneView.Family->EngineShowFlags.InstancedGrass)
{
HiddenFilterFlags |= EFilterFlags::Grass;
}