Skip to content
Musa Haji edited this page Dec 16, 2024 · 18 revisions

Hue Correction: Essential for Accurate Color Representation in HDR

Hue Correction is crucial in RenoDX mods for preserving the original color intent of games when transitioning from SDR to HDR. In many SDR-developed games, hue shifts often occur not by initial design but as artifacts of the display technology or the color processing methods used. Developers typically adjust their visual assets and color grading to compensate for these shifts, leading to in-game colors that may significantly differ from their original textures. For instance, in games like Dark Souls, fire textures that are pink in their raw form might appear orange or yellow in-game, a result of such compensations for hue shifts in SDR.

To ensure that these adjusted hues translate correctly in HDR and reflect the developers' adapted vision, implementing Hue Correction is necessary. This process accurately emulates the hue shifts that occur in SDR, maintaining the visual integrity and intended appearance of the game.

Below is an example from Atelier Sophie 1, where without hue correction bright oranges become carrot colored:

  • No Hue Correction -- Carrot (wrong color) sophie1 carrot

  • Reinhard -- Good sophie1 reinhard

Adding Hue Correction to your RenoDX project involves only a few lines of code and is typically straightforward. Here’s a basic implementation using the Reinhard tonemapper for Hue Correction:

Add these 3 lines to your config builder to control hue correction with a variable toneMapHueCorrection:

    config.hue_correction_type = renodx::tonemap::config::hue_correction_type::CUSTOM;
    config.hue_correction_color = renodx::tonemap::Reinhard(untonemapped);
    config.hue_correction_strength = injectedData.toneMapHueCorrection;

Hue Correction is also part of the UserColorGrading() function:

  hueCorrected = renodx::color::grade::UserColorGrading(
      untonemapped,
      1.f,                                         // Exposure
      1.f,                                         // Highlights
      1.f,                                         // Shadows
      1.f,                                         // Contrast
      1.f,                                         // Saturation
      0.f,                                         // Dechroma
      injectedData.toneMapHueCorrection,           // Hue Correction Strength
      renodx::tonemap::Reinhard(untonemapped);

Hue Correction can also be applied separately:

    correctedHue = renodx::color::correct::Hue(incorrectHue, renodx::tonemap::Reinhard(untonemapped))

Hue Correction can be used with any of RenoDX's built in tonemappers:

    renodx::tonemap::Reinhard(untonemapped)
    renodx::tonemap::uncharted2::BT709(untonemapped)
    renodx::tonemap::ACESFittedAP1(untonemapped)

Ideally, developers should use the game's vanilla tonemapper for hue correction, but in cases where games clamp with saturate() a tonemapper such as Uncharted2 should be used instead.

If you cant settle on a form of Hue Correction, you can always have multiple in your mod! For example Atelier Sophie 1 has a slider that lets the user select either no hue correction, Reinhard, or Uncharted2

Example code: https://github.com/marat569/renodx/blob/2f9f9f95283749023f18fa70a38a4f371d26ffd4/src/games/sophie1/tonemapper.hlsl#L42

As for the slider in addon.cpp: https://github.com/marat569/renodx/blob/2f9f9f95283749023f18fa70a38a4f371d26ffd4/src/games/sophie1/addon.cpp#L88

Example: Blue to Cyan Hue Shift

One of the most common hue shifts when upgrading a game to HDR is blue to cyan; where the SDR image is blue -- but the HDR output with no hue correction starts to shift towards cyan

  • Typically things will shift towards complementary colors (especially yellow/cyan) because they can get much brighter than red/blue; which kind of makes it difficult to guess the correct hue going from sdr to hdr - Dylan (HDR Den Discord)

SDR:

SDR head 1

HDR (Frostbite, no hue correction):

frostbite head no hue

If you compare the above two images, you can see the the HDR head is starting to shift torwards Cyan.

Here is the same head, same tonemapper, but with renodx::tonemap::Reinhard(untonemapped); hue correction at 0.5f strength

frostbite head  5 reinhard

The game used as an example has no vanilla color/sdr tonemapper, so we're applying Reinhard on untonemapped or the raw hdr render

One line of code fixed our magical head's color!

Also see: HDR color grading and display in Frostbite Slides 35-44