Skip to content

Commit

Permalink
Gamma Correction for Resident Evil 4 (#81)
Browse files Browse the repository at this point in the history
* feat(re4remake): add gamma correction, make gamma adjust by channel

- add sRGB -> 2.2 gamma correction
- make bt709Color a float3 as w is unused
- increase DICE ShoulderStart
- compensate for black crush with gamma correction in LUT scaling
- make gamma adjust work by channel instead of by luminance

* feat(re4remake): add gamma correction, make gamma adjust by channel

- add sRGB -> 2.2 gamma correction
- make bt709Color a float3 as w is unused
- increase DICE ShoulderStart
- compensate for black crush with gamma correction in LUT scaling
- make gamma adjust work by channel instead of by luminance

* fix(re4remake): fix gamma correction tooltip
  • Loading branch information
mqhaji authored Dec 5, 2024
1 parent a9737db commit 8101663
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 18 deletions.
7 changes: 5 additions & 2 deletions src/games/re4remake/ConvertRec2020PS_0x6737588D.ps_6_6.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@ float4 main(noperspective float4 SV_Position: SV_Position,
linear float2 TEXCOORD: TEXCOORD)
: SV_Target {
if (injectedData.toneMapType != 0) {
float4 bt709Color = tLinearImage.SampleLevel(PointBorder, TEXCOORD.xy, 0.0f);
float3 bt709Color = tLinearImage.SampleLevel(PointBorder, TEXCOORD.xy, 0.0f).rgb;

if (injectedData.toneMapGammaCorrection == 1.f) {
bt709Color = renodx::color::correct::GammaSafe(bt709Color);
}
#if 1
DICESettings config = DefaultDICESettings();
config.Type = 3;
config.ShoulderStart = 0.35;
config.ShoulderStart = 0.45;
const float dicePaperWhite = whitePaperNits / renodx::color::srgb::REFERENCE_WHITE;
const float dicePeakWhite = max(displayMaxNits, whitePaperNits) / renodx::color::srgb::REFERENCE_WHITE;
bt709Color.rgb = DICETonemap(bt709Color.rgb * dicePaperWhite, dicePeakWhite, config) / dicePaperWhite;
Expand Down
24 changes: 23 additions & 1 deletion src/games/re4remake/LUTBlackCorrection.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ float3 AdjustGammaOnLuminance(float3 linearColor, float gammaAdjustmentFactor) {
return linearColor * (adjustedLuminance / originalLuminance);
}

/// Adjusts gamma for each color channel, applying the adjustment only for values less than 1.
/// This function ensures that the color's original sign is preserved and that gamma correction is only applied to values below 1.
/// At `gammaAdjustmentFactor` = 1.15, it enhances detail in the midtones and shadows without affecting peak whites or clipping any values.
/// See: https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2408-7-2023-PDF-E.pdf Section 5.1.3.2
/// @param linearColor The RGB color to adjust.
/// @param gammaAdjustmentFactor Factor to adjust the gamma for values below 1.
/// @return The RGB color with adjusted gamma for components below 1, maintaining the original sign and preserving values of 1 and above.
float3 AdjustGammaByChannel(float3 linearColor, float gammaAdjustmentFactor) {
if (gammaAdjustmentFactor == 1.f) return linearColor; // No adjustment if factor is 1

// Create a mask to identify components less than 1
float3 mask = step(linearColor, float3(1.0f, 1.0f, 1.0f)); // 1 where linearColor < 1, 0 otherwise
// Adjust gamma only for components where the value is less than 1
return mask * renodx::color::gamma::EncodeSafe(linearColor, 1.f / gammaAdjustmentFactor) + (1.f - mask) * linearColor;
}

/// Applies a modified `renodx::lut::Sample` that accounts for only black level correction,
/// leaving peak white untouched as LUTs are already HDR, ensuring no highlight impact.
/// @param color_input Input color to apply the LUT to.
Expand All @@ -30,6 +46,9 @@ float3 LUTBlackCorrection(float3 color_input, Texture3D lut_texture, renodx::lut
float3 lutInputColor = renodx::lut::ConvertInput(color_input, lut_config);
float3 lutOutputColor = renodx::lut::SampleColor(lutInputColor, lut_config, lut_texture);
float3 color_output = renodx::lut::LinearOutput(lutOutputColor, lut_config);

float3 original_output = color_output;

if (lut_config.scaling != 0) {
float3 lutBlack = renodx::lut::SampleColor(renodx::lut::ConvertInput(0, lut_config), lut_config, lut_texture);
float3 lutMid = renodx::lut::SampleColor(renodx::lut::ConvertInput(0.18f, lut_config), lut_config, lut_texture);
Expand All @@ -41,6 +60,9 @@ float3 LUTBlackCorrection(float3 color_input, Texture3D lut_texture, renodx::lut
renodx::lut::GammaInput(color_input, lutInputColor, lut_config));
float3 recolored = renodx::lut::RecolorUnclamped(color_output, renodx::lut::LinearUnclampedOutput(unclamped, lut_config));
color_output = lerp(color_output, recolored, lut_config.scaling);
if (injectedData.toneMapGammaCorrection == 1.f) { // fixes crushed blacks with 2.2 gamma correction
color_output = lerp(color_output, original_output, saturate(pow(color_output, lutMid)));
}
}
color_output = renodx::lut::RestoreSaturationLoss(color_input, color_output, lut_config);
if (lut_config.strength != 1.f) {
Expand Down Expand Up @@ -78,4 +100,4 @@ float3 renoDRTSmoothClamp(float3 untonemapped) {
renoDRTColor = lerp(untonemapped, renoDRTColor, saturate(renodx::color::y::from::BT709(untonemapped) / renodrt_config.mid_gray_value));

return min(1, renoDRTColor);
}
}
36 changes: 24 additions & 12 deletions src/games/re4remake/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,29 @@ renodx::utils::settings::Settings settings = {
.tooltip = "Sets the tone mapper type",
.labels = {"Vanilla", "Vanilla+"},
},
new renodx::utils::settings::Setting{
.key = "toneMapGammaCorrection",
.binding = &shader_injection.toneMapGammaCorrection,
.value_type = renodx::utils::settings::SettingValueType::BOOLEAN,
.default_value = 1.f,
.can_reset = false,
.label = "Gamma Correction",
.section = "Tone Mapping",
.tooltip = "Emulates a 2.2 EOTF, this is likely what the developers tried to approximate with the vanilla gamma adjustment",
.is_enabled = []() { return shader_injection.toneMapType != 0; },
},
new renodx::utils::settings::Setting{
.key = "toneMapGammaAdjust",
.binding = &shader_injection.toneMapGammaAdjust,
.default_value = 1.f,
.label = "Gamma Adjustment",
.section = "Tone Mapping",
.tooltip = "Adjusts gamma",
.min = 0.75f,
.max = 1.25f,
.format = "%.2f",
.is_enabled = []() { return shader_injection.toneMapType != 0; },
},
new renodx::utils::settings::Setting{
.key = "colorGradeHighlightContrast",
.binding = &shader_injection.colorGradeHighlightContrast,
Expand Down Expand Up @@ -98,18 +121,6 @@ renodx::utils::settings::Settings settings = {
.max = 100.f,
.parse = [](float value) { return value * 0.01f; },
},
new renodx::utils::settings::Setting{
.key = "colorGradeGammaAdjust",
.binding = &shader_injection.colorGradeGammaAdjust,
.default_value = 1.f,
.label = "Gamma Adjustment (Hue Preserving)",
.section = "Color Grading",
.tooltip = "Adjusts gamma on luminance, only affects luminance values below 1.",
.min = 0.75f,
.max = 1.25f,
.format = "%.2f",
.is_enabled = []() { return shader_injection.toneMapType != 0; },
},
new renodx::utils::settings::Setting{
.key = "processingInternalSampling",
.binding = &shader_injection.processingInternalSampling,
Expand Down Expand Up @@ -150,6 +161,7 @@ renodx::utils::settings::Settings settings = {

void OnPresetOff() {
renodx::utils::settings::UpdateSetting("toneMapType", 0.f);
renodx::utils::settings::UpdateSetting("toneMapGammaCorrection", 0.f);
renodx::utils::settings::UpdateSetting("colorGradeToeAdjustmentType", 0.f);
renodx::utils::settings::UpdateSetting("colorGradeShadowToe", 1.f);
renodx::utils::settings::UpdateSetting("colorGradeHighlightContrast", 50.f);
Expand Down
3 changes: 2 additions & 1 deletion src/games/re4remake/shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@
// Should be 4x32
struct ShaderInjectData {
float toneMapType;
float toneMapGammaCorrection;
float toneMapGammaAdjust;
float colorGradeHighlightContrast;
float colorGradeToeAdjustmentType;
float colorGradeShadowToe;
float colorGradeLUTStrength;
float colorGradeLUTScaling;
float colorGradeGammaAdjust;
float processingInternalSampling;
};

Expand Down
2 changes: 1 addition & 1 deletion src/games/re4remake/tonemap_inside_0x1F9104F3.ps_6_6.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -1416,7 +1416,7 @@ void frag_main()
SV_Target.w = 0.0f;

if (injectedData.toneMapType != 0) {
SV_Target.rgb = AdjustGammaOnLuminance(SV_Target.rgb, injectedData.colorGradeGammaAdjust);
SV_Target.rgb = AdjustGammaByChannel(SV_Target.rgb, injectedData.toneMapGammaAdjust);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1447,7 +1447,7 @@ void frag_main()
SV_Target.w = 0.0f;

if (injectedData.toneMapType != 0) {
SV_Target.rgb = AdjustGammaOnLuminance(SV_Target.rgb, injectedData.colorGradeGammaAdjust);
SV_Target.rgb = AdjustGammaByChannel(SV_Target.rgb, injectedData.toneMapGammaAdjust);
}
}

Expand Down

0 comments on commit 8101663

Please sign in to comment.