Resource->ReadPixels is very slow... faster way?

I have set up a 2DSceneCapture component and using c++, I access the render target and read the pixels, like so:

void MyActor::UpdateBuffer( )
{

TArray<FColor> ColorBuffer;

if (RenderTarget != NULL)
{

	FTextureRenderTarget2DResource* textureResource = (FTextureRenderTarget2DResource*)RenderTarget->Resource;

	unsigned int ReadPixelsTimer = clock();

	if (textureResource->ReadPixels(ColorBuffer))
	{
	}

	long ReadPixelsDuration = clock() - ReadPixelsTimer;
	GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT("ReadPixels run time: %d"), ReadPixelsDuration));
}
}

I notice that my ReadPixels takes ages to complete… So, I would like to know if there is a faster way that I can do this?

What I really want, is to access the camera view data, but as I can’t find a way to do that, I resorted to the RenderTarget method as described here: A new, community-hosted Unreal Engine Wiki - Announcements - Epic Developer Community Forums

I’ve also read this post: Accessing pixel values of Texture2D - Asset Creation - Epic Developer Community Forums but I have no idea how to get MyTexture2D.

Any advice?

Have you ever worked something out? Because I have the same problem, ReadPixels() is just crazy slow makes up for 80% of all the time my entire function uses. There must be some way to get to the raw data quickly?

I tried using ReadPixelsPtr() instead and then copy the array around, but that is just as slow.

Nope. No further. Unfortunately, the support for this engine is not very good so despite my best efforts, I had to give up in the end. Let me know if you figure something out!

Well the only thing I noticed was an absolute massive difference if HDR was activated in the Render Target. That slowed things down a lot.

You could also look into running things asynchronously using Async, but that may not be viable, depending on what you are trying to do.

Otherwise, no, it seems we are stuck with ReadPixels()…

I know this question is getting quite old, but I showed up when I was looking for a solution to the same problem.

I think found a way around this by modifying ReadPixels so it does not block the game thread. I’ve added a description to the wiki (https://wiki.unrealengine.com/Render_Target_Lookup) in case anyone is interested.

1 Like

I also looking for a faster solution than ReadPixels, this is really important for many tasks.

I have not found a faster solution than ReadPixels, but, as I explained in my own post here, you can speed ReadPixels up a lot by disabling HDR on the render target and setting the render target’s resolution to match the active camera’s resolution. Otherwise, the renderer has to re-allocate resources every time it reads from the render target.

Great article, It was actually a launch point for this class in my code. Which I also wrote an article for. Enjoy!

1 Like

Hey Guys. I share my solution.

Did you guys set the “bGPUSharedFlag”?? This value is belonging to “UTextureRenderTarget2D” class.

In my case, when I set this value to “true”, ReadPixels() was faster than before!

This is my code. I sincerely hope it helps.

1 Like

Hey, being way late to the party I just wanted to post this, where I basically brought together everything I learned following the discussion here and on other forums, for my own projects, as I think that it may help others who want to do something similar and may or may not have less experience with UE4. This was the case for me when I read through the discussion here.

In the repository I explain a way to capture images from SceneCapture2D components to disk from scratch, giving above 30 fps even for complex scenes (dependent on your hardware).
I initially framed this towards generating data for machine learning, but of course it is usable for any application.

What file did you change this in?

I have 31 2D scene capture components running. Getting the resource from the rendering thread boost my framerate from 11.3 to 11.7 and reduce RAM usage from 9.2 to 8.1.

FTextureRenderTargetResource* resource;

ENQUEUE_RENDER_COMMAND(GetResource)([this, &resource](FRHICommandListImmediate& CommandList) { resource = TextureTarget->GetRenderTargetResource(); });

static TArray<FColor> colors;

FlushRenderingCommands();

if (resource) resource->ReadPixels(colors);