Skip to content

Commit

Permalink
vo_opengl: add new HDR tone mapping algorithm
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
haasn authored and wiiaboo committed Jun 9, 2017
1 parent 30cd963 commit d8a3b10
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 4 deletions.
28 changes: 24 additions & 4 deletions DOCS/man/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4645,13 +4645,27 @@ The following video options are currently all specific to ``--vo=opengl`` and
display. Valid values are:

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 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
Similar to ``reinhard`` but preserves dark contrast better (slightly
sigmoidal). Developed by John Hable for use in video games. (default)
Similar to ``reinhard`` but preserves both dark and bright details
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
Fits a logarithmic transfer between the tone curves.
linear
Expand All @@ -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
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
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
Expand Down
1 change: 1 addition & 0 deletions video/out/opengl/video.c
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ const struct m_sub_options gl_video_conf = {
OPT_INTRANGE("target-brightness", target_brightness, 0, 1, 100000),
OPT_CHOICE("hdr-tone-mapping", hdr_tone_mapping, 0,
({"clip", TONE_MAPPING_CLIP},
{"mobius", TONE_MAPPING_MOBIUS},
{"reinhard", TONE_MAPPING_REINHARD},
{"hable", TONE_MAPPING_HABLE},
{"gamma", TONE_MAPPING_GAMMA},
Expand Down
1 change: 1 addition & 0 deletions video/out/opengl/video.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ enum blend_subs_mode {

enum tone_mapping {
TONE_MAPPING_CLIP,
TONE_MAPPING_MOBIUS,
TONE_MAPPING_REINHARD,
TONE_MAPPING_HABLE,
TONE_MAPPING_GAMMA,
Expand Down
15 changes: 15 additions & 0 deletions video/out/opengl/video_shaders.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);)
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: {
float contrast = isnan(param) ? 0.5 : param,
offset = (1.0 - contrast) / contrast;
Expand Down

2 comments on commit d8a3b10

@Hrxn
Copy link
Contributor

@Hrxn Hrxn commented on d8a3b10 Jun 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also set to new default?

@haasn
Copy link
Member Author

@haasn haasn commented on d8a3b10 Jun 10, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, indeed, forgot to actually change the default

Please sign in to comment.