How can I copy Render target to UTexture2D ?

Hi,
Everything is in the title, how can I copy data from UTextureRendertarget to UTexture2D.
I tried this code :


UTexture2D* texsample = RenderTarget->ConstructTexture2D(this, "TextureSample", EObjectFlags::RF_NoFlags, CTF_DeferCompression);

But pixels from texsample are all black.

Do you need to create a UTexture2D at runtime?

Because if you need it at runtime, that’s not the way to go. Instead read the pixels from the RenderTarget using the GameThread_GetRenderTargetResource and ReadPixels functions. Once you have a TArray<FColor> you can create a UTexture2DDynamic which is the correct way to create textures at runtime.

Sorry, for reviving an old thread, but I’ve been seeing this same explanation all day, but they all leave one important bit out: how to actually copy the pixels to the UTexture2D/UTexture2DDynamic. The constructors for them do not take a TArray<FColor>. Nor do any of their member functions. Below is the function I’m trying to implement, but I don’t know what to fill in in place of the comment.

UTexture2D* ACameraLens::CapturePhoto()
{
    if (SceneCaptureComponent == nullptr || SceneCaptureComponent->TextureTarget == nullptr) {return nullptr;}
    SceneCaptureComponent->CaptureScene();

    FName TextureName = *FDateTime::Now().ToString();
    UTexture2D* Photo = UTexture2D::CreateTransient(
        SceneCaptureComponent->TextureTarget->SizeX,
        SceneCaptureComponent->TextureTarget->SizeY,
        SceneCaptureComponent->TextureTarget->GetFormat(),
        TextureName);

    TArray<FColor> Pixels;
    SceneCaptureComponent->TextureTarget->GetRenderTargetResource()->ReadPixels(Pixels);
    
    // Now what??

    return Photo;
}

Hi BadScientist89,

You don’t need to copy it manually, check out “UpdateTexture2D”:

Unfortunately, that does not seem to work for me. Perhaps because the RenderTarget is not square. It’s the same as the screen resolution. The Photo texture remains a blank white texture.

EDIT: It doesn’t work with the screen resolution set to 1080x1080 either, so I’m not sure what the issue is.

here’s an extract from some live code of mine:

renderTarget->UpdateTexture2D(texture2d,TSF_RGBA16F,CTF_Compress|CTF_AllowMips|CTF_SRGB,nullptr);

If you do need to copy the pixel data, you can write to it like (just replace the Memset with a Memcopy of the rendertarget pixels):

uint8* TextureData=tex->Source.LockMip(0);
FMemory::Memset(TextureData,clearCol,res*res*tex->Source.GetBytesPerPixel());
tex->Source.UnlockMip(0);

Thanks, RecourseDesign!

But for now, I’ve just decided to create a new TextureRenderTarget2D for each image capture and then display them to the player with a dynamic material instance on the image widget. I’m not sure what the difference in overhead is between Texture2D and TextureRenderTarget2D, but if I ever end up needing to convert again, I’ll keep your solution in mind!

[video-to-gif output image]

1 Like