mirror of
https://github.com/mpv-player/mpv
synced 2024-12-24 15:52:25 +00:00
vo_opengl: add new HDR tone mapping algorithm
I call it `mobius` because apparently the form f(x) = (cx+a)/(dx+b) is called a Möbius transform, which is the algorithm this is based on. In the extremes it becomes `reinhard` (param=0.0 and `clip` (param=1.0), smoothly transitioning between the two depending on the parameter. This is a useful tone mapping algorithm since the tunable mobius transform allows the user to decide the trade-off between color accuracy and detail preservation on a continuous scale. The default of 0.3 is already far more accurate than `reinhard` while also being reasonably good at preserving highlights, without suffering from the overall brightness drop and color distortion of `hable`. For these reasons, make this the new default. Also expand and improve the documentation for these tone mapping functions.
This commit is contained in:
parent
30cd963b25
commit
d8a3b10f45
@ -4645,13 +4645,27 @@ The following video options are currently all specific to ``--vo=opengl`` and
|
|||||||
display. Valid values are:
|
display. Valid values are:
|
||||||
|
|
||||||
clip
|
clip
|
||||||
Hard-clip any out-of-range values.
|
Hard-clip any out-of-range values. Use this when you care about
|
||||||
|
perfect color accuracy for in-range values at the cost of completely
|
||||||
|
distorting out-of-range values. Not generally recommended.
|
||||||
|
mobius
|
||||||
|
Generalization of Reinhard to a Möbius transform with linear section.
|
||||||
|
Smoothly maps out-of-range values while retaining contrast and colors
|
||||||
|
for in-range material as much as possible. Use this when you care about
|
||||||
|
color accuracy more than detail preservation. This is somewhere in
|
||||||
|
between ``clip`` and ``reinhard``, depending on the value of
|
||||||
|
``--tone-mapping-param``. (default)
|
||||||
reinhard
|
reinhard
|
||||||
Reinhard tone mapping algorithm. Very simple continuous curve.
|
Reinhard tone mapping algorithm. Very simple continuous curve.
|
||||||
Preserves dynamic range and peak but uses nonlinear contrast.
|
Preserves overall image brightness but uses nonlinear contrast, which
|
||||||
|
results in flattening of details and degradation in color accuracy.
|
||||||
hable
|
hable
|
||||||
Similar to ``reinhard`` but preserves dark contrast better (slightly
|
Similar to ``reinhard`` but preserves both dark and bright details
|
||||||
sigmoidal). Developed by John Hable for use in video games. (default)
|
better (slightly sigmoidal), at the cost of slightly darkening
|
||||||
|
everything. Developed by John Hable for use in video games. Use this
|
||||||
|
when you care about detail preservation more than color/brightness
|
||||||
|
accuracy. This is roughly equivalent to
|
||||||
|
``--hdr-tone-mapping=reinhard --tone-mapping-param=0.24``.
|
||||||
gamma
|
gamma
|
||||||
Fits a logarithmic transfer between the tone curves.
|
Fits a logarithmic transfer between the tone curves.
|
||||||
linear
|
linear
|
||||||
@ -4662,6 +4676,12 @@ The following video options are currently all specific to ``--vo=opengl`` and
|
|||||||
Set tone mapping parameters. Ignored if the tone mapping algorithm is not
|
Set tone mapping parameters. Ignored if the tone mapping algorithm is not
|
||||||
tunable. This affects the following tone mapping algorithms:
|
tunable. This affects the following tone mapping algorithms:
|
||||||
|
|
||||||
|
mobius
|
||||||
|
Specifies the transition point from linear to mobius transform. Every
|
||||||
|
value below this point is guaranteed to be mapped 1:1. The higher the
|
||||||
|
value, the more accurate the result will be, at the cost of losing
|
||||||
|
bright details. Defaults to 0.3, which due to the steep initial slope
|
||||||
|
still preserves in-range colors fairly accurately.
|
||||||
reinhard
|
reinhard
|
||||||
Specifies the local contrast coefficient at the display peak. Defaults
|
Specifies the local contrast coefficient at the display peak. Defaults
|
||||||
to 0.5, which means that in-gamut values will be about half as bright
|
to 0.5, which means that in-gamut values will be about half as bright
|
||||||
|
@ -328,6 +328,7 @@ const struct m_sub_options gl_video_conf = {
|
|||||||
OPT_INTRANGE("target-brightness", target_brightness, 0, 1, 100000),
|
OPT_INTRANGE("target-brightness", target_brightness, 0, 1, 100000),
|
||||||
OPT_CHOICE("hdr-tone-mapping", hdr_tone_mapping, 0,
|
OPT_CHOICE("hdr-tone-mapping", hdr_tone_mapping, 0,
|
||||||
({"clip", TONE_MAPPING_CLIP},
|
({"clip", TONE_MAPPING_CLIP},
|
||||||
|
{"mobius", TONE_MAPPING_MOBIUS},
|
||||||
{"reinhard", TONE_MAPPING_REINHARD},
|
{"reinhard", TONE_MAPPING_REINHARD},
|
||||||
{"hable", TONE_MAPPING_HABLE},
|
{"hable", TONE_MAPPING_HABLE},
|
||||||
{"gamma", TONE_MAPPING_GAMMA},
|
{"gamma", TONE_MAPPING_GAMMA},
|
||||||
|
@ -91,6 +91,7 @@ enum blend_subs_mode {
|
|||||||
|
|
||||||
enum tone_mapping {
|
enum tone_mapping {
|
||||||
TONE_MAPPING_CLIP,
|
TONE_MAPPING_CLIP,
|
||||||
|
TONE_MAPPING_MOBIUS,
|
||||||
TONE_MAPPING_REINHARD,
|
TONE_MAPPING_REINHARD,
|
||||||
TONE_MAPPING_HABLE,
|
TONE_MAPPING_HABLE,
|
||||||
TONE_MAPPING_GAMMA,
|
TONE_MAPPING_GAMMA,
|
||||||
|
@ -377,6 +377,21 @@ static void pass_tone_map(struct gl_shader_cache *sc, float ref_peak,
|
|||||||
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
|
GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TONE_MAPPING_MOBIUS: {
|
||||||
|
float j = isnan(param) ? 0.3 : param;
|
||||||
|
// solve for M(j) = j; M(ref_peak) = 1.0; M'(j) = 1.0
|
||||||
|
// where M(x) = scale * (x+a)/(x+b)
|
||||||
|
float a = -j*j * (ref_peak - 1) / (j*j - 2*j + ref_peak),
|
||||||
|
b = (j*j - 2*j*ref_peak + ref_peak) / (ref_peak - 1);
|
||||||
|
|
||||||
|
GLSLF("color.rgb = mix(vec3(%f) * (color.rgb + vec3(%f))\n"
|
||||||
|
" / (color.rgb + vec3(%f)),\n"
|
||||||
|
" color.rgb,\n"
|
||||||
|
" lessThanEqual(color.rgb, vec3(%f)));\n",
|
||||||
|
(b*b + 2*b*j + j*j) / (b - a), a, b, j);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case TONE_MAPPING_REINHARD: {
|
case TONE_MAPPING_REINHARD: {
|
||||||
float contrast = isnan(param) ? 0.5 : param,
|
float contrast = isnan(param) ? 0.5 : param,
|
||||||
offset = (1.0 - contrast) / contrast;
|
offset = (1.0 - contrast) / contrast;
|
||||||
|
Loading…
Reference in New Issue
Block a user