GetRenderTargetTexture() on GameViewport works in editor mode, but returns 0 in standalone

I’m trying to get a native texture pointer to the content currently displayed on screen.

Using 4.8.3 and executing the following code on the render thread:

GEngine->GameViewport->GetGameViewport()->GetRenderTargetTexture().GetReference();

Returns the correct texture pointer when run in the editor, and everything works fine.

However, when I run my project as a standalone or after packaging, it returns a null pointer. I’m guessing the viewports and rendertargets are set up differently in standalone mode compared to regular mode. How can I achieve what I want, so it works in all cases?

Okay, so I managed to get non-null texture pointer, by moving the code to the Draw() method of a custom UGameViewportClient, but the texture I get is not being rendered to when playing as standalone (I get a completely black texture). The exact same code works fine in PIE-mode.

1 Like

So it seems that the viewport in PIE-mode creates a render texture with a format that is different from the one in standalone mode. I get:

  • PF_B8G8R8A8 in PIE-mode
  • PF_A2B10G10R10 in standalone-mode

Can I force the render texture format of standalone mode to be the same format?

Did you get anywhere with this?

I’m trying to enable the AVIWriter::StartCapture during a standalone build. Of course it gets a viewport with a null RenderTarget…

Hey Yu He!

I am working on a similar issue and like you can only get black video out. Did you end up finding a way to convert the Pixel Format?

Information on this stuff is so hard to find >.<

I did in fact solve this! To convert the pixel format, you can sample the backbuffer using a simple pixel shader and draw it on a new render target with the desired size and format. Seems to have close to zero impact on performance.

1 Like

hi Ye Hu, can you give some light on how did you solve this? Thanks alot, i’m having the same issue :frowning:

Hello @Yu He,

Similarly to Madlions, I was wondering if you could shed some more light on how you managed to get the texture from the viewport in standalone mode?

Many thanks!
M

I use RTF_RGB10A2 in PIE mode, works perfectly. Where did you get that it’s PF_B8G8R8A8 in PIE?

Ok, i made it work SOMEHOW.

.h file:


#pragma once

#include "CoreMinimal.h"
#include "UObject/Object.h"
#include "UnrealClient.h"
#include "RQ_GameViewportClient.generated.h"

/**
 * 
 */
UCLASS()
class SCENARIOSYSTEM_API URQ_GameViewportClient : public UGameViewportClient
{
	GENERATED_BODY()

public:
	
	virtual void Draw(FViewport* InViewport, FCanvas* Canvas) override;

	void CopyViewportToRenderTarget(UTextureRenderTarget2D* RenderTarget);

	UPROPERTY()
	UTextureRenderTarget2D* MyRenderTarget;
	
	bool PendingCopyViewportToRenderTarget;


	void CopyTextureRHI(FRenderTarget* MyViewRenderTarget, UTextureRenderTarget2D* DestRenderTarget);
};

and .cpp file:

#include "Core/RQ_GameViewportClient.h"
#include "Engine/TextureRenderTarget2D.h"
#include "Slate/SceneViewport.h"


void URQ_GameViewportClient::Draw(FViewport* InViewport, FCanvas* Canvas)
{
	Super::Draw(Viewport, Canvas);
	
	if (InViewport && PendingCopyViewportToRenderTarget)
	{
		CopyTextureRHI(InViewport, MyRenderTarget);
	}
	
}

void URQ_GameViewportClient::CopyViewportToRenderTarget(UTextureRenderTarget2D* RenderTarget)
{
	MyRenderTarget = RenderTarget;
	PendingCopyViewportToRenderTarget = true;
}

void URQ_GameViewportClient::CopyTextureRHI(FRenderTarget* MyViewRenderTarget, UTextureRenderTarget2D* DestRenderTarget)
{
	

	ENQUEUE_RENDER_COMMAND(CopyToResolveTarget)(
		[MyViewRenderTarget, DestRenderTarget](FRHICommandListImmediate& RHICmdList)
		{
			FTexture2DRHIRef destTexture = DestRenderTarget->GetRenderTargetResource()->GetRenderTargetTexture();
			FResolveParams ResolveParams;
			RHICmdList.CopyToResolveTarget(MyViewRenderTarget->GetRenderTargetTexture(), destTexture, ResolveParams);
		});
	FlushRenderingCommands();
}

This this custom viewoirt client, so don’t forget to tell UE5 to use it in DefaultEngine.ini:

[/Script/Engine.Engine]
GameViewportClientClassName=/Script/ScenarioSystem.RQ_GameViewportClient

RenderTarget2D is using RTF_RGB10A2 pixel format

VinnyBlood’s method can work,but if you just want to get the texture manually somtimes but not every frame,see about this.
lets go in code.
GetGameViewport()->GetRenderTargetTexture will return the member RenderTargetTextureRHI in client,SceneViewport.UseSeparateRenderTarget() decide whether the RenderTargetTextureRHI is valid or not(FSceneViewport::InitDynamicRHI),wo if you want the texture,you gonna to make SceneViewport.bUseSeparateRenderTarget ture.if this flag value set as false,render result will send to the backbuffer directly.And this value setted in construct function with ViewportWidget(SWiewport) member parameter.
and as a violent way you can simply set GameViewportWidgetRef’s construct paramater RenderDirectlyToWindows to false in UGameEngine::CreateGameViewportWidget(),and every thing about this will be same with the editor.
However,you couldnt access to viewport dynamicrhi(just like editor),and you will get a upset down viewport in android.

It may have a runtime method to change the setting so you will not needed to change the engine source code,I dont have enough time to find it out right now.