TextureRenderTarget2D saved to PNG is much darker

After a ton of digging around I’ve managed to create an UTextureRenderTarget2D from C++ to capture a LDR screenshot in it using ScreenCaptureComponent2D set to “Final Color (LDR with PostProcess)”.

The screenshot looks ok while displayed on a image widget in the game but it’s much darker after saving it to a PNG file. I assume it’s something caused by the gamma correction but I’ve literally tried all combinations of rendertarget texture settings that came to mind to try to make it look ok but without any success.

Theoretically I would have to save it to disk without any gamma correction so that when viewing externally it gets gamma corrected again and it should look ok. Now it looks as it’s being double gamma corrected. But the question is HOW in UE4?

I’m saving the texture to disk exactly as described here:

To create the rendertarget texture from code I do this (in case it helps someone else):

UTextureRenderTarget2D *rtResult = NewObject<UTextureRenderTarget2D>();
rtResult->ClearColor = FLinearColor::Black;
rtResult->InitCustomFormat(width, height, PF_B8G8R8A8, true);

What am I missing?
Any suggestions are welcomed.

Here’s what I see after saving to PNG:

free upload

Here’s what it should like (when taking screenshot from UE4 directly):

image upload no limit

Apparently this got fixed in UE 4.10.4. It seems it was an engine bug. The texture is correctly saved to PNG now. It was applying an extra gamma correction when being saved to disk.

Also, as an extra bit of info. This is how I create the RenderTarget texture from code:

UTextureRenderTarget2D* UCustomBlueprintUtils::CreateRenderTarget2DTexture(int32 width, int32 height, bool   makeHDR)
  {
	UTextureRenderTarget2D *rtResult = NewObject<UTextureRenderTarget2D>();
	if (makeHDR)
		rtResult->InitAutoFormat(width, height);
	else
		rtResult->InitCustomFormat(width, height, PF_B8G8R8A8, false);

	return rtResult;
  }

For scene captures using “Final Color LDR” you just need a non-hdr render target texture. This means that it must be initialized using:

	rtResult->InitCustomFormat(width, height, PF_B8G8R8A8, false);

The last param (“false”) is to not force the texture color buffer from linear to gamma because the texture is already marked as sRGB by default.

Also, I’ve changed the way the texture is saved to disk (although it was now working ok on UE 4.10.4) Instead of using the method from the link posted in the question, I found in the engine code a much better approach using the built-in “FImageUtils” and “FFileHelper” classes as shown in the function below:

bool UCustomBlueprintUtils::SaveRenderTargetToFile(UTextureRenderTarget2D *rt, const FString& fileDestination)
{
	FTextureRenderTargetResource *rtResource = rt->GameThread_GetRenderTargetResource();
	FReadSurfaceDataFlags readPixelFlags(RCM_UNorm);

	TArray<FColor> outBMP;
	outBMP.AddUninitialized(rt->GetSurfaceWidth() * rt->GetSurfaceHeight());
	rtResource->ReadPixels(outBMP, readPixelFlags);

	FIntPoint destSize(rt->GetSurfaceWidth(), rt->GetSurfaceHeight());
	TArray<uint8> CompressedBitmap;
	FImageUtils::CompressImageArray(destSize.X, destSize.Y, outBMP, CompressedBitmap);
	bool imageSavedOk = FFileHelper::SaveArrayToFile(CompressedBitmap, *fileDestination);

	return imageSavedOk;
}

So the problem of saving a render texture to PNG is fixed. :slight_smile:

The only problem that I now have (but this is subject for another question) is that the engine’s “SceneCaptureComponent2D” doesn’t capture the final scene color correctly. It’s much darker than what I see in the viewport. And I’ve seen more people fighting with this issue but no final solution found yet. To be continued in another question… :smiley:

I also have that same issue with capturing correct (not dark) colors with a HDR target. Im on 4.17.2 and hope it is something that already exists as a bug report somewhere?

wait your another answer. very helpful for me. thanks.

Thanks a ton for this additional information, the custom spawn function was what solved out issue, that also resulted in too high contrast / gamma.

Thanks a ton for this additional information, the custom spawn function was what solved out issue, that also resulted in too high contrast / gamma.

I think I solved the image dimming problem, which is really caused by the gamma setting. But it’s worth noting that the gamma setting can be changed, and it’s very convenient.

You can add the following to your code
rtResult->TargetGamma=1;

Or, directly in the UE4 editor, modify the Target Gamma of the Render Target

270055-targetgamma.png

If it helps you, I’ll be happy~

1 Like

Thanks, set TargetGamma = 2.2 will do the work.

2 Likes