EM_Task/UnrealEd/Private/SEditorViewportViewMenu.cpp
Boshuang Zhao 5144a49c9b add
2026-02-13 16:18:33 +08:00

388 lines
20 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SEditorViewportViewMenu.h"
#include "SEditorViewportViewMenuContext.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "ToolMenus.h"
#include "EditorStyleSet.h"
#include "EditorViewportCommands.h"
#include "RayTracingDebugVisualizationMenuCommands.h"
#include "RenderResource.h"
#define LOCTEXT_NAMESPACE "EditorViewportViewMenu"
const FName SEditorViewportViewMenu::BaseMenuName("UnrealEd.ViewportToolbar.View");
void SEditorViewportViewMenu::Construct(const FArguments& InArgs, TSharedRef<SEditorViewport> InViewport, TSharedRef<class SViewportToolBar> InParentToolBar)
{
Viewport = InViewport;
MenuName = BaseMenuName;
MenuExtenders = InArgs._MenuExtenders;
SEditorViewportToolbarMenu::Construct(
SEditorViewportToolbarMenu::FArguments()
.ParentToolBar(InParentToolBar)
.Cursor(EMouseCursor::Default)
.Label(this, &SEditorViewportViewMenu::GetViewMenuLabel)
.LabelIcon(this, &SEditorViewportViewMenu::GetViewMenuLabelIcon)
.OnGetMenuContent(this, &SEditorViewportViewMenu::GenerateViewMenuContent));
}
FText SEditorViewportViewMenu::GetViewMenuLabel() const
{
FText Label = LOCTEXT("ViewMenuTitle_Default", "View");
TSharedPtr<SEditorViewport> PinnedViewport = Viewport.Pin();
if (PinnedViewport.IsValid())
{
const TSharedPtr<FEditorViewportClient> ViewportClient = PinnedViewport->GetViewportClient();
check(ViewportClient.IsValid());
const EViewModeIndex ViewMode = ViewportClient->GetViewMode();
// If VMI_VisualizeBuffer, return its subcategory name
if (ViewMode == VMI_VisualizeBuffer)
{
Label = ViewportClient->GetCurrentBufferVisualizationModeDisplayName();
}
// For any other category, return its own name
else
{
Label = UViewModeUtils::GetViewModeDisplayName(ViewMode);
}
}
return Label;
}
const FSlateBrush* SEditorViewportViewMenu::GetViewMenuLabelIcon() const
{
FName Icon = NAME_None;
TSharedPtr<SEditorViewport> PinnedViewport = Viewport.Pin();
if (PinnedViewport.IsValid())
{
static FName WireframeIcon("EditorViewport.WireframeMode");
static FName UnlitIcon("EditorViewport.UnlitMode");
static FName LitIcon("EditorViewport.LitMode");
static FName DetailLightingIcon("EditorViewport.DetailLightingMode");
static FName LightingOnlyIcon("EditorViewport.LightingOnlyMode");
static FName LightComplexityIcon("EditorViewport.LightComplexityMode");
static FName ShaderComplexityIcon("EditorViewport.ShaderComplexityMode");
static FName QuadOverdrawIcon("EditorViewport.QuadOverdrawMode");
static FName ShaderComplexityWithQuadOverdrawIcon("EditorViewport.ShaderCOmplexityWithQuadOverdrawMode");
static FName PrimitiveDistanceAccuracyIcon("EditorViewport.TexStreamAccPrimitiveDistanceMode");
static FName MeshUVDensityAccuracyIcon("EditorViewport.TexStreamAccMeshUVDensityMode");
static FName MaterialTextureScaleAccuracyIcon("EditorViewport.TexStreamAccMaterialTextureScaleMode");
static FName RequiredTextureResolutionIcon("EditorViewport.RequiredTextureResolutionMode");
static FName LightOverlapIcon("EditorViewport.StationaryLightOverlapMode");
static FName LightmapDensityIcon("EditorViewport.LightmapDensityMode");
static FName ReflectionModeIcon("EditorViewport.ReflectionOverrideMode");
static FName LODColorationIcon("EditorViewport.LODColorationMode");
static FName VisualizeBufferIcon("EditorViewport.VisualizeBufferMode");
static FName CollisionPawnIcon("EditorViewport.CollisionPawn");
static FName CollisionVisibilityIcon("EditorViewport.CollisionVisibility");
switch (PinnedViewport->GetViewportClient()->GetViewMode())
{
case VMI_BrushWireframe:
Icon = WireframeIcon;
break;
case VMI_Wireframe:
Icon = WireframeIcon;
break;
case VMI_Unlit:
Icon = UnlitIcon;
break;
case VMI_Lit:
Icon = LitIcon;
break;
#if RHI_RAYTRACING
// #dxr_todo: UE-72550 use special icons for ray tracing view modes
case VMI_RayTracingDebug:
Icon = LitIcon;
break;
case VMI_PathTracing:
Icon = LitIcon;
break;
#endif
case VMI_Lit_DetailLighting:
Icon = DetailLightingIcon;
break;
case VMI_LightingOnly:
Icon = LightingOnlyIcon;
break;
case VMI_LightComplexity:
Icon = LightComplexityIcon;
break;
case VMI_ShaderComplexity:
Icon = ShaderComplexityIcon;
break;
case VMI_QuadOverdraw:
Icon = QuadOverdrawIcon;
break;
case VMI_ShaderComplexityWithQuadOverdraw:
Icon = ShaderComplexityWithQuadOverdrawIcon;
break;
case VMI_PrimitiveDistanceAccuracy:
Icon = PrimitiveDistanceAccuracyIcon;
break;
case VMI_MeshUVDensityAccuracy:
Icon = MeshUVDensityAccuracyIcon;
break;
case VMI_MaterialTextureScaleAccuracy:
Icon = MaterialTextureScaleAccuracyIcon;
break;
case VMI_RequiredTextureResolution:
Icon = RequiredTextureResolutionIcon;
break;
case VMI_StationaryLightOverlap:
Icon = LightOverlapIcon;
break;
case VMI_LightmapDensity:
Icon = LightmapDensityIcon;
break;
case VMI_ReflectionOverride:
Icon = ReflectionModeIcon;
break;
case VMI_VisualizeBuffer:
Icon = VisualizeBufferIcon;
break;
case VMI_CollisionPawn:
Icon = CollisionPawnIcon;
break;
case VMI_CollisionVisibility:
Icon = CollisionVisibilityIcon;
break;
case VMI_LitLightmapDensity:
break;
case VMI_LODColoration:
Icon = LODColorationIcon;
break;
case VMI_HLODColoration:
Icon = LODColorationIcon;
break;
case VMI_GroupLODColoration:
Icon = LODColorationIcon;
break;
}
}
return FEditorStyle::GetBrush(Icon);
}
void SEditorViewportViewMenu::RegisterMenus() const
{
if (!UToolMenus::Get()->IsMenuRegistered(BaseMenuName))
{
UToolMenu* Menu = UToolMenus::Get()->RegisterMenu(BaseMenuName);
Menu->AddDynamicSection("BaseSection", FNewToolMenuDelegate::CreateLambda([](UToolMenu* InMenu)
{
if (UEditorViewportViewMenuContext* Context = InMenu->FindContext<UEditorViewportViewMenuContext>())
{
Context->EditorViewportViewMenu.Pin()->FillViewMenu(InMenu);
}
}));
}
}
TSharedRef<SWidget> SEditorViewportViewMenu::GenerateViewMenuContent() const
{
RegisterMenus();
UEditorViewportViewMenuContext* ContextObject = NewObject<UEditorViewportViewMenuContext>();
ContextObject->EditorViewportViewMenu = SharedThis(this);
FToolMenuContext MenuContext(Viewport.Pin()->GetCommandList(), MenuExtenders, ContextObject);
return UToolMenus::Get()->GenerateWidget(MenuName, MenuContext);
}
void SEditorViewportViewMenu::FillViewMenu(UToolMenu* Menu) const
{
const FEditorViewportCommands& BaseViewportActions = FEditorViewportCommands::Get();
{
// View modes
{
FToolMenuSection& Section = Menu->AddSection("ViewMode", LOCTEXT("ViewModeHeader", "View Mode"));
{
Section.AddMenuEntry(BaseViewportActions.LitMode, UViewModeUtils::GetViewModeDisplayName(VMI_Lit));
Section.AddMenuEntry(BaseViewportActions.UnlitMode, UViewModeUtils::GetViewModeDisplayName(VMI_Unlit));
Section.AddMenuEntry(BaseViewportActions.WireframeMode, UViewModeUtils::GetViewModeDisplayName(VMI_BrushWireframe));
Section.AddMenuEntry(BaseViewportActions.DetailLightingMode, UViewModeUtils::GetViewModeDisplayName(VMI_Lit_DetailLighting));
Section.AddMenuEntry(BaseViewportActions.LightingOnlyMode, UViewModeUtils::GetViewModeDisplayName(VMI_LightingOnly));
Section.AddMenuEntry(BaseViewportActions.ReflectionOverrideMode, UViewModeUtils::GetViewModeDisplayName(VMI_ReflectionOverride));
Section.AddMenuEntry(BaseViewportActions.CollisionPawn, UViewModeUtils::GetViewModeDisplayName(VMI_CollisionPawn));
Section.AddMenuEntry(BaseViewportActions.CollisionVisibility, UViewModeUtils::GetViewModeDisplayName(VMI_CollisionVisibility));
}
#if RHI_RAYTRACING
if (IsRayTracingEnabled())
{
Section.AddMenuEntry(BaseViewportActions.PathTracingMode, UViewModeUtils::GetViewModeDisplayName(VMI_PathTracing));
}
#endif
// Optimization
{
struct Local
{
static void BuildOptimizationMenu(UToolMenu* Menu, TWeakPtr<SViewportToolBar> InParentToolBar)
{
const FEditorViewportCommands& BaseViewportCommands = FEditorViewportCommands::Get();
UWorld* World = GWorld;
const ERHIFeatureLevel::Type FeatureLevel = (IsInGameThread() && World) ? (ERHIFeatureLevel::Type)World->FeatureLevel : GMaxRHIFeatureLevel;
{
FToolMenuSection& Section = Menu->AddSection("OptimizationViewmodes", LOCTEXT("OptimizationSubMenuHeader", "Optimization Viewmodes"));
if (FeatureLevel == ERHIFeatureLevel::SM5)
{
Section.AddMenuEntry(BaseViewportCommands.LightComplexityMode, UViewModeUtils::GetViewModeDisplayName(VMI_LightComplexity));
if (IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.AllowStaticLighting"))->GetValueOnAnyThread() != 0)
{
Section.AddMenuEntry(BaseViewportCommands.LightmapDensityMode, UViewModeUtils::GetViewModeDisplayName(VMI_LightmapDensity));
}
Section.AddMenuEntry(BaseViewportCommands.StationaryLightOverlapMode, UViewModeUtils::GetViewModeDisplayName(VMI_StationaryLightOverlap));
}
Section.AddMenuEntry(BaseViewportCommands.ShaderComplexityMode, UViewModeUtils::GetViewModeDisplayName(VMI_ShaderComplexity));
if (AllowDebugViewShaderMode(DVSM_ShaderComplexityContainedQuadOverhead, GMaxRHIShaderPlatform, FeatureLevel))
{
Section.AddMenuEntry(BaseViewportCommands.ShaderComplexityWithQuadOverdrawMode, UViewModeUtils::GetViewModeDisplayName(VMI_ShaderComplexityWithQuadOverdraw));
}
if (AllowDebugViewShaderMode(DVSM_QuadComplexity, GMaxRHIShaderPlatform, FeatureLevel))
{
Section.AddMenuEntry(BaseViewportCommands.QuadOverdrawMode, UViewModeUtils::GetViewModeDisplayName(VMI_QuadOverdraw));
}
}
{
FToolMenuSection& Section = Menu->AddSection("TextureStreaming", LOCTEXT("TextureStreamingHeader", "Texture Streaming Accuracy"));
if (AllowDebugViewShaderMode(DVSM_PrimitiveDistanceAccuracy, GMaxRHIShaderPlatform, FeatureLevel) && (!InParentToolBar.IsValid() || InParentToolBar.Pin()->IsViewModeSupported(VMI_PrimitiveDistanceAccuracy)))
{
Section.AddMenuEntry(BaseViewportCommands.TexStreamAccPrimitiveDistanceMode, UViewModeUtils::GetViewModeDisplayName(VMI_PrimitiveDistanceAccuracy));
}
if (AllowDebugViewShaderMode(DVSM_MeshUVDensityAccuracy, GMaxRHIShaderPlatform, FeatureLevel) && (!InParentToolBar.IsValid() || InParentToolBar.Pin()->IsViewModeSupported(VMI_MeshUVDensityAccuracy)))
{
Section.AddMenuEntry(BaseViewportCommands.TexStreamAccMeshUVDensityMode, UViewModeUtils::GetViewModeDisplayName(VMI_MeshUVDensityAccuracy));
}
// TexCoordScale accuracy viewmode requires shaders that are only built in the TextureStreamingBuild, which requires the new metrics to be enabled.
if (AllowDebugViewShaderMode(DVSM_MaterialTextureScaleAccuracy, GMaxRHIShaderPlatform, FeatureLevel) && CVarStreamingUseNewMetrics.GetValueOnAnyThread() != 0 && (!InParentToolBar.IsValid() || InParentToolBar.Pin()->IsViewModeSupported(VMI_MaterialTextureScaleAccuracy)))
{
Section.AddMenuEntry(BaseViewportCommands.TexStreamAccMaterialTextureScaleMode, UViewModeUtils::GetViewModeDisplayName(VMI_MaterialTextureScaleAccuracy));
}
if (AllowDebugViewShaderMode(DVSM_RequiredTextureResolution, GMaxRHIShaderPlatform, FeatureLevel) && (!InParentToolBar.IsValid() || InParentToolBar.Pin()->IsViewModeSupported(VMI_MaterialTextureScaleAccuracy)))
{
Section.AddMenuEntry(BaseViewportCommands.RequiredTextureResolutionMode, UViewModeUtils::GetViewModeDisplayName(VMI_RequiredTextureResolution));
}
}
}
};
Section.AddSubMenu(
"OptimizationSubMenu",
LOCTEXT("OptimizationSubMenu", "Optimization Viewmodes"), LOCTEXT("Optimization_ToolTip", "Select optimization visualizer"),
FNewToolMenuDelegate::CreateStatic(&Local::BuildOptimizationMenu, ParentToolBar),
FUIAction(FExecuteAction(), FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]()
{
const TSharedRef<SEditorViewport> ViewportRef = Viewport.Pin().ToSharedRef();
const TSharedPtr<FEditorViewportClient> ViewportClient = ViewportRef->GetViewportClient();
check(ViewportClient.IsValid());
const EViewModeIndex ViewMode = ViewportClient->GetViewMode();
return (
// Texture Streaming Accuracy
ViewMode == VMI_LightComplexity || ViewMode == VMI_LightmapDensity || ViewMode == VMI_StationaryLightOverlap || ViewMode == VMI_ShaderComplexity || ViewMode == VMI_ShaderComplexityWithQuadOverdraw || ViewMode == VMI_QuadOverdraw
// Texture Streaming Accuracy
|| ViewMode == VMI_PrimitiveDistanceAccuracy || ViewMode == VMI_MeshUVDensityAccuracy || ViewMode == VMI_MaterialTextureScaleAccuracy || ViewMode == VMI_RequiredTextureResolution);
})),
EUserInterfaceActionType::RadioButton,
/* bInOpenSubMenuOnClick = */ false, FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.QuadOverdrawMode"));
}
#if RHI_RAYTRACING
if (IsRayTracingEnabled())
{
struct Local
{
static void BuildRayTracingDebugMenu(FMenuBuilder& Menu, TWeakPtr<SViewportToolBar> InParentToolBar)
{
const FRayTracingDebugVisualizationMenuCommands& RtDebugCommands = FRayTracingDebugVisualizationMenuCommands::Get();
RtDebugCommands.BuildVisualisationSubMenu(Menu);
}
};
Section.AddSubMenu("RayTracingDebugSubMenu", LOCTEXT("RayTracingDebugSubMenu", "Ray Tracing Debug"), LOCTEXT("RayTracing_ToolTip", "Select ray tracing buffer visualization view modes"), FNewMenuDelegate::CreateStatic(&Local::BuildRayTracingDebugMenu, ParentToolBar));
}
#endif
{
struct Local
{
static void BuildLODMenu(UToolMenu* Menu)
{
{
FToolMenuSection& Section = Menu->AddSection("LevelViewportLODColoration", LOCTEXT("LODModesHeader", "Level of Detail Coloration"));
Section.AddMenuEntry(FEditorViewportCommands::Get().LODColorationMode, UViewModeUtils::GetViewModeDisplayName(VMI_LODColoration));
Section.AddMenuEntry(FEditorViewportCommands::Get().HLODColorationMode, UViewModeUtils::GetViewModeDisplayName(VMI_HLODColoration));
}
}
};
Section.AddSubMenu(
"VisualizeGroupedLOD",
LOCTEXT("VisualizeGroupedLODDisplayName", "Level of Detail Coloration"), LOCTEXT("GroupedLODMenu_ToolTip", "Select a mode for LOD Coloration"),
FNewToolMenuDelegate::CreateStatic(&Local::BuildLODMenu),
FUIAction(FExecuteAction(), FCanExecuteAction(),
FIsActionChecked::CreateLambda([this]()
{
const TSharedRef<SEditorViewport> ViewportRef = Viewport.Pin().ToSharedRef();
const TSharedPtr<FEditorViewportClient> ViewportClient = ViewportRef->GetViewportClient();
check(ViewportClient.IsValid());
const EViewModeIndex ViewMode = ViewportClient->GetViewMode();
return (ViewMode == VMI_LODColoration || ViewMode == VMI_HLODColoration);
})),
EUserInterfaceActionType::RadioButton,
/* bInOpenSubMenuOnClick = */ false, FSlateIcon(FEditorStyle::GetStyleSetName(), "EditorViewport.GroupLODColorationMode"));
}
}
// Auto Exposure
{
const FEditorViewportCommands& BaseViewportCommands = FEditorViewportCommands::Get();
TSharedRef<SWidget> FixedEV100Menu = Viewport.Pin()->BuildFixedEV100Menu();
TSharedPtr<FEditorViewportClient> EditorViewPostClient = Viewport.Pin()->GetViewportClient();
const bool bIsLevelEditor = EditorViewPostClient.IsValid() && EditorViewPostClient->IsLevelEditorClient();
FToolMenuSection& Section = Menu->AddSection("Exposure", LOCTEXT("ExposureHeader", "Exposure"));
Section.AddMenuEntry(bIsLevelEditor ? BaseViewportCommands.ToggleInGameExposure : BaseViewportCommands.ToggleAutoExposure);
Section.AddEntry(FToolMenuEntry::InitWidget("FixedEV100", FixedEV100Menu, LOCTEXT("FixedEV100", "EV100")));
}
}
}
#undef LOCTEXT_NAMESPACE