Files
UnrealEngine/Engine/Plugins/Editor/EngineAssetDefinitions/Source/Private/AssetDefinition_StaticMesh.cpp
2025-05-18 13:04:45 +08:00

560 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AssetDefinition_StaticMesh.h"
#include "Algo/Accumulate.h"
#include "EditorSupportDelegates.h"
#include "Engine/StaticMeshSourceData.h"
#include "StaticMeshEditorModule.h"
#include "FbxMeshUtils.h"
#include "Misc/MessageDialog.h"
#include "StaticMeshCompiler.h"
#include "ThumbnailRendering/SceneThumbnailInfo.h"
#include "ToolMenu.h"
#include "ToolMenus.h"
#include "ContentBrowserMenuContexts.h"
#include "ToolMenuSection.h"
#define LOCTEXT_NAMESPACE "UAssetDefinition_StaticMesh"
UThumbnailInfo* UAssetDefinition_StaticMesh::LoadThumbnailInfo(const FAssetData& InAssetData) const
{
return UE::Editor::FindOrCreateThumbnailInfo(InAssetData.GetAsset(), USceneThumbnailInfo::StaticClass());
}
FAssetOpenSupport UAssetDefinition_StaticMesh::GetAssetOpenSupport(const FAssetOpenSupportArgs& OpenSupportArgs) const
{
return FAssetOpenSupport(OpenSupportArgs.OpenMethod,OpenSupportArgs.OpenMethod == EAssetOpenMethod::Edit || OpenSupportArgs.OpenMethod == EAssetOpenMethod::View);
}
EAssetCommandResult UAssetDefinition_StaticMesh::OpenAssets(const FAssetOpenArgs& OpenArgs) const
{
IStaticMeshEditorModule* StaticMeshEditorModule = &FModuleManager::LoadModuleChecked<IStaticMeshEditorModule>( "StaticMeshEditor" );
for (UStaticMesh* Mesh : OpenArgs.LoadObjects<UStaticMesh>())
{
StaticMeshEditorModule->CreateStaticMeshEditor(OpenArgs.GetToolkitMode(), OpenArgs.ToolkitHost, Mesh);
}
return EAssetCommandResult::Handled;
}
// Menu Extensions
//--------------------------------------------------------------------
namespace MenuExtension_StaticMesh
{
// When copying and pasting LOD data between meshes, we don't actually put the data onto the clipboard it's just
// data stored here and referenced when executing paste.
static TWeakObjectPtr<UStaticMesh> LODCopyMesh;
static TAutoConsoleVariable<int32> CVarEnableSaveGeneratedLODsInPackage(
TEXT("r.StaticMesh.EnableSaveGeneratedLODsInPackage"),
0,
TEXT("Enables saving generated LODs in the Package.\n") \
TEXT("0 - Do not save (and hide this menu option) [default].\n") \
TEXT("1 - Enable this option and save the LODs in the Package.\n"),
ECVF_Default
);
static void ExecuteSaveGeneratedLODsInPackage(const FToolMenuContext& InContext)
{
if (const UContentBrowserAssetContextMenuContext* CBContext = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext))
{
for (UStaticMesh* StaticMesh : CBContext->LoadSelectedObjects<UStaticMesh>())
{
StaticMesh->GenerateLodsInPackage();
}
}
}
static void ExecuteRemoveVertexColors(const FToolMenuContext& InContext)
{
const FText WarningMessage = LOCTEXT("Warning_RemoveVertexColors", "Are you sure you want to remove vertex colors from all selected meshes? There is no undo available.");
if (FMessageDialog::Open(EAppMsgType::YesNo, WarningMessage) == EAppReturnType::Yes)
{
FScopedSlowTask SlowTask(1.0f, LOCTEXT("RemovingVertexColors", "Removing Vertex Colors"));
if (const UContentBrowserAssetContextMenuContext* CBContext = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext))
{
for (UStaticMesh* StaticMesh : CBContext->LoadSelectedObjects<UStaticMesh>())
{
StaticMesh->RemoveVertexColors();
}
}
}
}
// Nanite Section
//=================================================================
const static FName NAME_NaniteEnabled("NaniteEnabled");
static bool IsNaniteEnabled(const FAssetData& StaticMeshAsset)
{
bool bNaniteEnabled = false;
return StaticMeshAsset.GetTagValue<bool>(NAME_NaniteEnabled, bNaniteEnabled) && bNaniteEnabled;
}
void ModifyNaniteEnable(const TArray<UStaticMesh*>& Objects, bool bNaniteEnable)
{
TArray<UStaticMesh*> Meshes;
Meshes.Reserve(Objects.Num());
for (UStaticMesh* Mesh: Objects)
{
if (Mesh && Mesh->NaniteSettings.bEnabled != bNaniteEnable)
{
Meshes.Add(Mesh);
}
}
FStaticMeshCompilingManager::FFinishCompilationOptions FinishCompilationOptions;
FinishCompilationOptions.bIncludeDependentMeshes = true;
FStaticMeshCompilingManager::Get().FinishCompilation(Meshes, FinishCompilationOptions);
for (UStaticMesh* Mesh : Meshes)
{
Mesh->NaniteSettings.bEnabled = bNaniteEnable;
}
UStaticMesh::BatchBuild(Meshes);
for (UStaticMesh* Mesh : Meshes)
{
Mesh->MarkPackageDirty();
Mesh->OnMeshChanged.Broadcast();
}
}
void ExecuteNaniteEnable(const FToolMenuContext& InContext)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext);
TArray<UStaticMesh*> RegularMeshes = Context->LoadSelectedObjectsIf<UStaticMesh>([](const FAssetData& AssetData) {
return !IsNaniteEnabled(AssetData);
});
ModifyNaniteEnable(RegularMeshes, true);
}
void ExecuteNaniteDisable(const FToolMenuContext& InContext)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext);
TArray<UStaticMesh*> NaniteMeshes = Context->LoadSelectedObjectsIf<UStaticMesh>([](const FAssetData& AssetData) {
return IsNaniteEnabled(AssetData);
});
ModifyNaniteEnable(NaniteMeshes, false);
}
static void GetNaniteMenu(UToolMenu* Menu)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu);
FToolMenuSection& Section = Menu->FindOrAddSection("NaniteActions");
{
const TAttribute<FText> Label = LOCTEXT("StaticMesh_NaniteToggle", "Nanite");
const TAttribute<FText> ToolTip = LOCTEXT("StaticMesh_NaniteToggleTooltip", "Toggle Nanite support on the selected meshes.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateLambda([](const FToolMenuContext& InContext)
{
if (const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext))
{
const bool bContainsTrue = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return IsNaniteEnabled(InAsset); });
const bool bContainsFalse = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return !IsNaniteEnabled(InAsset); });
if ((bContainsTrue && bContainsFalse) || bContainsTrue)
{
ExecuteNaniteDisable(InContext);
}
else
{
ExecuteNaniteEnable(InContext);
}
}
});
UIAction.GetActionCheckState = FToolMenuGetActionCheckState::CreateLambda([](const FToolMenuContext& InContext)
{
if (const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext))
{
const bool bContainsTrue = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return IsNaniteEnabled(InAsset); });
const bool bContainsFalse = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return !IsNaniteEnabled(InAsset); });
return bContainsTrue && bContainsFalse ? ECheckBoxState::Undetermined : (bContainsTrue ? ECheckBoxState::Checked : ECheckBoxState::Unchecked);
}
return ECheckBoxState::Undetermined;
});
Section.AddMenuEntry("StaticMesh_NaniteToggle", Label, ToolTip, Icon, UIAction, EUserInterfaceActionType::ToggleButton);
}
Section.AddSeparator("Nanite_EnableDisableOptions");
const int32 NaniteMeshes = Algo::Accumulate(Context->SelectedAssets, 0, [](int32 Value, const FAssetData& StaticMeshAsset)
{
bool bNaniteEnabled = false;
return (StaticMeshAsset.GetTagValue<bool>(NAME_NaniteEnabled, bNaniteEnabled) && bNaniteEnabled) ? Value + 1 : Value;
});
{
const int32 RegularMeshes = Context->SelectedAssets.Num() - NaniteMeshes;
const TAttribute<FText> Label = FText::Format(LOCTEXT("StaticMesh_NaniteEnableAll", "Enable Nanite ({0} Meshes)"), RegularMeshes);
const TAttribute<FText> ToolTip = LOCTEXT("StaticMesh_NaniteEnableAllTooltip", "Enables support for Nanite on the selected meshes.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteNaniteEnable);
UIAction.CanExecuteAction.BindLambda([RegularMeshes](const FToolMenuContext&) { return RegularMeshes > 0; });
Section.AddMenuEntry("StaticMesh_EnableNanite", Label, ToolTip, Icon, UIAction);
}
{
const TAttribute<FText> Label = FText::Format(LOCTEXT("StaticMesh_NaniteDisableAll", "Disable Nanite ({0} Meshes)"), NaniteMeshes);
const TAttribute<FText> ToolTip = LOCTEXT("StaticMesh_NaniteDisableAllTooltip", "Disables support for Nanite on the selected meshes.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteNaniteDisable);
UIAction.CanExecuteAction.BindLambda([NaniteMeshes](const FToolMenuContext&) { return NaniteMeshes > 0; });
Section.AddMenuEntry("StaticMesh_DisableNanite", Label, ToolTip, Icon, UIAction);
}
}
// LOD Section
//=================================================================
static void ExecuteImportMeshLOD(const FToolMenuContext&, FAssetData StaticMeshAsset, int32 LOD, bool bReimportWithNewFile)
{
if (UStaticMesh* Mesh = Cast<UStaticMesh>(StaticMeshAsset.GetAsset()))
{
FbxMeshUtils::ImportMeshLODDialog(Mesh, LOD, true, bReimportWithNewFile);
}
}
static void ExecuteImportHiResMesh(const FToolMenuContext& InContext)
{
if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset<UStaticMesh>(InContext))
{
if (FbxMeshUtils::ImportStaticMeshHiResSourceModelDialog(StaticMesh))
{
FEditorDelegates::RefreshEditor.Broadcast();
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
}
}
}
static void ExecuteReimportHiResMeshWithNewFile(const FToolMenuContext& InContext)
{
if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset<UStaticMesh>(InContext))
{
StaticMesh->GetHiResSourceModel().SourceImportFilename = FString();
if (FbxMeshUtils::ImportStaticMeshHiResSourceModelDialog(StaticMesh))
{
FEditorDelegates::RefreshEditor.Broadcast();
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
}
}
}
static void ExecuteRemoveHiResMesh(const FToolMenuContext& InContext)
{
if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset<UStaticMesh>(InContext))
{
if (FbxMeshUtils::RemoveStaticMeshHiRes(StaticMesh))
{
FEditorDelegates::RefreshEditor.Broadcast();
FEditorSupportDelegates::RedrawAllViewports.Broadcast();
}
}
}
const static FName NAME_HasHiResMesh("HasHiResMesh");
static TOptional<bool> HasHiResMesh(const FAssetData& StaticMeshAsset)
{
bool bHasHiResMesh = false;
if (StaticMeshAsset.GetTagValue<bool>(NAME_HasHiResMesh, bHasHiResMesh))
{
return bHasHiResMesh;
}
return TOptional<bool>();
}
static void GetImportHiResMenu(UToolMenu* Menu)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu);
check(Context->SelectedAssets.Num() == 1);
const FAssetData& StaticMeshAsset = Context->SelectedAssets[0];
FToolMenuSection& Section = Menu->FindOrAddSection("HighResMeshActions");
const TOptional<bool> bHasHighResMesh = HasHiResMesh(StaticMeshAsset);
// Import / Reimport
{
if (!bHasHighResMesh.Get(false))
{
const TAttribute<FText> Label = LOCTEXT("Import_HighRes", "Import High Res...");
const TAttribute<FText> ToolTip = LOCTEXT("Import_HighResTip", "Adds a high resolution version of the mesh. Used instead of LOD0 by systems that can benefit from more detailed geometry (Nanite, modeling, etc.).");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteImportHiResMesh);
Section.AddMenuEntry("Import_HighRes", Label, ToolTip, Icon, UIAction);
}
else
{
{
const TAttribute<FText> Label = LOCTEXT("Reimport_HighRes", "Reimport High Res");
const TAttribute<FText> ToolTip = LOCTEXT("Reimport_HighRes_Tip", "Reimport over existing the existing high res mesh.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteImportHiResMesh);
Section.AddMenuEntry("Reimport_HighRes", Label, ToolTip, Icon, UIAction);
}
{
const TAttribute<FText> Label = LOCTEXT("Reimport_HighRes_WithNewFile", "Reimport High Res with new file...");
const TAttribute<FText> ToolTip = LOCTEXT("Reimport_HighRes_WithNewFileTip", "Reimport the high resolution version of the mesh with a new file.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteReimportHiResMeshWithNewFile);
Section.AddMenuEntry("Reimport_HighRes_WithNewFile", Label, ToolTip, Icon, UIAction);
}
}
}
// Remove
{
const TAttribute<FText> Label = LOCTEXT("Remove_HighRes", "Remove High Res");
const TAttribute<FText> ToolTip = LOCTEXT("Remove_HighRes_Tip", "Remove the high res version of the mesh");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteRemoveHiResMesh);
UIAction.CanExecuteAction = FToolMenuCanExecuteAction::CreateLambda([bHasHighResMesh](const FToolMenuContext& Context) { return bHasHighResMesh.Get(true); });
Section.AddMenuEntry("Remove_HighRes", Label, ToolTip, Icon, UIAction);
}
}
static void ExecuteCopyLODSettings(const FToolMenuContext& InContext)
{
if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset<UStaticMesh>(InContext))
{
LODCopyMesh = StaticMesh;
}
}
static void ExecutePasteLODSettings(const FToolMenuContext& InContext)
{
if (!LODCopyMesh.IsValid())
{
return;
}
// Retrieve LOD settings from source mesh
struct FLODSettings
{
FMeshReductionSettings ReductionSettings;
float ScreenSize;
};
TArray<FLODSettings> LODSettings;
LODSettings.AddZeroed(LODCopyMesh->GetNumSourceModels());
for (int32 i = 0; i < LODCopyMesh->GetNumSourceModels(); i++)
{
LODSettings[i].ReductionSettings = LODCopyMesh->GetSourceModel(i).ReductionSettings;
LODSettings[i].ScreenSize = LODCopyMesh->GetSourceModel(i).ScreenSize.Default;
}
const bool bAutoComputeLODScreenSize = LODCopyMesh->bAutoComputeLODScreenSize;
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext);
// Copy LOD settings over to selected objects in content browser (meshes)
for (UStaticMesh* Mesh : Context->LoadSelectedObjects<UStaticMesh>())
{
const int32 LODCount = LODSettings.Num();
Mesh->SetNumSourceModels(LODCount);
for (int32 i = 0; i < LODCount; i++)
{
FStaticMeshSourceModel& SrcModel = Mesh->GetSourceModel(i);
SrcModel.ReductionSettings = LODSettings[i].ReductionSettings;
SrcModel.ScreenSize.Default = LODSettings[i].ScreenSize;
}
Mesh->bAutoComputeLODScreenSize = bAutoComputeLODScreenSize;
Mesh->PostEditChange();
Mesh->MarkPackageDirty();
}
}
static bool CanPasteLODSettings(const FToolMenuContext& InContext)
{
return LODCopyMesh.IsValid();
}
const static FName NAME_LODs("LODs");
static int32 GetNumberOfLODs(const FAssetData& StaticMeshAsset)
{
int32 NumberOfLODs = 0;
return StaticMeshAsset.GetTagValue<int32>(NAME_LODs, NumberOfLODs) ? NumberOfLODs : 0;
}
static void GetImportLODMenu(UToolMenu* Menu, bool bReimportWithNewFile)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu);
check(Context->SelectedAssets.Num() == 1);
FToolMenuSection& Section = Menu->FindOrAddSection("ImportLODMenu");
const FAssetData& StaticMeshAsset = Context->SelectedAssets[0];
//Add 1 so we can Add LOD when we are not in "Reimport With New File" submenu
const int32 OriginalLodCount = GetNumberOfLODs(StaticMeshAsset);
const int32 LodCount = OriginalLodCount+ (bReimportWithNewFile ? 0 : 1);
for (int32 LOD = 1; LOD < LodCount; ++LOD)
{
FText Label = FText::Format(LOCTEXT("Reimport LOD (number)", "Reimport LOD {0}"), LOD);
FText ToolTip = LOCTEXT("ReimportTip", "Reimport over existing LOD");
if (LOD == OriginalLodCount)
{
Label = FText::Format(LOCTEXT("Add LOD (number)", "Add LOD {0}"), LOD);
ToolTip = LOCTEXT("NewImportTip", "Import new LOD");
}
{
const FSlateIcon Icon = FSlateIcon();
const FToolMenuExecuteAction UIAction = FToolMenuExecuteAction::CreateStatic(&ExecuteImportMeshLOD, StaticMeshAsset, LOD, bReimportWithNewFile);
Section.AddMenuEntry(*FString::Printf(TEXT("LOD_%d"), LOD), Label, ToolTip, Icon, UIAction);
}
}
}
static void GetLODMenu(UToolMenu* Menu)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu);
FToolMenuSection& Section = Menu->FindOrAddSection("LODActions");
if (Context->SelectedAssets.Num() == 1)
{
constexpr bool bReimportWithNewFile = true;
Section.AddSubMenu(
"ImportLODsMenu",
NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLOD", "Import LOD"),
NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLODtooltip", "Imports meshes into the LODs"),
FNewToolMenuDelegate::CreateStatic(&GetImportLODMenu, !bReimportWithNewFile)
);
Section.AddSubMenu(
"ReimportLODsWithNewFileMenu",
NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLODWithNewFile", "Reimport LOD With New File"),
NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLODWithNewFiletooltip", "Reimports meshes LODs with new file."),
FNewToolMenuDelegate::CreateStatic(&GetImportLODMenu, bReimportWithNewFile)
);
}
Section.AddSeparator("CopyPaste");
{
const TAttribute<FText> Label = LOCTEXT("StaticMesh_CopyLOD", "Copy LOD");
const TAttribute<FText> ToolTip = LOCTEXT("StaticMesh_CopyLODTooltip", "Copies the LOD settings from the selected mesh.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteCopyLODSettings);
UIAction.CanExecuteAction.BindLambda([](const FToolMenuContext& Context) { return UContentBrowserAssetContextMenuContext::GetNumAssetsSelected(Context) == 1; });
Section.AddMenuEntry("StaticMesh_CopyLOD", Label, ToolTip, Icon, UIAction);
}
{
FText Label = FText(LOCTEXT("StaticMesh_PasteLOD", "Paste LOD"));
if (LODCopyMesh.IsValid())
{
Label = FText::Format(LOCTEXT("StaticMesh_PasteLODWithName", "Paste LOD from {0}"), FText::FromString(LODCopyMesh->GetName()));
}
const TAttribute<FText> ToolTip = LOCTEXT("StaticMesh_PasteLODToltip", "Pastes LOD settings to the selected mesh(es).");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecutePasteLODSettings);
UIAction.CanExecuteAction = FToolMenuCanExecuteAction::CreateStatic(&CanPasteLODSettings);
Section.AddMenuEntry("StaticMesh_PasteLOD", Label, ToolTip, Icon, UIAction);
}
if (Context->SelectedAssets.Num() == 1)
{
Section.AddSeparator("HighRes");
Section.AddSubMenu(
"ImportHighResMenu",
NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_HiRes", "High Res"),
NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_HiRestooltip", "High resolution version of the mesh. Used instead of LOD0 by systems that can benefit from more detailed geometry (Nanite, modeling, etc.)"),
FNewToolMenuDelegate::CreateStatic(&GetImportHiResMenu)
);
}
}
static FDelayedAutoRegisterHelper DelayedAutoRegister(EDelayedRegisterRunPhase::EndOfEngineInit, []{
UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateLambda([]()
{
FToolMenuOwnerScoped OwnerScoped(UE_MODULE_NAME);
UToolMenu* Menu = UE::ContentBrowser::ExtendToolMenu_AssetContextMenu(UStaticMesh::StaticClass());
FToolMenuSection& Section = Menu->FindOrAddSection("GetAssetActions");
Section.AddDynamicEntry(NAME_None, FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection)
{
const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InSection);
if (Context && Context->bCanBeModified)
{
if (CVarEnableSaveGeneratedLODsInPackage.GetValueOnGameThread() != 0)
{
const TAttribute<FText> Label = LOCTEXT("ObjectContext_SaveGeneratedLODsInPackage", "Save Generated LODs");
const TAttribute<FText> ToolTip = LOCTEXT("ObjectContext_SaveGeneratedLODsInPackageTooltip", "Run the mesh reduce and save the generated LODs as part of the package.");
const FSlateIcon Icon = FSlateIcon();
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteSaveGeneratedLODsInPackage);
InSection.AddMenuEntry("ObjectContext_SaveGeneratedLODsInPackage", Label, ToolTip, Icon, UIAction);
}
{
const TAttribute<FText> Label = LOCTEXT("ObjectContext_ClearVertexColors", "Remove Vertex Colors");
const TAttribute<FText> ToolTip = LOCTEXT("ObjectContext_ClearVertexColorsTooltip", "Removes vertex colors from all LODS in all selected meshes.");
const FSlateIcon Icon = FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.RemoveVertexColors");
FToolUIAction UIAction;
UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteRemoveVertexColors);
InSection.AddMenuEntry("ObjectContext_ClearVertexColors", Label, ToolTip, Icon, UIAction);
}
{
InSection.AddSubMenu(
"StaticMesh_NaniteMenu",
LOCTEXT("StaticMesh_NaniteMenu", "Nanite"),
LOCTEXT("StaticMesh_NaniteTooltip", "Nanite Options and Tools"),
FNewToolMenuDelegate::CreateStatic(&GetNaniteMenu),
false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Adjust")
);
}
{
InSection.AddSubMenu(
"StaticMesh_LODMenu",
LOCTEXT("StaticMesh_LODMenu", "Level Of Detail"),
LOCTEXT("StaticMesh_LODTooltip", "LOD Options and Tools"),
FNewToolMenuDelegate::CreateStatic(&GetLODMenu),
false,
FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.LOD")
);
}
}
}));
}));
});
}
#undef LOCTEXT_NAMESPACE