Skip to content

Instantly share code, notes, and snippets.

@Quackdoc
Created June 1, 2023 08:17
Show Gist options
  • Save Quackdoc/cc37d015a4343c5caec26f459d9f2334 to your computer and use it in GitHub Desktop.
Save Quackdoc/cc37d015a4343c5caec26f459d9f2334 to your computer and use it in GitHub Desktop.
olive tonemap ported from hdr-toys
<?xml version="1.0"?>
<olive version="230220">
<nodes version="1">
<node version="1" id="org.olivevideoeditor.Olive.displaytransform" ptr="1991839047088">
<input id="enabled_in">
<primary>
<keyframing>0</keyframing>
<standard>
<track>true</track>
</standard>
</primary>
</input>
<input id="tex_in">
<primary>
<standard>
<track></track>
</standard>
</primary>
</input>
<input id="display_in">
<primary>
<standard>
<track>0</track>
</standard>
</primary>
</input>
<input id="view_in">
<primary>
<standard>
<track>0</track>
</standard>
</primary>
</input>
<input id="dir_in">
<primary>
<standard>
<track>0</track>
</standard>
</primary>
</input>
<connections>
<connection input="tex_in" element="-1">
<output>1991285140944</output>
</connection>
</connections>
<caches>
<audio>{ba1879fc-773e-4cd0-9ed4-cb7715ffa1ca}</audio>
<video>{b7aac616-432b-4ae7-b31d-be625f65cec0}</video>
<thumb>{c42a5196-a70e-4ea7-8013-d1bdf3ded39e}</thumb>
<waveform>{5d6ac312-66ac-4db6-8a9e-09146de35401}</waveform>
</caches>
<custom/>
</node>
<node version="1" id="org.olivevideoeditor.Olive.shader" ptr="1991285140944">
<label>Compress</label>
<input id="enabled_in">
<primary>
<keyframing>0</keyframing>
<standard>
<track>true</track>
</standard>
</primary>
</input>
<input id="source">
<primary>
<standard>
<track>#version 150
//OVE shader_name: Compress
//OVE shader_description:
//OVE main_input_name: Input
uniform sampler2D tex_in;
//OVE end
// pixel coordinates in range [0..1]x[0..1]
in vec2 ove_texcoord;
// output color
out vec4 frag_color;
const float cyan_limit = 1.6515689028157825;
const float magenta_limit = 1.7355376392652817;
const float yellow_limit = 1.671460554049985;
const float cyan_threshold = 0.4770771960073855;
const float magenta_threshold = 0.43305325213057494;
const float yellow_threshold = 0.8430686842640781;
const float select = 0.1;
mat3 M = mat3(
1.6605, -0.5876, -0.0728,
-0.1246, 1.1329, -0.0083,
-0.0182, -0.1006, 1.1187);
void main(void) {
vec4 color = texture(tex_in, ove_texcoord);
vec3 color_src = color.rgb;
vec3 color_src_cliped = clamp(color_src, 0.0, 1.0);
vec3 color_dst = color_src_cliped * M;
vec3 rgb = color_dst;
// Distance limit: How far beyond the gamut boundary to compress
vec3 dl = vec3(cyan_limit, magenta_limit, yellow_limit);
// Amount of outer gamut to affect
vec3 th = vec3(cyan_threshold, magenta_threshold, yellow_threshold);
// Achromatic axis
float ac = max(rgb.x, max(rgb.y, rgb.z));
// Inverse RGB Ratios: distance from achromatic axis
vec3 d = ac == 0.0 ? vec3(0.0) : (ac - rgb) / abs(ac);
// Calculate scale so compression function passes through distance limit: (x=dl, y=1)
vec3 s;
s.x = (1.0 - th.x) / sqrt(dl.x - 1.0);
s.y = (1.0 - th.y) / sqrt(dl.y - 1.0);
s.z = (1.0 - th.z) / sqrt(dl.z - 1.0);
vec3 cd; // Compressed distance
// Parabolic compression function: https://www.desmos.com/calculator/nvhp63hmtj
cd.x = d.x &lt; th.x ? d.x : s.x * sqrt(d.x - th.x + s.x * s.x / 4.0) - s.x * sqrt(s.x * s.x / 4.0) + th.x;
cd.y = d.y &lt; th.y ? d.y : s.y * sqrt(d.y - th.y + s.y * s.y / 4.0) - s.y * sqrt(s.y * s.y / 4.0) + th.y;
cd.z = d.z &lt; th.z ? d.z : s.z * sqrt(d.z - th.z + s.z * s.z / 4.0) - s.z * sqrt(s.z * s.z / 4.0) + th.z;
// Inverse RGB Ratios to RGB
vec3 crgb = ac - cd * abs(ac);
color.rgb = mix(rgb, crgb, select);
frag_color= color.rgba;
}
</track>
</standard>
</primary>
</input>
<input id="issues">
<primary>
<standard>
<track>None</track>
</standard>
</primary>
</input>
<input id="tex_in">
<primary>
<standard>
<track></track>
</standard>
</primary>
</input>
<connections>
<connection input="tex_in" element="-1">
<output>1991285142096</output>
</connection>
</connections>
<hints>
<hint input="enabled_in" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="issues" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="source" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="tex_in" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
</hints>
<caches>
<audio>{d0f2d853-dfc5-46f9-bce2-25c7f4a498dc}</audio>
<video>{a72a54d3-2d1e-4719-b9a5-d370f64a3751}</video>
<thumb>{affcfa21-94d6-43bf-85d4-993aada2a416}</thumb>
<waveform>{d266519a-e979-456f-9386-d463b97a28ac}</waveform>
</caches>
<custom/>
</node>
<node version="1" id="org.olivevideoeditor.Olive.shader" ptr="1991285142096">
<label>bt.2446a</label>
<input id="enabled_in">
<primary>
<keyframing>0</keyframing>
<standard>
<track>true</track>
</standard>
</primary>
</input>
<input id="source">
<primary>
<standard>
<track>#version 150
//OVE shader_name: bt.2446a
//OVE shader_description: Tonemap linear to bt.2446a
//OVE main_input_name: Input
uniform sampler2D tex_in;
//OVE end
// pixel coordinates in range [0..1]x[0..1]
in vec2 ove_texcoord;
// output color
out vec4 frag_color;
const float L_hdr = 2500.0;
const float L_sdr = 203.0;
const float a = 0.2627;
const float b = 0.6780;
const float c = 0.0593; // a + b + c = 1
const float d = 1.8814; // 2 * (a + b)
const float e = 1.4747; // 2 * (1 - a)
vec3 RGB_to_YCbCr(float R, float G, float B) {
const float Y = a * R + b * G + c * B;
const float Cb = (B - Y) / d;
const float Cr = (R - Y) / e;
return vec3(Y, Cb, Cr);
}
vec3 YCbCr_to_RGB(float Y, float Cb, float Cr) {
const float R = Y + e * Cr;
const float G = Y - (a * e / b) * Cr - (c * d / b) * Cb;
const float B = Y + d * Cb;
return vec3(R, G, B);
}
float f(float Y) {
Y = pow(Y, 1.0 / 2.4);
const float pHDR = 1.0 + 32.0 * pow(L_hdr / 10000.0, 1.0 / 2.4);
const float pSDR = 1.0 + 32.0 * pow(L_sdr / 10000.0, 1.0 / 2.4);
const float Yp = log(1.0 + (pHDR - 1.0) * Y) / log(pHDR);
float Yc;
if (Yp &lt;= 0.7399) Yc = Yp * 1.0770;
else if (Yp &lt; 0.9909) Yc = Yp * (-1.1510 * Yp + 2.7811) - 0.6302;
else Yc = Yp * 0.5000 + 0.5000;
const float Ysdr = (pow(pSDR, Yc) - 1.0) / (pSDR - 1.0);
Y = pow(Ysdr, 2.4);
return Y;
}
vec3 tone_mapping(vec3 YCbCr) {
const float W = L_hdr / L_sdr;
YCbCr /= W;
float Y = YCbCr.r;
float Cb = YCbCr.g;
float Cr = YCbCr.b;
const float Ysdr = f(Y);
const float Yr = Ysdr / (1.1 * Y);
Cb *= Yr;
Cr *= Yr;
Y = Ysdr - max(0.1 * Cr, 0.0);
return vec3(Y, Cb, Cr);
}
void main(void) {
//vec4 textureColor = texture(tex_in, ove_texcoord);
//frag_color= textureColor.brga;
vec4 color = texture(tex_in, ove_texcoord);
color.rgb = RGB_to_YCbCr(color.r, color.g, color.b);
color.rgb = tone_mapping(color.rgb);
color.rgb = YCbCr_to_RGB(color.r, color.g, color.b);
frag_color= color.rgba;
}</track>
</standard>
</primary>
</input>
<input id="issues">
<primary>
<standard>
<track>None</track>
</standard>
</primary>
</input>
<input id="tex_in">
<primary>
<standard>
<track></track>
</standard>
</primary>
</input>
<connections>
<connection input="tex_in" element="-1">
<output>1991486862384</output>
</connection>
</connections>
<hints>
<hint input="enabled_in" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="issues" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="source" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="tex_in" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
</hints>
<caches>
<audio>{599174c3-e141-4e2a-be0d-6a7236d14eab}</audio>
<video>{7c2957b5-f0bb-47f4-a69e-316c42b1009a}</video>
<thumb>{e00b2c50-37ed-4d7c-af82-6a5292fa35fa}</thumb>
<waveform>{dd54e144-e707-4bfd-8e51-292f7d8ecfd5}</waveform>
</caches>
<custom/>
</node>
<node version="1" id="org.olivevideoeditor.Olive.shader" ptr="1991486862384">
<label>HLG to linear</label>
<input id="enabled_in">
<primary>
<keyframing>0</keyframing>
<standard>
<track>true</track>
</standard>
</primary>
</input>
<input id="source">
<primary>
<standard>
<track>#version 150
//OVE shader_name: HLG to linear
//OVE shader_description:
//OVE main_input_name: Input
uniform sampler2D tex_in;
//OVE end
// pixel coordinates in range [0..1]x[0..1]
in vec2 ove_texcoord;
// output color
out vec4 frag_color;
const float L_sdr = 203.0;
const float Lb_sdr = 0;
const float L_w = 1000.0;
const float L_b = 0.0;
const float alpha = L_w - L_b;
const float beta = L_b;
const float gamma = 1.2 * pow(1.111, log2(L_w / 1000.0));
const float a = 0.17883277;
const float b = 1.0 - 4.0 * a;
const float c = 0.5 - a * log(4.0 * a);
// HLG EOTF (i.e. HLG inverse OETF followed by the HLG OOTF)
vec3 HLG_to_Y(vec3 HLG) {
// HLG Inverse OETF scene-linear (non-linear signal value to scene linear)
const vec3 sceneLinear = vec3(
HLG.r &gt;= 0.0 &amp;&amp; HLG.r &lt;= 0.5 ? pow(HLG.r, 2.0) / 3.0 : (exp((HLG.r - c) / a) + b) / 12.0,
HLG.g &gt;= 0.0 &amp;&amp; HLG.g &lt;= 0.5 ? pow(HLG.g, 2.0) / 3.0 : (exp((HLG.g - c) / a) + b) / 12.0,
HLG.b &gt;= 0.0 &amp;&amp; HLG.b &lt;= 0.5 ? pow(HLG.b, 2.0) / 3.0 : (exp((HLG.b - c) / a) + b) / 12.0
);
// HLG OOTF (scene linear to display linear)
const float Y_s = dot(sceneLinear, vec3(0.2627, 0.6780, 0.0593));
const vec3 displayLinear = alpha * pow(Y_s, gamma - 1) * sceneLinear + beta;
return displayLinear;
}
vec3 Y_to_linCV(vec3 Y, float Ymax, float Ymin) {
return (Y - Ymin) / (Ymax - Ymin);
}
void main(void) {
vec4 textureColor = texture(tex_in, ove_texcoord);
textureColor.rgb = clamp(textureColor.rgb, 0.0, 1.0); //clip
textureColor.rgb = HLG_to_Y(textureColor.rgb);
textureColor.rgb = Y_to_linCV(textureColor.rgb, L_sdr, Lb_sdr);
frag_color= textureColor.rgba;
}
</track>
</standard>
</primary>
</input>
<input id="issues">
<primary>
<standard>
<track>None</track>
</standard>
</primary>
</input>
<input id="tex_in">
<primary>
<standard>
<track></track>
</standard>
</primary>
</input>
<connections>
<connection input="tex_in" element="-1">
<output>1991422096304</output>
</connection>
</connections>
<hints>
<hint input="enabled_in" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="issues" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="source" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
<hint input="tex_in" element="-1" version="1">
<types/>
<index>-1</index>
<tag></tag>
</hint>
</hints>
<caches>
<audio>{bae4ad56-b731-4e97-a858-f89938a47bc9}</audio>
<video>{1e0de5ab-8367-4d85-8c2a-776a4e5369c2}</video>
<thumb>{6695b66d-123a-4d74-997d-0dfcc8d6e38d}</thumb>
<waveform>{9d6ec18f-700d-4ab1-81fc-4c7d500c330c}</waveform>
</caches>
<custom/>
</node>
<properties>
<node ptr="1991839047088">
<expanded>0</expanded>
<x>-0.833334</x>
<y>1.18519</y>
</node>
<node ptr="1991285142096">
<expanded>0</expanded>
<x>-1.62878</x>
<y>1.23457</y>
</node>
<node ptr="1991285140944">
<expanded>0</expanded>
<x>-1.20455</x>
<y>-0.0493827</y>
</node>
<node ptr="1991486862384">
<expanded>0</expanded>
<x>-1.99621</x>
<y>-0.0493827</y>
</node>
</properties>
</nodes>
</olive>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment