ShowFlag.HMDDistortion
ShowFlag.HMDDistortion
#Overview
name: ShowFlag.HMDDistortion
This variable is created as a Console Variable (cvar).
- type:
Var
- help:
Allows to override a specific showflag (works in editor and game, \
It is referenced in 15
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of ShowFlag.HMDDistortion is to control the distortion of output for Head-Mounted Display (HMD) devices in Unreal Engine’s rendering pipeline. This setting is primarily used in the post-processing stage of rendering for VR applications.
This variable is utilized by several Unreal Engine subsystems and plugins, including:
- The core rendering system (in MobileShadingRenderer and PostProcessing)
- The HeadMountedDisplay module
- Various VR-related plugins (SimpleHMD, PixelStreamingHMD, OpenXRHMD)
- The XRBase plugin
The value of this variable is typically set in the SetupViewFamily function of various HMD implementations. It can also be controlled through the engine’s show flags system.
The HMDDistortion flag interacts closely with other variables, particularly:
- StereoRendering: Often set alongside HMDDistortion to enable stereoscopic 3D rendering
- MotionBlur: Usually disabled when HMDDistortion is enabled
- Various other rendering flags that may need to be adjusted for VR rendering
Developers should be aware of the following when using this variable:
- It’s marked as SHOWFLAG_ALWAYS_ACCESSIBLE, meaning it’s available even in shipping builds
- Different HMD implementations may handle this flag differently. For example, PixelStreamingHMD sets it to false to avoid applying distortion on the UE side
- It’s part of the post-processing pass sequence and can affect performance
Best practices when using this variable include:
- Ensure it’s correctly set for your specific HMD implementation
- Be aware of its performance implications in your post-processing pipeline
- Consider its interaction with other rendering flags, especially in VR contexts
- Test thoroughly with your target HMD devices to ensure correct distortion application
The associated variable HMDDistortion is effectively the same as ShowFlag.HMDDistortion. It’s used in the same contexts and with the same considerations. The main difference is in how it’s accessed or set in different parts of the engine code.
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:311
Scope: file
Source code excerpt:
SHOWFLAG_FIXED_IN_SHIPPING(0, HighResScreenshotMask, SFG_Transient, NSLOCTEXT("UnrealEd", "HighResScreenshotMaskSF", "High Res Screenshot Mask"))
/** Distortion of output for HMD devices, SHOWFLAG_ALWAYS_ACCESSIBLE for now because USceneCaptureComponent needs that */
SHOWFLAG_ALWAYS_ACCESSIBLE(HMDDistortion, SFG_PostProcess, NSLOCTEXT("UnrealEd", "HMDDistortionSF", "HMD Distortion"))
/** Whether to render in stereoscopic 3d, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's used by StereoRendering */
SHOWFLAG_ALWAYS_ACCESSIBLE(StereoRendering, SFG_Hidden, NSLOCTEXT("UnrealEd", "StereoRenderingSF", "Stereoscopic Rendering"))
/** Show objects even if they should be distance culled, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(DistanceCulledPrimitives, SFG_Hidden, NSLOCTEXT("UnrealEd", "DistanceCulledPrimitivesSF", "Distance Culled Primitives"))
/** To visualize the culling in Tile Based Deferred Lighting, later for non tiled as well */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeLightCulling, SFG_Hidden, NSLOCTEXT("UnrealEd", "VisualizeLightCullingSF", "Light Culling"))
#Associated Variable and Callsites
This variable is associated with another variable named HMDDistortion
. They share the same value. See the following C++ source code.
#Loc: <Workspace>/Engine/Plugins/Experimental/SimpleHMD/Source/SimpleHMD/Private/SimpleHMD.cpp:276
Scope (from outer to inner):
file
function void FSimpleHMD::SetupViewFamily
Source code excerpt:
{
InViewFamily.EngineShowFlags.MotionBlur = 0;
InViewFamily.EngineShowFlags.HMDDistortion = true;
InViewFamily.EngineShowFlags.StereoRendering = IsStereoEnabled();
if (UWorld* World = GWorld)
{
WorldToMeters = World->GetWorldSettings()->WorldToMeters;
}
#Loc: <Workspace>/Engine/Plugins/Media/PixelStreaming/Source/PixelStreamingHMD/Private/PixelStreamingHMD.cpp:289
Scope (from outer to inner):
file
function void FPixelStreamingHMD::SetupViewFamily
Source code excerpt:
InViewFamily.EngineShowFlags.MotionBlur = 0;
// Note: We do not want to apply any distortion on the UE side.
InViewFamily.EngineShowFlags.HMDDistortion = false;
InViewFamily.EngineShowFlags.StereoRendering = IsStereoEnabled();
if (UWorld* World = GWorld)
{
WorldToMeters = World->GetWorldSettings()->WorldToMeters;
}
#Loc: <Workspace>/Engine/Plugins/Runtime/OpenXR/Source/OpenXRHMD/Private/OpenXRHMD.cpp:1229
Scope (from outer to inner):
file
function void FOpenXRHMD::SetupViewFamily
Source code excerpt:
{
InViewFamily.EngineShowFlags.MotionBlur = 0;
InViewFamily.EngineShowFlags.HMDDistortion = false;
InViewFamily.EngineShowFlags.StereoRendering = IsStereoEnabled();
const FPipelinedFrameState& FrameState = GetPipelinedFrameStateForThread();
if (FrameState.Views.Num() > 2)
{
InViewFamily.EngineShowFlags.Vignette = 0;
#Loc: <Workspace>/Engine/Plugins/Runtime/XRBase/Source/XRBase/Private/DefaultXRCamera.cpp:216
Scope (from outer to inner):
file
function void FDefaultXRCamera::SetupViewFamily
Source code excerpt:
if (InViewFamily.Views.Num() > 0 && !InViewFamily.Views[0]->bIsSceneCapture)
{
InViewFamily.EngineShowFlags.HMDDistortion = HMD != nullptr ? HMD->GetHMDDistortionEnabled(InViewFamily.Scene->GetShadingPath()) : false;
}
InViewFamily.EngineShowFlags.StereoRendering = bCurrentFrameIsStereoRendering;
InViewFamily.EngineShowFlags.Rendering = HMD != nullptr ? !HMD->IsRenderingPaused() : true;
}
void FDefaultXRCamera::SetupView(FSceneViewFamily& InViewFamily, FSceneView& InView)
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:311
Scope: file
Source code excerpt:
SHOWFLAG_FIXED_IN_SHIPPING(0, HighResScreenshotMask, SFG_Transient, NSLOCTEXT("UnrealEd", "HighResScreenshotMaskSF", "High Res Screenshot Mask"))
/** Distortion of output for HMD devices, SHOWFLAG_ALWAYS_ACCESSIBLE for now because USceneCaptureComponent needs that */
SHOWFLAG_ALWAYS_ACCESSIBLE(HMDDistortion, SFG_PostProcess, NSLOCTEXT("UnrealEd", "HMDDistortionSF", "HMD Distortion"))
/** Whether to render in stereoscopic 3d, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's used by StereoRendering */
SHOWFLAG_ALWAYS_ACCESSIBLE(StereoRendering, SFG_Hidden, NSLOCTEXT("UnrealEd", "StereoRenderingSF", "Stereoscopic Rendering"))
/** Show objects even if they should be distance culled, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(DistanceCulledPrimitives, SFG_Hidden, NSLOCTEXT("UnrealEd", "DistanceCulledPrimitivesSF", "Distance Culled Primitives"))
/** To visualize the culling in Tile Based Deferred Lighting, later for non tiled as well */
SHOWFLAG_FIXED_IN_SHIPPING(0, VisualizeLightCulling, SFG_Hidden, NSLOCTEXT("UnrealEd", "VisualizeLightCullingSF", "Light Culling"))
#Loc: <Workspace>/Engine/Source/Runtime/HeadMountedDisplay/Public/IHeadMountedDisplay.h:117
Scope (from outer to inner):
file
class class IHeadMountedDisplay : public IModuleInterface
Source code excerpt:
/**
* Whether HMDDistortion post processing is enabled or not
*/
virtual bool GetHMDDistortionEnabled(EShadingPath ShadingPath) const = 0;
/**
* Called just before rendering the current frame on the render thread. Invoked before applying late update, so plugins that want to refresh poses on the
* render thread prior to late update. Use this to perform any initializations prior to rendering.
*/
UE_DEPRECATED(4.19, "Use IXRTrackingSystem::OnBeginRendering_Renderthread instead")
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/MobileShadingRenderer.cpp:506
Scope (from outer to inner):
file
function void FMobileSceneRenderer::InitViews
Source code excerpt:
// For the most part this is not the case when using scene captures. Thus scene captures always render to scene color target.
const bool bShouldCompositeEditorPrimitives = FSceneRenderer::ShouldCompositeEditorPrimitives(Views[0]);
const bool bStereoRenderingAndHMD = ViewFamily.EngineShowFlags.StereoRendering && ViewFamily.EngineShowFlags.HMDDistortion;
bRenderToSceneColor = !bGammaSpace
|| bStereoRenderingAndHMD
|| bRequiresUpscale
|| bShouldCompositeEditorPrimitives
|| Views[0].bIsSceneCapture
|| Views[0].bIsReflectionCapture
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:389
Scope (from outer to inner):
file
function void AddPostProcessingPasses
Source code excerpt:
VisualizeTemporalUpscaler,
PixelInspector,
HMDDistortion,
HighResolutionScreenshotMask,
#if UE_ENABLE_DEBUG_DRAWING
DebugPrimitive,
#endif
PrimaryUpscale,
SecondaryUpscale,
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:496
Scope (from outer to inner):
file
function void AddPostProcessingPasses
Source code excerpt:
PassSequence.SetEnabled(EPass::PixelInspector, false);
#endif
PassSequence.SetEnabled(EPass::HMDDistortion, EngineShowFlags.StereoRendering && EngineShowFlags.HMDDistortion);
PassSequence.SetEnabled(EPass::HighResolutionScreenshotMask, IsHighResolutionScreenshotMaskEnabled(View));
#if UE_ENABLE_DEBUG_DRAWING
PassSequence.SetEnabled(EPass::DebugPrimitive, FSceneRenderer::ShouldCompositeDebugPrimitivesInPostProcess(View));
#endif
PassSequence.SetEnabled(EPass::PrimaryUpscale, PaniniConfig.IsEnabled() || (View.PrimaryScreenPercentageMethod == EPrimaryScreenPercentageMethod::SpatialUpscale && PrimaryViewRect.Size() != View.GetSecondaryViewRectSize()));
PassSequence.SetEnabled(EPass::SecondaryUpscale, View.RequiresSecondaryUpscale() || View.Family->GetSecondarySpatialUpscalerInterface() != nullptr);
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:1644
Scope (from outer to inner):
file
function void AddPostProcessingPasses
Source code excerpt:
#endif
if (PassSequence.IsEnabled(EPass::HMDDistortion))
{
FHMDDistortionInputs PassInputs;
PassSequence.AcceptOverrideIfLastPass(EPass::HMDDistortion, PassInputs.OverrideOutput);
PassInputs.SceneColor = SceneColor;
SceneColor = AddHMDDistortionPass(GraphBuilder, View, PassInputs);
}
if (PassSequence.IsEnabled(EPass::HighResolutionScreenshotMask))
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:2146
Scope (from outer to inner):
file
function void AddMobilePostProcessingPasses
Source code excerpt:
SecondaryUpscale,
Visualize,
HMDDistortion,
MAX
};
static const TCHAR* PassNames[] =
{
TEXT("Distortion"),
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:2232
Scope (from outer to inner):
file
function void AddMobilePostProcessingPasses
Source code excerpt:
PassSequence.SetEnabled(EPass::Visualize, View.Family->EngineShowFlags.ShaderComplexity);
PassSequence.SetEnabled(EPass::HMDDistortion, View.Family->EngineShowFlags.StereoRendering && View.Family->EngineShowFlags.HMDDistortion);
// Always evaluate custom post processes
// The scene color will be decoded at the first post-process material and output linear color space for the following passes
// bMetalMSAAHDRDecode will be set to false if there is any post-process material exist
auto AddPostProcessMaterialPass = [&GraphBuilder, &View, &Inputs, &SceneColor, &CustomDepth, &bMetalMSAAHDRDecode, &PassSequence](EBlendableLocation BlendableLocation, bool bLastPass)
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/PostProcess/PostProcessing.cpp:2922
Scope (from outer to inner):
file
function void AddMobilePostProcessingPasses
Source code excerpt:
}
if (PassSequence.IsEnabled(EPass::HMDDistortion))
{
FHMDDistortionInputs PassInputs;
PassSequence.AcceptOverrideIfLastPass(EPass::HMDDistortion, PassInputs.OverrideOutput);
PassInputs.SceneColor = SceneColor;
PassInputs.OverrideOutput.LoadAction = View.IsFirstInFamily() ? ERenderTargetLoadAction::EClear : ERenderTargetLoadAction::ELoad;
SceneColor = AddHMDDistortionPass(GraphBuilder, View, PassInputs);
}
#Loc: <Workspace>/Engine/Source/Runtime/Renderer/Private/ReflectionEnvironmentCapture.cpp:1291
Scope (from outer to inner):
file
function void CaptureSceneIntoScratchCubemap
Source code excerpt:
ViewFamily.EngineShowFlags.MotionBlur = 0;
ViewFamily.EngineShowFlags.SetOnScreenDebug(false);
ViewFamily.EngineShowFlags.HMDDistortion = 0;
// Conditionally exclude particles and light functions as they are usually dynamic, and can't be captured well
ViewFamily.EngineShowFlags.Particles = 0;
ViewFamily.EngineShowFlags.LightFunctions = abs(GReflectionCaptureEnableLightFunctions) ? 1 : 0;
ViewFamily.EngineShowFlags.SetCompositeEditorPrimitives(false);
// These are highly dynamic and can't be captured effectively
ViewFamily.EngineShowFlags.LightShafts = 0;