1

I've been trying, but failing to do it with this code

UTextureRenderTarget2D *renderTarget; // In header

void UMyActorComponent::BeginPlay()
{
    Super::BeginPlay();
    texture = UTexture2D::CreateTransient(1, 1);
    FTexture2DMipMap& Mip = texture->PlatformData->Mips[0];
    void* Data = Mip.BulkData.Lock(LOCK_READ_WRITE);
    uint8 red[4] = { 255, 255, 255, 255 };
    FMemory::Memcpy(Data, &red, sizeof(red));
    Mip.BulkData.Unlock();
    texture->UpdateResource();

    renderTarget->UpdateTexture2D(texture, TSF_BGRA8);
}

I at least know for a fact I have the correct handle to the renderTarget, because I've been able to clear the render target. I might be missing something simple any help is appreciated.

J. Rehbein
  • 107
  • 1
  • 9
  • Does anything happen if you call `renderTarget->UpdateResourceImmediate(false);` after `renderTarget->UpdateTexture2D(texture, TSF_BGRA8);`? – Ruzihm Jan 08 '20 at 18:20
  • 1
    @Ruzihm After digging through the source I've found that UpdateTexture2D is wrapped entirely in a #if WITH_EDITOR block which I've read that means it does nothing in your game. You were very close though I noticed the resource wasn't updated at the end of the function, but I guess that doesn't matter anyway. I'll post my solution when I figure it out. – J. Rehbein Jan 09 '20 at 03:24

1 Answers1

1

I found a solution and it seems like its the correct way to do it.

Disclaimer

Using a texture render target might not be the best approach since generally a render target conveys you’re rendering from the gpu to the gpu. And in this case I’m writing data from the cpu to the gpu. So you might run into some unforseen problems down the line if you take this approach. Probably creating a transient texture is the proper way to do this.

Solution

Dynamically initializing the Render Target's Resource

So first you'll need to initialize your UTextureRenderTarget2D to your desired resolution using this function. Put this where it makes sense.

RenderTarget->InitCustomFormat(2, 2, PF_B8G8R8A8, true);

I'm using a 2x2 image with a BGRA8 pixel format and linear color space for this example

Function to update the Render Target

Then you'll want to place this function somewhere accessible in your code

void UpdateTextureRegion(FTexture2DRHIRef TextureRHI, int32 MipIndex, uint32 NumRegions, FUpdateTextureRegion2D Region, uint32 SrcPitch, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8* SrcData)> DataCleanupFunc = [](uint8*) {})
 {
     ENQUEUE_RENDER_COMMAND(UpdateTextureRegionsData)(
         [=](FRHICommandListImmediate& RHICmdList)
         {
             check(TextureRHI.IsValid());
             RHIUpdateTexture2D(
                 TextureRHI,
                 MipIndex,
                 Region,
                 SrcPitch,
                 SrcData
                 + Region.SrcY * SrcPitch
                 + Region.SrcX * SrcBpp
             );
             
             DataCleanupFunc(SrcData);
         });
 }

Updating the Render Target

This code will write a red, green, blue, and white

static uint8 rgbw[4 * 4] = {
                       0,   0,   255, 255,
                       0,   255,   0, 255,
                       255,   0,   0, 255,
                       255, 255, 255, 255

    };
auto region = FUpdateTextureRegion2D(0, 0, 0, 0, 2, 2);
UpdateTextureRegion(RenderTarget, 0, 1, region, 2*4, 4, rgbw);

Attach the Render Target to a plane in the editor and it should hopefully look like this when all is said and done

In game

And with that you should have some functioning code to play with.

J. Rehbein
  • 107
  • 1
  • 9
  • Sorry a quick question, What is the SrcPitch? How is it used within the RHIUpdateTexture2D function? – Massimo Isonni Dec 03 '21 at 08:36
  • 1
    @MassimoIsonni It is the distance between rows of **`SrcData` in bytes**. So if `SrcData` is tightly packed with no gaps between rows and BGRA8 data then its equal to 4 times the length of the rows in `SrcData` – J. Rehbein Dec 03 '21 at 20:52
  • @Rehbein Downvoted, this code can not be run `Cannot convert lvalue of type UTextureRenderTarget2D* to parameter type FTexture2DRHIRef` – Nicholas Jela Dec 19 '22 at 11:35
  • @NicholasJela My bad yeah I think I edited the code one too many times if you figure it out I think you can just edit my answer to what you got working – J. Rehbein Dec 21 '22 at 04:36