const CHROMA_KEY: &str = r#"
vec3 fx_ycc(vec3 c) {
return vec3(dot(c, vec3(0.299, 0.587, 0.114)),
dot(c, vec3(-0.168736, -0.331264, 0.5)) + 0.5,
dot(c, vec3(0.5, -0.418688, -0.081312)) + 0.5);
}
vec3 fx_rgb(vec3 y) {
float cb = y.y - 0.5;
float cr = y.z - 0.5;
return vec3(y.x + 1.402 * cr, y.x - 0.344136 * cb - 0.714136 * cr, y.x + 1.772 * cb);
}
float fx_alpha(vec2 uv) {
vec2 c = fx_ycc(texture(tex, uv).rgb).yz;
vec2 k = fx_ycc(clamp(vec3(p0, p1, p2) / 255.0, 0.0, 1.0)).yz;
float sim = clamp(p3, 0.0, 1.0) * 0.5;
return smoothstep(sim, sim + max(clamp(p4, 0.0, 1.0) * 0.5, 0.0005), distance(c, k));
}
void main() {
vec2 uv = gl_FragCoord.xy / u_res;
vec4 src = texture(tex, uv);
float a = fx_alpha(uv);
float sh = p7 * u_scale;
if (abs(sh) > 0.01) {
vec2 step_ = vec2(abs(sh)) / u_res;
for (int i = 0; i < 8; i++) {
float ang = float(i) * 0.78539816;
float n = fx_alpha(uv + vec2(cos(ang), sin(ang)) * step_);
a = sh > 0.0 ? min(a, n) : max(a, n);
}
}
vec3 rgb = src.rgb;
float spill = clamp(p6, 0.0, 1.0);
if (spill > 0.0) {
vec3 y = fx_ycc(rgb);
vec2 kc = fx_ycc(clamp(vec3(p0, p1, p2) / 255.0, 0.0, 1.0)).yz - 0.5;
if (length(kc) > 0.001) {
vec2 dir = normalize(kc);
vec2 cc = y.yz - 0.5;
float proj = dot(cc, dir);
if (proj > 0.0) {
cc -= dir * proj * spill;
rgb = clamp(fx_rgb(vec3(y.x, cc + 0.5)), 0.0, 1.0);
}
}
}
vec4 res = vec4(rgb, src.a * a);
if (p5 >= 0.5) {
res = vec4(vec3(a), 1.0);
}
float m = u_has_mask > 0.5 ? texture(u_mask, uv).r : 1.0;
out_color = mix(src, res, m);
}
"#;Expand description
Chroma key: distance in the Cb/Cr plane to the key colour, with spill removal, matte erode/dilate (p7 project px, + shrinks) and a show-mask switch (p5).