Image Alt


UE4 Plugin for Scene Capture rendering to separate window

Unreal engine is a really powerful Engine, but when you try to work with custom rendering, multi-window, or your own shaders and GPU draw calls everything becomes more complicated.

The main reason for over-complication is the custom-made and HUGE UE4 rendering pipeline. Essentially UE4 made something called a “slate framework” as its own GUI, which works through 3D GPU acceleration but is meant for both 2D and 3D Graphics. I won’t say custom rendering is really hard in UE4, but a huge amount of rendering interfaces, modules, and dependencies makes it more complicated.

Today I want to describe and share with you the plugin code for MultiWindow ScreenCapture Rendering; I’ve had a challenge with building in custom rendering and custom window creation in the past and now I want to share my knowledge.

We made a small plugin which is focused only on rendering a custom SceneRenderingComponent texture to a Custom Window which works during editing and playing in UE4 Editor.

Essentially this is an Editor plugin which creates a new button in Editor UI, and when you click the Play Scene button opens a new custom window and renders a ScreenCapture texture from the scene to this window.

Alright, lets take a look into the code and go through the logic step by step.

> The plugin is called PlayScene and logic execution starts in PlayScene.cpp

[code language=”cpp”]
void FPlaySceneModule::StartupModule()
// Initialize play button ui style

// Register play capture commands
PluginCommands = MakeShareable(new FUICommandList);

// Add play capture button command
FExecuteAction::CreateRaw(this, &FPlaySceneModule::PluginButtonClicked),

FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");

// Add play scene button to editor
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender);
ToolbarExtender->AddToolBarExtension("Settings", EExtensionHook::After, PluginCommands, FToolBarExtensionDelegate::CreateRaw(this, &FPlaySceneModule::AddToolbarExtension));


In StartupModule() we execute logic for Editor PlayScene button styles, register UI commands and all handlers

> When we click PlayScene Button it executes the function PluginButtonClicked()

[code language=”cpp”]
void FPlaySceneModule::PluginButtonClicked()
// Init layCapture Window

And it creates a window and starts rendering, let’s move to file PlaySceneSlate.cpp

> Here is how we create the window and assign a viewport

[code language=”cpp”]
: PlaySceneWindowWidth(1280)
, PlaySceneWindowHeight(720)
// Create SWindow
PlaySceneWindow = SNew(SWindow)
.ScreenPosition(FVector2D(0, 0))
.ClientSize(FVector2D(PlaySceneWindowWidth, PlaySceneWindowHeight))


// Assign window events delegator
InDelegate.BindRaw(this, &FPlaySceneSlate::OnWindowClosed);

// Create and assign viewport to window
PlaySceneViewport = SNew(SPlaySceneViewport);

> In our custom Viewport we need to create Viewport Client, Scene Viewport and SetViewportInterface to Slate Viewport

[code language=”cpp”]
void SPlaySceneViewport::Construct(const FArguments& InArgs)
// Create Viewport Widget
Viewport = SNew(SViewport)

// Create Viewport Client
PlaySceneViewportClient = MakeShareable(new FPlaySceneViewportClient());

// Create Scene Viewport
SceneViewport = MakeShareable(new FSceneViewport(PlaySceneViewportClient.Get(), Viewport));

// Assign SceneViewport to Viewport widget. It needed for rendering

// Assing Viewport widget for our custom PlayScene Viewport

> And the last step is Draw function inside FPlaySceneViewportClient, which is executed each frame and issues the draw call for our Texture from SceneCaptureComponent

[code language=”cpp”]
void FPlaySceneViewportClient::Draw(FViewport * Viewport, FCanvas * Canvas)
// Clear entire canvas

// Draw SceneCaptureComponent texture to entire canvas
auto TextRenderTarget2D = IPlayScene::Get().GetTextureRenderTarget2D();
if (TextRenderTarget2D.IsValid() && TextRenderTarget2D->Resource != nullptr)
FCanvasTileItem TileItem(FVector2D(0, 0), TextRenderTarget2D->Resource,
FVector2D(Viewport->GetRenderTargetTexture()->GetSizeX(), Viewport->GetRenderTargetTexture()->GetSizeY()),
TileItem.BlendMode = ESimpleElementBlendMode::SE_BLEND_Opaque;

Full code with the example can be found at GitHub

%d bloggers like this: