微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

iPhone 上的 WebGL 色度键过滤器很奇怪

如何解决iPhone 上的 WebGL 色度键过滤器很奇怪

我正在从事一个项目,其目标是将没有背景的视频打印到网站的屏幕上。它必须是跨平台的。 我的第一次尝试是简单地阅读视频,在画布上处理每一帧并使特定颜色的像素透明。但结果太“脏”了。 然后我创立了this tutorial,所以我尝试通过执行以下代码来应用它:

HTML:

<div class="incrusted-video-player">
    <video id="videoVideo" height="500" playsinline>
        <source src="videos/incrusted/test.webm">
        <source src="videos/incrusted/test.mp4">
    </video>
    <canvas id="canvasVideo" height="500" width="282">Votre navigateur ne supporte pas WebGL</canvas>
</div>


<script id="fragment-shader" type="glsl">
precision mediump float;

uniform sampler2D tex;
uniform float texWidth;
uniform float texHeight;

uniform vec3 keyColor;
uniform float similarity;
uniform float smoothness;
uniform float spill;

// From https://github.com/libretro/glsl-shaders/blob/master/nnedi3/shaders/rgb-to-yuv.glsl
vec2 RGBtoUV(vec3 rgb) {
  return vec2(
    rgb.r * -0.169 + rgb.g * -0.331 + rgb.b *  0.5    + 0.5,rgb.r *  0.5   + rgb.g * -0.419 + rgb.b * -0.081  + 0.5
  );
}

vec4 ProcessChromakey(vec2 texCoord) {
  vec4 rgba = texture2D(tex,texCoord);
  float chromadist = distance(RGBtoUV(texture2D(tex,texCoord).rgb),RGBtoUV(keyColor));

  float baseMask = chromadist - similarity;
  float fullMask = pow(clamp(baseMask / smoothness,0.,1.),1.5);
  rgba.a = fullMask;

  float spillVal = pow(clamp(baseMask / spill,1.5);
  float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722,1.);
  rgba.rgb = mix(vec3(desat,desat,desat),rgba.rgb,spillVal);

  return rgba;
}

void main(void) {
  vec2 texCoord = vec2(gl_FragCoord.x/texWidth,1.0 - (gl_FragCoord.y/texHeight));
  gl_FragColor = ProcessChromakey(texCoord);
}
</script>
<script src="index.js" type="text/javascript"></script>

index.js

let video = document.querySelector('#videoVideo'),canvas = document.querySelector('#canvasVideo'),gl = canvas.getContext("webgl",{premultipliedAlpha: false}),processInterval,colorKey = '587b45',colorSimilarity = 0,// [0 - 1]
    colorSmotthness = 0.087,// [0 - 1]
    colorSpill = 0; // [0 - 1]

let texLoc,texWidthLoc,texHeightLoc,keyColorLoc,similarityLoc,smoothnessLoc,spillLoc;

video.addEventListener('play',() => {
    console.log('video play')
    document.querySelector('.incrusted-video-player').classList.add('play');
    if (processInterval) clearInterval(processInterval)
    processInterval = setInterval(processFrame,1000/30);
})

video.addEventListener('ended',() => {
    console.log('video ended')
    document.querySelector('.incrusted-video-player').classList.remove('play');
    if (processInterval) clearInterval(processInterval)
})

function startIncrustedVideoPlayer() {
    const vs = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vs,'attribute vec2 c; void main(void) { gl_Position=vec4(c,0.0,1.0); }');
    gl.compileShader(vs);

    const fs = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fs,document.getElementById("fragment-shader").innerText);
    gl.compileShader(fs);
    if (!gl.getShaderParameter(fs,gl.COMPILE_STATUS)) {
        console.error(gl.getShaderInfoLog(fs));
    }

    const prog = gl.createProgram();
    gl.attachShader(prog,vs);
    gl.attachShader(prog,fs);
    gl.linkProgram(prog);
    gl.useProgram(prog);

    const vb = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER,vb);
    gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([-1,1,-1,1]),gl.STATIC_DRAW);

    const coordLoc = gl.getAttribLocation(prog,'c');
    gl.vertexAttribPointer(coordLoc,2,gl.FLOAT,false,0);
    gl.enabLevertexAttribArray(coordLoc);

    gl.activeTexture(gl.TEXTURE0);
    const tex = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D,tex);

    gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.TEXTURE_MIN_FILTER,gl.LINEAR);

    texLoc = gl.getUniformlocation(prog,"tex");
    texWidthLoc = gl.getUniformlocation(prog,"texWidth");
    texHeightLoc = gl.getUniformlocation(prog,"texHeight");
    keyColorLoc = gl.getUniformlocation(prog,"keyColor");
    similarityLoc = gl.getUniformlocation(prog,"similarity");
    smoothnessLoc = gl.getUniformlocation(prog,"smoothness");
    spillLoc = gl.getUniformlocation(prog,"spill");

    video.addEventListener('play',() => {
        if (processInterval) clearInterval(processInterval);
        processInterval = setInterval(processFrame,1000/30);
    });

    video.addEventListener('ended',() => processInterval && clearInterval(processInterval));

    video.play();
}

function processFrame() {
    const Metadata = {width: canvas.offsetWidth,height: canvas.offsetHeight};

    gl.viewport(0,Metadata.width,Metadata.height);
    gl.texImage2D(gl.TEXTURE_2D,gl.RGB,gl.UNSIGNED_BYTE,video);
    gl.uniform1i(texLoc,0);
    gl.uniform1f(texWidthLoc,Metadata.width);
    gl.uniform1f(texHeightLoc,Metadata.height);
    const m = colorKey;
    gl.uniform3f(keyColorLoc,parseInt(m.substr(0,2),16) / 255,parseInt(m.substr(2,parseInt(m.substr(4,16) / 255);
    gl.uniform1f(similarityLoc,colorSimilarity);
    gl.uniform1f(smoothnessLoc,colorSmotthness);
    gl.uniform1f(spillLoc,colorSpill);
    gl.drawArrays(gl.TRIANGLE_FAN,4);
}

您可以在此处查看结果:https://hecvr.navalex.net 它实际上在桌面上运行良好,但是当涉及到移动设备时(仅在 iPhone X 上测试过),我在画布视频后面有一个半透明的白色背景。 我真的很了解 webgl 和 canvas,但我尝试调整过滤器参数(颜色、平滑度等),但没有解决我的问题。

也许有人知道为什么它会在移动设备上显示这种白色背景?

PS:如果有人知道在网络上包含透明视频的更简单的解决方案(我们尝试过 WebM 等,但我们从未完成跨平台结果..)

谢谢, 纳瓦莱克斯

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。