Quick answer: Use InitCustomFormat(W, H, PF_FloatRGBA, /*bForceLinearGamma=*/true) instead of InitAutoFormat. Or call ResizeTarget(W, H) which preserves the existing format.
A scene capture renders to a UTextureRenderTarget2D for use as a mirror. It looks correct until the window resizes — after which colors are washed out and HDR values clipped. The render target was recreated at the new resolution with the wrong format.
Two Init Methods, Two Behaviors
UTextureRenderTarget2D has multiple init paths:
InitAutoFormat(W, H)— resizes and picks a default format (RTF_RGBA8 sRGB on most platforms). Overrides any custom format you previously set.InitCustomFormat(W, H, Format, bForceLinearGamma)— resizes with the format you specify. Use for HDR, normal maps, depth, or any non-default needs.ResizeTarget(W, H)— resizes without touching the format. Use when only the resolution should change.
Many resize code paths call InitAutoFormat by reflex, silently downgrading HDR RTs to 8-bit sRGB.
The Fix
// Before (wrong if RT was previously HDR):
RenderTarget->InitAutoFormat(NewWidth, NewHeight);
// After:
RenderTarget->InitCustomFormat(NewWidth, NewHeight, PF_FloatRGBA, true);
RenderTarget->UpdateResourceImmediate(true);
PF_FloatRGBA is 16-bit half-float per channel — 64 bits per pixel. bForceLinearGamma = true avoids gamma encoding so HDR values pass through. UpdateResourceImmediate commits the change on the rendering thread without waiting for the next frame.
Alternative: Preserve Existing Format
RenderTarget->ResizeTarget(NewWidth, NewHeight);
Simpler and safer. Use whenever the goal is purely a resolution change — ResizeTarget keeps whatever format you originally created the RT with.
Common Format Choices
PF_B8G8R8A8+ sRGB — standard low-bit color. 32 bpp.PF_FloatRGBA(RTF_RGBA16f) — HDR, 64 bpp.PF_R32_FLOAT— single channel float, e.g., depth or shadow.PF_R16G16B16A16— integer HDR, 64 bpp.
For real-time HDR with bloom/tonemapping, FloatRGBA is the typical choice; for normal map captures, use a linear 8/8 with R8G8 packing.
UpdateResourceImmediate vs UpdateResource
The standard UpdateResource defers the underlying resource creation to the next render frame. If you read from the RT in the same frame as the resize, you may sample undefined data. UpdateResourceImmediate blocks until the resource is ready — safer for runtime resize/use in the same tick.
Verifying
Capture the RT before and after resize. Sample a pixel that should hold an HDR value (e.g., 5.0 red). Before fix: clamped to 1.0 after resize. After fix: still 5.0. Use the Output Log r.SceneRenderTargetResizeMethod 2 to debug RT lifetimes during resize sequences.
“InitAutoFormat is convenient and wrong for anything non-default. Either be explicit with InitCustomFormat or use ResizeTarget to keep format intact.”
For HDR render targets, write a helper EnsureHDR(RT, W, H) that always calls InitCustomFormat with the right flags. Centralizes the choice.