foliage.DitheredLOD

foliage.DitheredLOD

#Overview

name: foliage.DitheredLOD

This variable is created as a Console Variable (cvar).

It is referenced in 8 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of foliage.DitheredLOD is to control the LOD (Level of Detail) transition method for foliage in Unreal Engine 5. It determines whether dithered LOD or popping LOD is used for foliage rendering.

This setting variable is primarily used by the rendering system, specifically for foliage and hierarchical instanced static meshes. It is part of the Engine module and is also utilized by the MovieRenderPipeline plugin.

The value of this variable is set through a console variable (CVar) named CVarDitheredLOD. It is initialized with a default value of 1, meaning dithered LOD is enabled by default. The value can be changed at runtime through console commands or programmatically.

The main subsystems that rely on this setting variable are:

  1. The Hierarchical Instanced Static Mesh rendering system
  2. The Movie Render Pipeline

The associated variable CVarDitheredLOD interacts directly with foliage.DitheredLOD, as they share the same value and purpose.

Developers should be aware of the following when using this variable:

  1. A value greater than zero enables dithered LOD, while a value of zero or less uses popping LOD.
  2. It can be overridden in certain scenarios, such as during movie rendering, to force a specific LOD behavior.
  3. It interacts with other LOD-related variables like foliage.ForceLOD.

Best practices when using this variable include:

  1. Consider the performance implications of dithered vs. popping LOD transitions.
  2. Test the visual quality and performance with different values to find the optimal setting for your project.
  3. Be cautious when overriding this value, especially in movie rendering scenarios, as it may affect the final output quality.

Regarding the associated variable CVarDitheredLOD: The purpose of CVarDitheredLOD is to provide a programmatic way to access and modify the foliage.DitheredLOD setting. It is implemented as a TAutoConsoleVariable, which allows for easy runtime modification and querying of the value.

CVarDitheredLOD is used in the Hierarchical Instanced Static Mesh rendering code to determine whether to use multiple sections for LOD transitions. It is checked on the render thread to ensure thread-safe access to the current value.

Developers should be aware that changes to CVarDitheredLOD will directly affect the behavior of foliage LOD transitions in the engine. When using this variable, ensure that any modifications are made in a thread-safe manner, especially when accessing it from different engine subsystems.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp:66

Scope: file

Source code excerpt:


static TAutoConsoleVariable<int32> CVarDitheredLOD(
	TEXT("foliage.DitheredLOD"),
	1,
	TEXT("If greater than zero, dithered LOD is used, otherwise popping LOD is used."));

static TAutoConsoleVariable<int32> CVarOverestimateLOD(
	TEXT("foliage.OverestimateLOD"),
	0,

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Private/Graph/Nodes/MovieGraphGlobalGameOverrides.cpp:53

Scope (from outer to inner):

file
function     void UMovieGraphGlobalGameOverridesNode::BuildNewProcessCommandLineArgsImpl

Source code excerpt:

		InOutDeviceProfileCvars.Add(TEXT("r.SkeletalMeshLODBias=-10"));
		InOutDeviceProfileCvars.Add(TEXT("r.ParticleLODBias=-10"));
		InOutDeviceProfileCvars.Add(TEXT("foliage.DitheredLOD=0"));
		InOutDeviceProfileCvars.Add(TEXT("foliage.ForceLOD=0"));
	}

	if (bDisableHLODs)
	{
		// It's a command and not an integer cvar (despite taking 1/0)

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Private/Graph/Nodes/MovieGraphGlobalGameOverrides.cpp:119

Scope (from outer to inner):

file
function     void UMovieGraphGlobalGameOverridesNode::ApplySettings

Source code excerpt:

		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousSkeletalMeshBias, TEXT("r.SkeletalMeshLODBias"), -10, bOverrideValues);
		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousParticleLODBias, TEXT("r.ParticleLODBias"), -10, bOverrideValues);
		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousFoliageDitheredLOD, TEXT("foliage.DitheredLOD"), 0, bOverrideValues);
		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousFoliageForceLOD, TEXT("foliage.ForceLOD"), 0, bOverrideValues);
	}

	if (bDisableHLODs)
	{
		// It's a command and not an integer cvar (despite taking 1/0), so we can't cache it 

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Private/MoviePipelineGameOverrideSetting.cpp:67

Scope (from outer to inner):

file
function     void UMoviePipelineGameOverrideSetting::ApplyCVarSettings

Source code excerpt:

		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousSkeletalMeshBias, TEXT("r.SkeletalMeshLODBias"), -10, bOverrideValues);
		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousParticleLODBias, TEXT("r.ParticleLODBias"), -10, bOverrideValues);
		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousFoliageDitheredLOD, TEXT("foliage.DitheredLOD"), 0, bOverrideValues);
		MOVIEPIPELINE_STORE_AND_OVERRIDE_CVAR_INT(PreviousFoliageForceLOD, TEXT("foliage.ForceLOD"), 0, bOverrideValues);
	}

	if (bDisableHLODs)
	{
		// It's a command and not an integer cvar (despite taking 1/0), so we can't cache it 

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Private/MoviePipelineGameOverrideSetting.cpp:193

Scope (from outer to inner):

file
function     void UMoviePipelineGameOverrideSetting::BuildNewProcessCommandLineArgsImpl

Source code excerpt:

		InOutDeviceProfileCvars.Add(TEXT("r.SkeletalMeshLODBias=-10"));
		InOutDeviceProfileCvars.Add(TEXT("r.ParticleLODBias=-10"));
		InOutDeviceProfileCvars.Add(TEXT("foliage.DitheredLOD=0"));
		InOutDeviceProfileCvars.Add(TEXT("foliage.ForceLOD=0"));
	}

	if (bDisableHLODs)
	{
		// It's a command and not an integer cvar (despite taking 1/0)

#Loc: <Workspace>/Engine/Plugins/MovieScene/MovieRenderPipeline/Source/MovieRenderPipelineCore/Public/Graph/Nodes/MovieGraphGlobalGameOverrides.h:120

Scope (from outer to inner):

file
function     class MOVIERENDERPIPELINECORE_API UMovieGraphGlobalGameOverridesNode : public UMovieGraphSettingNode { GENERATED_BODY

Source code excerpt:

	 * - r.SkeletalMeshLODBias
	 * - r.ParticleLODBias
	 * - foliage.DitheredLOD
	 * - foliage.ForceLOD
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rendering", meta = (EditCondition = "bOverride_bDisableLODs"))
	bool bDisableLODs;

	/**
	 * Determines if hierarchical LODs should be disabled and their real meshes used instead, regardless of distance.
	 * Note that this does not affect World Partition HLODs.
	 */
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Rendering", meta = (EditCondition = "bOverride_bDisableHLODs"))
	bool bDisableHLODs;

	/**
	 * Flushing level streaming ensures that any pending changes to sub-levels or world partition are fully processed before we render
	 * the frame. This feature generally only adds to render times on the frames that have level visibility state changes, so generally
	 * safe to leave turned on all the time.

#Associated Variable and Callsites

This variable is associated with another variable named CVarDitheredLOD. They share the same value. See the following C++ source code.

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp:65

Scope: file

Source code excerpt:

	ECVF_Scalability);

static TAutoConsoleVariable<int32> CVarDitheredLOD(
	TEXT("foliage.DitheredLOD"),
	1,
	TEXT("If greater than zero, dithered LOD is used, otherwise popping LOD is used."));

static TAutoConsoleVariable<int32> CVarOverestimateLOD(
	TEXT("foliage.OverestimateLOD"),

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/HierarchicalInstancedStaticMesh.cpp:1490

Scope (from outer to inner):

file
function     void FHierarchicalStaticMeshSceneProxy::GetDynamicMeshElements

Source code excerpt:

	SCOPE_CYCLE_COUNTER(STAT_HISMCGetDynamicMeshElement);

	bool bMultipleSections = bDitheredLODTransitions && CVarDitheredLOD.GetValueOnRenderThread() > 0;
	// Disable multiple selections when forced LOD is set
	bMultipleSections = bMultipleSections && ForcedLodModel <= 0 && CVarForceLOD.GetValueOnRenderThread() < 0;

	bool bSingleSections = !bMultipleSections;
	bool bOverestimate = CVarOverestimateLOD.GetValueOnRenderThread() > 0;