Introduce Khronos Neutral tonemapper as new default along with debug options to control tonemap mix (#2464) (#2468)

master
Rye Mutt 2024-08-30 12:49:05 -07:00 committed by GitHub
parent 7ab6144c00
commit 5b832291a8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 70 additions and 16 deletions

View File

@ -9832,6 +9832,28 @@
<key>Value</key>
<real>0.4</real>
</map>
<key>RenderTonemapMix</key>
<map>
<key>Comment</key>
<string>Mix between linear and tonemapped colors (0.0(Linear) - 1.0(Tonemapped)</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>1.0</real>
</map>
<key>RenderTonemapType</key>
<map>
<key>Comment</key>
<string>What tonemapper to use: 0 = Khronos Neutral, 1 = ACES</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>ReplaySession</key>
<map>
<key>Comment</key>

View File

@ -29,9 +29,7 @@ out vec4 frag_color;
uniform sampler2D diffuseRect;
uniform float exposure;
uniform float gamma;
uniform float aces_mix;
uniform vec2 screen_res;
in vec2 vary_fragcoord;

View File

@ -95,9 +95,33 @@ vec3 toneMapACES_Hill(vec3 color)
return color;
}
// Khronos Neutral tonemapping
// https://github.com/KhronosGroup/ToneMapping/tree/main
// Input color is non-negative and resides in the Linear Rec. 709 color space.
// Output color is also Linear Rec. 709, but in the [0, 1] range.
vec3 PBRNeutralToneMapping( vec3 color )
{
const float startCompression = 0.8 - 0.04;
const float desaturation = 0.15;
float x = min(color.r, min(color.g, color.b));
float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
color -= offset;
float peak = max(color.r, max(color.g, color.b));
if (peak < startCompression) return color;
const float d = 1. - startCompression;
float newPeak = 1. - d * d / (peak + d - startCompression);
color *= newPeak / peak;
float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.);
return mix(color, newPeak * vec3(1, 1, 1), g);
}
uniform float exposure;
uniform float gamma;
uniform float aces_mix;
uniform float tonemap_mix;
uniform int tonemap_type;
vec3 toneMap(vec3 color)
{
@ -106,8 +130,20 @@ vec3 toneMap(vec3 color)
color *= exposure * exp_scale;
// mix ACES and Linear here as a compromise to avoid over-darkening legacy content
color = mix(toneMapACES_Hill(color), color, aces_mix);
vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0));
switch(tonemap_type)
{
case 0:
color = PBRNeutralToneMapping(color);
break;
case 1:
color = toneMapACES_Hill(color);
break;
}
// mix tonemapped and linear here to provide adjustment
color = mix(clamped_color, color, tonemap_mix);
#endif
return color;
@ -125,14 +161,6 @@ void debugExposure(inout vec3 color)
}
}
vec3 legacyGamma(vec3 color)
{
vec3 c = 1. - clamp(color, vec3(0.), vec3(1.));
c = 1. - pow(c, vec3(gamma)); // s/b inverted already CPU-side
return c;
}
void main()
{
//this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)

View File

@ -7087,10 +7087,16 @@ void LLPipeline::tonemap(LLRenderTarget* src, LLRenderTarget* dst)
F32 e = llclamp(exposure(), 0.5f, 4.f);
static LLStaticHashedString s_exposure("exposure");
static LLStaticHashedString aces_mix("aces_mix");
static LLStaticHashedString tonemap_mix("tonemap_mix");
static LLStaticHashedString tonemap_type("tonemap_type");
shader.uniform1f(s_exposure, e);
shader.uniform1f(aces_mix, gEXRImage.notNull() ? 0.f : 0.3f);
static LLCachedControl<U32> tonemap_type_setting(gSavedSettings, "RenderTonemapType", 0U);
shader.uniform1i(tonemap_type, tonemap_type_setting);
static LLCachedControl<F32> tonemap_mix_setting(gSavedSettings, "RenderTonemapMix", 1.f);
shader.uniform1f(tonemap_mix, tonemap_mix_setting);
mScreenTriangleVB->setBuffer();
mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3);