reckfellENGINE

HDR, exposure and preserving highlights

Separate HDR, sRGB and exposure; save EXR without losing bright values.

On this page

HDR rendering keeps light values above 1 during intermediate calculations. This preserves differences between bright surfaces before exposure and tone mapping. It does not mean unlimited precision, an HDR monitor, or automatically realistic graphics.

Separate three operations

OperationPurposeWhat it does not do
sRGB → linearDecode color values before lighting calculations. sRGB 0.5 is approximately linear 0.214.Compress bright highlights into a display range.
Exposure and tone mappingAdjust scene brightness and map scene values to the intended output.Restore details already clipped in a texture or image.
HDR display outputDeliver an appropriate signal to a supported display through a supported OS/backend configuration.Turn an ordinary PNG or an 8-bit buffer into source HDR data.

A linear → sRGB transfer alone is not tone mapping: an input of 4 still produces a value above 1. Neither step adds missing surface detail, correct normals, shadows or reflections.

Configure a 3D scene

  1. Add a WorldEnvironment Entity and assign an Environment resource. Check whether the active Camera3D has its own Environment override before editing a resource that may not affect the view.
  2. Choose a tone mapper in the Environment's Tonemap section. Compare curves on the same camera and scene; a different curve changes highlight contrast and color, not just brightness.
  3. Set a stable exposure while adjusting lights. In code, Environment.TonemapExposure is a multiplier, not an EV stop count. A multiplier of 2 doubles its input; 0.5 halves it.
  4. If camera attributes are assigned, check their exposure multiplier and whether auto exposure is enabled. Disable automatic adaptation when comparing two lighting settings; otherwise the camera may compensate for the change.
  5. Check the frame at the intended renderer and output configuration. Renderer effects and HDR-display support are separate capabilities; do not assume the same result on every device.

See Environment and post-processing for the scene controls and HDR output for display output. There is no general “enable both sRGB switches” step in this workflow.

Keep color textures separate from data textures

Albedo/base-color textures normally contain encoded color. In a custom spatial shader, mark the corresponding color sampler with source_color so it is interpreted as color by the renderer. Normal maps, roughness, metallic and masks contain data: do not apply a color transfer just because they are image files. Use the appropriate material slot or shader hint for each map.

Avoid manually applying SrgbToLinear() to a value that has already been decoded by the material/shader path. Double conversion darkens the result. Conversely, a CPU Image.GetPixel() reads stored pixel values; it does not perform material sampling or lighting. A float Image format identifies storage precision, not the color space of its contents.

Save HDR image data without silently clipping it

Use a float format such as Image.Format.Rgbaf when creating CPU image data with values above 1. The following helper writes a one-pixel test image with RGB (4, 2, 0.25) to EXR. It is a file-data example, not a scene render or viewport screenshot.

C#
using Reckfell;

public static class HdrData
{
    // CPU image data, not a viewport capture or a display-ready screenshot.
    public static Image CreateSample()
    {
        var image = Image.CreateEmpty(1, 1, false, Image.Format.Rgbaf);
        image.SetPixel(0, 0, new Color(4f, 2f, 0.25f, 1f));
        return image;
    }

    public static Error SaveSample(string path)
    {
        using var image = CreateSample();
        return image.SaveExr(path, grayscale: false,
            colorImage: false, maxLinearValue: -1f);
    }
}

Call HdrData.SaveSample("user://hdr-data.exr") and check the returned Error before using the file. Load it with Image.LoadFromFile() to inspect the values. On the tested Windows runtime, EXR retains (4, 2, 0.25); saving the same Image through SavePng() clips the first two channels to 1. PNG saving does not automatically apply the sRGB transfer needed to prepare arbitrary linear data for display.

The EXR options have specific meanings in 1.0.0:

  • colorImage: false preserves signed float data. true clamps negative channel values to zero; it does not apply sRGB conversion or tone mapping.
  • maxLinearValue: -1f disables the upper clamp. A nonnegative value clamps stored channel values to that maximum; it is not an exposure adjustment.
  • grayscale: true labels a single-channel image as luminance. It does not turn an RGB image into grayscale.

The writer accepts uncompressed R/RG/RGB/RGBA 8-bit, half-float and float formats. Saving an 8-bit source as EXR cannot recover values or precision already lost. A build without the EXR writer returns Error.Unavailable; file and format failures also require checking the result. Verify codec availability in the actual exported build.

Capture a viewport deliberately

Wait for RenderingServer.FramePostDraw before reading Viewport.GetTexture().GetImage(); reading in _Ready() may return an old or blank frame. Then inspect the returned Image's format and the rendering path that produced it. A float format alone does not prove that this is the raw scene buffer before tone mapping.

Renaming a screenshot to .exr, converting an 8-bit Image to float, or calling SaveExr() after highlights were clipped does not recover the original lighting. The HDR 2D viewport option concerns its own linear HDR rendering path; it is not a universal raw-3D-buffer capture switch.

Diagnose the visible problem

SymptomCheck first
White light sources or windows lose all detailCompare with a lower fixed exposure; inspect source texture clipping and the tone curve. EXR saving will not repair an already clipped source.
Image looks too dark or washed outCheck color/data texture classification and duplicate or missing color conversion.
Brightness changes after moving the cameraCheck auto exposure before changing every light.
Adjusting the Environment has no effectCheck the active camera, its Environment override and the WorldEnvironment used by that viewport.
Screenshot is black or staleWait for frame completion and verify that the viewport actually renders.
Light leaks through a wall or ceilingCheck geometry, normals, shadow casting and shadow settings. A tone mapper does not fix missing occlusion.

The companion checks execute color transfers and CPU EXR/PNG roundtrips in the installed Windows editor. They do not validate GPU tone curves, physical exposure, HDR-monitor output, exported codecs or visual quality on other platforms.

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.