JS、WebGL:视频倒置显示

问题描述 投票:0回答:0

视频由 WebGL 着色器处理,该着色器添加了模糊滤镜并将其呈现在画布上。但是,结果,视频显示颠倒了。演示是here。是否上下颠倒 - 取决于应用模糊滤镜的次数。如果模糊滤镜被应用奇数次,它就会颠倒;如果数字是偶数 - 那么它将正常显示。

为了解决这个问题,我尝试添加 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);正如here所描述的那样。但由于某种原因它不起作用。

我用模糊滤镜渲染视频的代码:

class WebGLRenderer {
    #ctx = null;
    #texWidthLoc = null;
    #texHeightLoc = null;
    #sigmaLoc = null;
    #fb = null;
    #fb2 = null;
    #tex = null;
    #texfb = null;
    #texfb2 = null;

    get ctx() {
        return this.#ctx;
    }
 
    static blurFilterShader = `
        precision mediump float;
        uniform sampler2D texture0;
        uniform sampler2D texture1;
        uniform float texWidth;
        uniform float texHeight;

        uniform float u_sigma;

        float CalcGauss( float x, float sigma )
        {
            return exp(-0.5*(x*x)/(sigma*sigma));
        }

        vec4 blur(vec2 texCoord, sampler2D texture, float sigma) {
            vec2 texC     = texCoord;
            vec4 texCol   = texture2D( texture, texC );

            vec4 gaussCol = vec4( texCol.rgb, 1.0 );
            vec2 steph     = vec2(1.0, 0.0) / texWidth;
            for ( int i = 1; i <= 32; ++ i )
            {
                float weight = CalcGauss( float(i) / 32.0, sigma * 0.5 );
                if ( weight < 1.0/255.0 )
                break;
                texCol    = texture2D( texture, texC + steph * float(i) );
                gaussCol += vec4( texCol.rgb * weight, weight );
                texCol    = texture2D( texture, texC - steph * float(i) );
                gaussCol += vec4( texCol.rgb * weight, weight );
            }
    
            gaussCol.rgb = clamp( gaussCol.rgb / gaussCol.w, 0.0, 1.0 );
            return vec4( gaussCol.rgb, 1.0 );
        }

        void main(void) {
            vec2 texCoord = vec2(gl_FragCoord.x/texWidth, 1.0 - (gl_FragCoord.y/texHeight));
            vec4 blur0 = blur(texCoord, texture0, u_sigma);
            gl_FragColor = blur0;
        }
        `;

    constructor(type, canvas) {
        this.canvas = canvas;
        this.lastWidth = 0;
        this.allSourceFilters = [];
        this.blurFilters = [];

        const gl = this.#ctx = canvas.getContext(type, {
            premultipliedAlpha: false,
        });
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

        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, WebGLRenderer.blurFilterShader);
        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, 1, -1, 1, 1]), gl.STATIC_DRAW);

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

        gl.activeTexture(gl.TEXTURE0);
        const tex = this.#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.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);


        //gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
        gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
        gl.enable(gl.BLEND);
        gl.disable(gl.DEPTH_TEST);

        gl.enable(gl.CULL_FACE);

        const texWidthLoc = this.#texWidthLoc = gl.getUniformLocation(prog, "texWidth");
        const texHeightLoc = this.#texHeightLoc = gl.getUniformLocation(prog, "texHeight");
        const sigmaLoc = this.#sigmaLoc = gl.getUniformLocation(prog, "u_sigma");

        const fb = this.#fb = gl.createFramebuffer();
        const texfb = this.#texfb = gl.createTexture();
        const fb2 = this.#fb2 = gl.createFramebuffer();
        const texfb2 = this.#texfb2 = gl.createTexture();

    }

    draw(frame) {
        this.canvas.width = frame.videoWidth;
        this.canvas.height = frame.videoHeight;
        let frameWidth = frame.videoWidth;
        let frameHeight = frame.videoHeight;
        
        const gl = this.#ctx;

        if (this.lastWidth != frameWidth) {

            gl.bindTexture(gl.TEXTURE_2D, this.#texfb);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, frameWidth, frameHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
                
            gl.bindFramebuffer(gl.FRAMEBUFFER, this.#fb);
            gl.framebufferTexture2D(
                gl.FRAMEBUFFER,
                gl.COLOR_ATTACHMENT0,  // attach texture as COLOR_ATTACHMENT0
                gl.TEXTURE_2D,         // attach a 2D texture
                this.#texfb,                     // the texture to attach
                0);
        }
        

        let currentFrameBuffer = this.#fb;
        let currentTexture = this.#tex;
        for (let b in this.blurFilters) {
            let filter = this.blurFilters[b];
            //gl.bindFramebuffer(gl.FRAMEBUFFER, currentFrameBuffer);
            //gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.#tex, 0);
            gl.viewport(0, 0, frameWidth, frameHeight);
            //gl.activeTexture(gl.TEXTURE0);
            gl.bindTexture(gl.TEXTURE_2D, currentTexture);
            if (parseInt(b) == 0) {
                gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, frame);
                
            }
            gl.uniform1f(this.#texWidthLoc, frameWidth);
            gl.uniform1f(this.#texHeightLoc, frameHeight);
            gl.uniform1f(this.#sigmaLoc, parseFloat(filter.sigma));
            if (this.blurFilters[parseInt(b) + 1]) {
                if(gl.getParameter(gl.FRAMEBUFFER_BINDING) == this.#fb) {
                    currentFrameBuffer = this.#fb2;
                    currentTexture = this.#texfb;
                } else {
                    currentFrameBuffer = this.#fb;
                    currentTexture = this.#tex;
                }
                
                gl.bindFramebuffer(gl.FRAMEBUFFER, currentFrameBuffer);
                gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, currentTexture, 0);
                gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
            } else {
                gl.bindFramebuffer(gl.FRAMEBUFFER, null);
                gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
            }
        }
      
    }
    
    addBlueFilter() {
        let blurFilterData = {
            sigma: 0.08
        }
        this.blurFilters.push(blurFilterData);
        return blurFilterData;
    }
};

为什么会发生这种情况,如何解决?

javascript canvas glsl webgl fragment-shader
© www.soinside.com 2019 - 2024. All rights reserved.