Hi Connor,
I completely understand. I will mention this with Epic staff, but since the behavior of the editor visibility toggles has always been like this, and since UE has been commonly used for Virtual Production for a while now, I would expect this to have been thoroughly taken into consideration by now. For example, note that the Stage App (docs, course) contains an Outliner-like UI that does include a column for controlling the “Hidden in Game” flag of actors in the scene.
If you choose to tool around it, I believe it should be fairly simple to implement an Editor Utility Widget to show a list of actors along with a toggle for their visibility.
Alternatively, you could extend the Outliner itself and add your own “hidden in game” column to it. If this interests you, you could base your implementation on class FSceneOutlinerGutter, which is the current editor visibility “eye” column, and/or on class FDisplayClusterLightCardOutlinerHiddenInGameColumn, which also controls the “hidden in game” actor property. I tried this myself to validate the idea, and here’s the code I ended up with:
`class FHiddenInGameColumn : public ISceneOutlinerColumn
{
public:
FHiddenInGameColumn (ISceneOutliner& SceneOutliner)
{
WeakOutliner = StaticCastSharedRef(SceneOutliner.AsShared());
}
static FName GetID()
{
static FName ColumnName(“Hidden in Game”);
return ColumnName;
}
virtual FName GetColumnID() override
{
return GetID();
}
virtual SHeaderRow::FColumn::FArguments ConstructHeaderRowColumn() override
{
return SHeaderRow::Column(GetColumnID())
.FixedWidth(24.0f)
.HAlignHeader(HAlign_Left)
.VAlignHeader(VAlign_Center)
.HAlignCell(HAlign_Center)
.VAlignCell(VAlign_Center)
.DefaultTooltip(FText::FromName(GetColumnID()))
.HeaderContentPadding(FMargin(4.0f, 0.0f, 0.0f, 0.0f))
[
SNew(SImage)
.ColorAndOpacity(FSlateColor::UseForeground())
.Image(FAppStyle::Get().GetBrush(“Level.VisibleIcon16x”))
];
}
virtual const TSharedRef ConstructRowWidget(FSceneOutlinerTreeItemRef TreeItem, const STableRow& Row) override
{
if (TreeItem->IsValid() && TreeItem->IsA())
{
TSharedPtr ActorItem = StaticCastSharedRef(TreeItem);
AActor* Actor = ActorItem->Actor.Get();
if (Actor)
{
return SNew(SButton)
.ButtonStyle(FAppStyle::Get(), “NoBorder”) // Optional: No border for cleaner icon look
.ContentPadding(0) // Optional: tighter layout
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.OnClicked_Lambda(
Actor
{
bool bShouldHide = !Actor->IsHidden();
Actor->Modify();
Actor->SetActorHiddenInGame(bShouldHide); // Hidden in Game
Actor->SetIsTemporarilyHiddenInEditor(bShouldHide); // Hidden in Editor Temporarily
Actor->bHiddenEd = bShouldHide; // Hidden in Editor at Startup
return FReply::Handled();
})
[
SNew(SImage)
.Image_Lambda(
Actor
{
return FAppStyle::GetBrush(Actor->IsHidden()
? “Level.NotVisibleIcon16x” // Closed eye
: “Level.VisibleIcon16x”); // Open eye
})
];
}
}
return SNullWidget::NullWidget;
}
private:
TWeakPtr WeakOutliner;
};
void FMyEditorModule::StartupModule()
{
FSceneOutlinerModule& SceneOutlinerModule = FModuleManager::LoadModuleChecked(“SceneOutliner”);
SceneOutlinerModule.RegisterDefaultColumnType(
FSceneOutlinerColumnInfo(ESceneOutlinerColumnVisibility::Visible, 1)
);
}`This worked pretty well, but there was one thing I was not completely happy with: after applying a Level Snapshot, the in-editor visibility toggle of all actors seems to be reset to “visible”. I could not find a callback (besides Tick) I could use to update them. But the runtime visibility gets applied correctly.
Best regards,
Vitor