ShowFlag.Grain

ShowFlag.Grain

#Overview

name: ShowFlag.Grain

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

It is referenced in 7 C++ source files.

#Summary

#Usage in the C++ source code

The purpose of ShowFlag.Grain is to control the visibility of film grain post-processing effect in Unreal Engine’s rendering system. This setting variable is part of the post-processing pipeline and affects the final visual output of the scene.

The Unreal Engine subsystems that rely on this setting variable are primarily the rendering system and the post-processing module. Based on the callsites, we can see that it’s used in the SceneRendering and SceneView components.

The value of this variable is set through the engine’s show flags system, which allows toggling various visual features on and off. It can be manipulated through the engine’s UI or programmatically.

The ShowFlag.Grain interacts with other variables, particularly:

  1. FinalPostProcessSettings.FilmGrainIntensity: If ShowFlag.Grain is false, FilmGrainIntensity is set to 0, effectively disabling the film grain effect.
  2. FinalPostProcessSettings.FilmGrainTexture: This texture is used when the grain effect is enabled.

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

  1. It’s fixed in shipping builds, meaning it can’t be toggled at runtime in final game releases.
  2. It affects performance, as enabling grain requires additional post-processing.
  3. It’s part of the SFG_PostProcess group, indicating its role in post-processing effects.

Best practices when using this variable include:

  1. Use it judiciously, as film grain can significantly alter the visual style of your game.
  2. Consider performance implications, especially on lower-end devices.
  3. Ensure it aligns with your game’s artistic direction and target platform capabilities.

Regarding the associated variable ‘Grain’:

The purpose of the Grain variable varies depending on the context. In the MotoSynthEngine, it’s used in audio processing for granular synthesis. In the rendering context, it’s likely an internal representation of the ShowFlag.Grain setting.

The Grain variable is used in multiple Unreal Engine subsystems, including the experimental MotoSynth plugin for audio and the core rendering system.

The value of this variable is set and used differently in various contexts. In audio processing, it’s part of the grain pool in granular synthesis. In rendering, its value is typically derived from the ShowFlag.Grain setting.

Developers should be aware that the Grain variable has different meanings and usages in different parts of the engine. It’s crucial to understand the specific context when working with this variable.

Best practices include ensuring proper initialization and cleanup of Grain objects in audio processing, and correctly handling the grain effect in rendering based on the ShowFlag.Grain setting.

#References in C++ code

#Callsites

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

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:47

Scope: file

Source code excerpt:

SHOWFLAG_ALWAYS_ACCESSIBLE(Vignette, SFG_PostProcess, NSLOCTEXT("UnrealEd", "VignetteSF", "Vignette"))
/** Fine film grain */
SHOWFLAG_FIXED_IN_SHIPPING(1, Grain, SFG_PostProcess, NSLOCTEXT("UnrealEd", "GrainSF", "Grain"))
/** Screen Space Ambient Occlusion, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(AmbientOcclusion, SFG_LightingComponents, NSLOCTEXT("UnrealEd", "AmbientOcclusionSF", "Ambient Occlusion"))
/** Decal rendering, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(Decals, SFG_Normal, NSLOCTEXT("UnrealEd", "DecalsSF", "Decals"))
/** like bloom dirt mask */
SHOWFLAG_FIXED_IN_SHIPPING(1, CameraImperfections, SFG_PostProcess, NSLOCTEXT("UnrealEd", "CameraImperfectionsSF", "Camera Imperfections"))

#Associated Variable and Callsites

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

#Loc: <Workspace>/Engine/Plugins/Experimental/MotoSynth/Source/MotoSynth/Private/MotoSynthEngine.cpp:438

Scope (from outer to inner):

file
function     void FMotoSynthEngine::GenerateGranularEngine

Source code excerpt:

			{
				int32 GrainIndex = ActiveGrains[ActiveGrainIndex];
				FMotoSynthGrainRuntime& Grain = GrainPool[GrainIndex];
				Grain.SetRPM(CurrentRPM);

				if (bGranularEngineEnabled)
				{
					OutAudio[SampleIndex] += Grain.GenerateSample();
				}
				else
				{
					// Still need to generate the grain since envelope state is dependent on grain state
					// TODO: if this is used at runtime, implement a virtual GenerateSample to update state but not do any audio work 
					// Currently the expectation is that this mode is only an editor-only mode (i.e. no pure synth engines shipped)
					Grain.GenerateSample();
				}

				if (Grain.IsDone())
				{
					ActiveGrains.RemoveAtSwap(ActiveGrainIndex, 1, EAllowShrinking::No);
					FreeGrains.Push(GrainIndex);
				}
			}

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/SceneView.cpp:2118

Scope (from outer to inner):

file
function     void FSceneView::EndFinalPostprocessSettings

Source code excerpt:

	}

	if(!Family->EngineShowFlags.Grain)
	{
		FinalPostProcessSettings.FilmGrainIntensity = 0.0f;
	}

	if(!Family->EngineShowFlags.CameraImperfections)
	{

#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:47

Scope: file

Source code excerpt:

SHOWFLAG_ALWAYS_ACCESSIBLE(Vignette, SFG_PostProcess, NSLOCTEXT("UnrealEd", "VignetteSF", "Vignette"))
/** Fine film grain */
SHOWFLAG_FIXED_IN_SHIPPING(1, Grain, SFG_PostProcess, NSLOCTEXT("UnrealEd", "GrainSF", "Grain"))
/** Screen Space Ambient Occlusion, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(AmbientOcclusion, SFG_LightingComponents, NSLOCTEXT("UnrealEd", "AmbientOcclusionSF", "Ambient Occlusion"))
/** Decal rendering, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(Decals, SFG_Normal, NSLOCTEXT("UnrealEd", "DecalsSF", "Decals"))
/** like bloom dirt mask */
SHOWFLAG_FIXED_IN_SHIPPING(1, CameraImperfections, SFG_PostProcess, NSLOCTEXT("UnrealEd", "CameraImperfectionsSF", "Camera Imperfections"))

#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/SceneRendering.cpp:2705

Scope (from outer to inner):

file
function     FSceneRenderer::FSceneRenderer

Source code excerpt:

		// Handle the film grain texture
		if (ViewInfo->FinalPostProcessSettings.FilmGrainIntensity > 0.0f &&
			ViewFamily.EngineShowFlags.Grain &&
			CVarFilmGrain.GetValueOnGameThread() != 0 &&
			SupportsFilmGrain(ViewFamily.GetShaderPlatform()))
		{
			UTexture2D* FilmGrainTexture = ViewInfo->FinalPostProcessSettings.FilmGrainTexture;
			if (FilmGrainTexture == nullptr)
			{

#Loc: <Workspace>/Engine/Source/Runtime/SignalProcessing/Private/GrainDelay.cpp:96

Scope (from outer to inner):

file
namespace    Audio
namespace    GrainDelay
function     void FGrainDelay::SetGrainBasePitchShiftRatio

Source code excerpt:

				for (const int32 ActiveGrainId : ActiveGrains)
				{
					FGrain& Grain = GrainPool[ActiveGrainId];

					// Set the pitch shift ratio of the grain.
					// This function will take into account the initial random pitch offset
					Grain.SetGrainPitchShiftRatio(InPitchRatioBase, SampleRate);
				}
			}
		}
		
		void FGrainDelay::SpawnGrain(const float InDelay, const float InDuration, const float InPitchShiftRatioOffset)
		{

#Loc: <Workspace>/Engine/Source/Runtime/SignalProcessing/Private/GrainDelay.cpp:149

Scope (from outer to inner):

file
namespace    Audio
namespace    GrainDelay
function     float FGrainDelay::SynthesizeFrame

Source code excerpt:

				// Get the grain data
				const int32 GrainId = ActiveGrains[ActiveGrainIndex];
				FGrain& Grain = GrainPool[GrainId];
				
				// Calculate the grain envelope
				// should have never been added to the pool
				check(!FMath::IsNearlyZero(Grain.DurationFrames));
				const float Fraction = FMath::Min(Grain.NumFramesRendered / Grain.DurationFrames, 1.0f);
				const float GrainVolume = Grain::GetValue(GrainEnvelope, Fraction);

				const float PitchShiftedSample = Grain.PitchShifter.ReadDopplerShiftedTapFromDelay(InDelayLine, Grain.DelayTapPositionMilliseconds);
				OutFrame += GrainVolume * PitchShiftedSample;

				// Note we are tracking real frames rendered not frames consumed from the delay for grain duration 
				Grain.NumFramesRendered += 1.0f;

				// Clean up the grain once it's done
				if (Grain.NumFramesRendered >= Grain.DurationFrames)
				{
					// Pop back on this id so we can reuse it next time a grain is spawned
					FreeGrains.Add(GrainId);

					// Remove at swap allows us to clean up the active grain list while we loop through it
					ActiveGrains.RemoveAtSwap(ActiveGrainIndex, 1, EAllowShrinking::No);