For reading from a render target on the render thread:
UTextureRenderTarget2D* RT;
TArray<FColor>* OutPixels;
// If you're on the game thread (or any non-render thread) you need this to schedule work for the render thread
ENQUEUE_RENDER_COMMAND(ReadRTCmd)(
[RT, OutPixels](FRHICommandListImmediate& RHICmdList)
{
// If you're already on the render thread, you just need this
FTextureRenderTarget2DResource* RTResource =
static_cast<FTextureRenderTarget2DResource*>(RT->GetRenderTargetResource());
RHICmdList.ReadSurfaceData(
RTResource->GetTextureRHI(),
FIntRect(0, 0, RT->SizeX, RT->SizeY),
*OutPixels,
FReadSurfaceDataFlags());
});
// Call this if you need to wait for the read to finish before continuing work on the game thread.
// It's potentially slow though and if you need it, you're probably fine using the UKismetRendererLibrary functions.
FlushRenderingCommands();