webgl readpixels纹理着色器问题

时间:2016-02-19 01:10:59

标签: javascript glsl textures webgl shader

我一直在尝试学习一些webgl,并且基本上有两个程序,其中渲染的像素存储在纹理中,然后在其他程序的着色器中使用。

webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);

这将调用并尝试读取屏幕的像素,并将修改后的数据放回到纹理中,以便在下一个程序渲染例程中使用。

我得到的是黑色屏幕逐渐变得更加透明,但是也应该看到u_image(因为这是在第一个用readpixels读取像素的程序中渲染的)。

如果我注释掉第二个节​​目的渲染:

    gl.useProgram(webgl.program);
    gl.clearColor(0, 0.5, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 6);

然后它只会渲染u_image而不会有任何褪色。 所以我不确定是什么问题。好像它可能没有正确读取像素?但是,如果情况如此,为什么衰落会起作用呢?尝试使用这两种纹理有什么问题吗?

希望有人可以查看代码并查看可能存在的问题。

//webgl stuff

var webgl = new webglData();

function webglData(){
    this.then = 0;      //used for deltatime in rendering
    this.request;       //requestanimationframe, used when stopping/starting

    this.canvas;
    this.context;
    this.div;

    this.program;
    this.cellProgram;

    this.texture = [];
    this.frameBuffer = [];

    this.cellVShader = `
        attribute vec2 aVertexPosition;

        attribute vec2 a_position;
        attribute vec2 a_texCoord;

        uniform vec2 u_resolution;

        varying vec2 v_texCoord;

        varying vec2 v_NW;
        varying vec2 v_N;
        varying vec2 v_NE;
        varying vec2 v_W;
        varying vec2 v_E;
        varying vec2 v_SW;
        varying vec2 v_S;
        varying vec2 v_SE;

        vec2 getOffset( int x, int y){
            vec2 v = floor(a_texCoord * u_resolution);
            v.x += float(x), v.y += float(y);
            v /= u_resolution;
            return v;
        }

        void main() {
            //v_texCoord = a_texCoord;
            //gl_Position = vec4(aVertexPosition, 0.0, 1.0);

            // convert the rectangle from pixels to 0.0 to 1.0
            vec2 zeroToOne = a_position / u_resolution;

            // convert from 0->1 to 0->2
            vec2 zeroToTwo = zeroToOne * 2.0;

            // convert from 0->2 to -1->+1 (clipspace)
            vec2 clipSpace = zeroToTwo - 1.0;

            gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

            // pass the texCoord to the fragment shader
            // The GPU will interpolate this value between points.
            v_texCoord = a_texCoord;

            v_NW = getOffset( -1, 1);
            v_N = getOffset( 0, 1);
            v_NE = getOffset( 1, 1);
            v_W = getOffset( -1, 0);
            v_E = getOffset( 1, 0);
            v_SW = getOffset( -1, -1);
            v_S = getOffset( 0, -1);
            v_SE = getOffset( 1, -1);
        }
    `;
    this.cellFShader = `
        #ifdef GL_ES
        precision highp float;
        #endif

        uniform sampler2D u_canvas1; 
        uniform vec4 uColor;
        // our texture
        uniform sampler2D u_before;
        uniform sampler2D u_after;
        uniform sampler2D u_image;

        // the texCoords passed in from the vertex shader.
        varying vec2 v_texCoord;
        varying vec2 v_NW;
        varying vec2 v_N;
        varying vec2 v_NE;
        varying vec2 v_W;
        varying vec2 v_E;
        varying vec2 v_SW;
        varying vec2 v_S;
        varying vec2 v_SE;

        void main() {
            // Look up a color from the texture.
            gl_FragColor = texture2D(u_image, v_W);
            //gl_FragColor = uColor;
        }
    `;

    this.vertexShader = `
        attribute vec2 aVertexPosition;

        attribute vec2 a_position;
        attribute vec2 a_texCoord;

        uniform vec2 u_resolution;

        varying vec2 v_texCoord;

        void main() {
            //v_texCoord = a_texCoord;
            //gl_Position = vec4(aVertexPosition, 0.0, 1.0);

            // convert the rectangle from pixels to 0.0 to 1.0
            vec2 zeroToOne = a_position / u_resolution;

            // convert from 0->1 to 0->2
            vec2 zeroToTwo = zeroToOne * 2.0;

            // convert from 0->2 to -1->+1 (clipspace)
            vec2 clipSpace = zeroToTwo - 1.0;

            gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

            // pass the texCoord to the fragment shader
            // The GPU will interpolate this value between points.
            v_texCoord = a_texCoord;
        }
    `;
    this.fragmentShader = `
        #ifdef GL_ES
        precision highp float;
        #endif

        uniform sampler2D u_canvas1; 
        uniform vec4 uColor;
        // our texture
        uniform sampler2D u_before;
        uniform sampler2D u_after;
        uniform sampler2D u_image;

        // the texCoords passed in from the vertex shader.
        varying vec2 v_texCoord;

        void main() {
            // Look up a color from the texture.
            gl_FragColor = texture2D(u_before, v_texCoord);
            //gl_FragColor = uColor;
        }
    `;

    this.init = function(){
        this.div = innerDoc.getElementById('webglDiv');
        gui.Window.get().showDevTools();

        this.canvas = document.createElement('canvas');
        this.context = this.canvas.getContext("experimental-webgl");
        this.canvas.width = 512;
        this.canvas.height = 512;
        this.canvas.style.position = 'absolute';
        this.canvas.style.zIndex = -1;
        this.canvas.style.pointerEvents = 'none';

        this.div.appendChild(this.canvas);

        if(!this.context)return;
        var gl = this.context;
        gl.viewport(0, 0, this.canvas.width, this.canvas.height);
        gl.clearColor(0, 0.5, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);

        //compile the shaders and create the program for webgl
        var vs = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vs, this.vertexShader);
        gl.compileShader(vs);        
        var fs = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fs, this.fragmentShader);
        gl.compileShader(fs);
        var cvs = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(cvs, this.cellVShader);
        gl.compileShader(cvs);       
        var cfs = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(cfs, this.cellFShader);
        gl.compileShader(cfs);

        this.program = gl.createProgram();
        gl.attachShader(this.program, vs);
        gl.attachShader(this.program, fs);
        gl.linkProgram(this.program);
        //gl.useProgram(this.program);
        this.cellProgram = gl.createProgram();
        gl.attachShader(this.cellProgram, cvs);
        gl.attachShader(this.cellProgram, cfs);
        gl.linkProgram(this.cellProgram);
        //gl.useProgram(this.cellProgram);

        //output any errors
        if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(vs));
        if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(fs));
        if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))console.log(gl.getProgramInfoLog(this.program));
        if (!gl.getShaderParameter(cvs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(cvs));
        if (!gl.getShaderParameter(cfs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(cfs));
        if (!gl.getProgramParameter(this.cellProgram, gl.LINK_STATUS))console.log(gl.getProgramInfoLog(this.cellProgram));

        this.setupStuff(gl, this.program);
        this.setupStuff(gl, this.cellProgram);

        this.texture.push( this.setupTexture(tool.canvas, 0, "u_image") );
        this.texture.push( this.createBlankTexture(gl, tool.canvas.width*tool.canvas.height*4, gl.RGBA, tool.canvas.width, tool.canvas.height, "u_before") );
        this.texture.push( this.createBlankTexture(gl, tool.canvas.width*tool.canvas.height*4, gl.RGBA, tool.canvas.width, tool.canvas.height, "u_after") );
        this.frameBuffer.push( gl.createFramebuffer() );

        this.request = requestAnimationFrame(this.render);
    }

    this.render = function(now){
        if(!webgl.context || config.tab!='scene'){cancelAnimationFrame(webgl.request); return;}
        var gl = webgl.context;

        // Convert the time to seconds
        now *= 0.001;
        // Subtract the previous time from the current time
        var deltaTime = now - webgl.then;
        // Remember the current time for the next frame.
        webgl.then = now;

        gl.useProgram(webgl.cellProgram);
        gl.drawArrays(gl.TRIANGLES, 0, 6);
        webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);

        gl.useProgram(webgl.program);
        gl.clearColor(0, 0.5, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, 6);

        this.request = requestAnimationFrame(webgl.render);
    }

    this.setupStuff = function(gl, program){
        gl.useProgram(program);

        // look up where the vertex data needs to go.
        var positionLocation = gl.getAttribLocation(program, "a_position");
        var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");

        // provide texture coordinates for the rectangle.
        //this will be what the texture gets displayed on?
        var texCoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
          0.0,  0.0,
          1.0,  0.0,
          0.0,  1.0,
          0.0,  1.0,
          1.0,  0.0,
          1.0,  1.0]), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(texCoordLocation);
        gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

        // lookup uniforms
        var resolutionLocation = gl.getUniformLocation(program, "u_resolution");

        // set the resolution
        gl.uniform2f(resolutionLocation, this.canvas.width, this.canvas.height);

        // Create a buffer for the position of the rectangle corners.
        // store the data for the texture coordinates that were defined above, into the a_position?
        var buffer = gl.createBuffer();
        //this.frameBuffer.push(buffer);
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.enableVertexAttribArray(positionLocation);
        gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

        // Set a rectangle the same size as the image.
        //I guess this adjusts the buffer data that was just created?
        this.setRectangle(gl, 0, 0, this.canvas.width, this.canvas.height);

        //var tex2 = setupTexture(canvas2, 1, program, "u_canvas2");

        // Draw the rectangle.
        //gl.drawArrays(gl.TRIANGLES, 0, 6);
        //gl.drawArrays(gl.TRIANGLES, 0, numItems);
    }

    this.refreshTexture = function(){
        if(!this.context)return;
        var gl = this.context;

        gl.activeTexture(gl.TEXTURE0 + 0);
        gl.bindTexture(gl.TEXTURE_2D, this.texture[0]);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tool.canvas);

        //gl.drawArrays(gl.TRIANGLES, 0, 6);

    }

    this.modTexture = function(gl, sTexture, framebuffer){
        gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, sTexture, 0);

        if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE)
        {
            var sTextureSize = sTexture.width * sTexture.height * 4;    // r, g, b, a
            var pixels = new Uint8Array( sTextureSize );
            gl.readPixels( 0, 0, sTexture.width, sTexture.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels );

            for( var i=0 ; i<sTextureSize ; i+=4 )
            {
                if( pixels[i+3] > 0 )
                {
                    pixels[i+3] = Math.min( 255, pixels[i+3]*0.995 );     // set half alpha
                }
            }

            // upload changes
            gl.activeTexture(gl.TEXTURE0 + 1);
            gl.bindTexture(gl.TEXTURE_2D, sTexture);
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 
                        sTexture.width, sTexture.height, 0,
                        gl.RGBA, gl.UNSIGNED_BYTE, pixels);
        }

        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    }

    this.setupFrameBuffer = function(canvas, textureUnit, program, uniformName) {
        if(!this.context)return;
        var gl = this.context;

        var rttFramebuffer = gl.createFramebuffer();
        gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
        rttFramebuffer.width = this.canvas.width;
        rttFramebuffer.height = this.canvas.height;

        var rttTexture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_2D, rttTexture);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
        gl.generateMipmap(gl.TEXTURE_2D);

        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rttFramebuffer.width, rttFramebuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rttTexture, 0);

        gl.bindTexture(gl.TEXTURE_2D, null);
        gl.bindRenderbuffer(gl.RENDERBUFFER, null);
        gl.bindFramebuffer(gl.FRAMEBUFFER, null);    

        return rttFrameBuffer;
    }

    this.setupTexture = function(canvas, textureUnit, uniformName) {
        var gl = this.context;
        var tex = gl.createTexture();

        this.updateTextureFromCanvas(tex, canvas, textureUnit);
        tex.width = canvas.width;
        tex.height= canvas.height;

        // Set the parameters so we can render any size image.
        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.useProgram(this.program);
        var location = gl.getUniformLocation(this.program, uniformName);
        gl.uniform1i(location, textureUnit);
        gl.useProgram(this.cellProgram);
        location = gl.getUniformLocation(this.cellProgram, uniformName);
        gl.uniform1i(location, textureUnit);

        return tex;
    }

    this.updateTextureFromCanvas = function(tex, canvas, textureUnit) {
        if(!this.context)return;
        var gl = this.context;

        gl.activeTexture(gl.TEXTURE0 + textureUnit);
        gl.bindTexture(gl.TEXTURE_2D, tex);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
    }

    this.createBlankTexture = function(gl, dataArray, type, width, height, uniformName) {
        var dataTypedArray = new Uint8Array(dataArray); // Don't need to do this if the data is already in a typed array
        for( var i=0 ; i<dataArray ; i+=4 )
        {
            dataTypedArray[i+3] = 255;
        }
        var texture = gl.createTexture();
        texture.width = width;
        texture.height= height;
        gl.activeTexture(gl.TEXTURE0 + this.texture.length);
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.texImage2D(gl.TEXTURE_2D, 0, type, width, height, 0, type, gl.UNSIGNED_BYTE, dataTypedArray);
        // Other texture setup here, like filter modes and mipmap generation
        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.useProgram(this.program);
        var location = gl.getUniformLocation(this.program, uniformName);
        gl.uniform1i(location, this.texture.length);
        gl.useProgram(this.cellProgram);
        location = gl.getUniformLocation(this.cellProgram, uniformName);
        gl.uniform1i(location, this.texture.length);

        return texture;
    }


    this.setRectangle = function(gl, x, y, width, height) {
        var x1 = x;
        var x2 = x + width;
        var y1 = y;
        var y2 = y + height;
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
        x1, y1,
        x2, y1,
        x1, y2,
        x1, y2,
        x2, y1,
        x2, y2]), gl.STATIC_DRAW);
    }
}

1 个答案:

答案 0 :(得分:0)

好的,我设法让事情有效。 我必须了解在不同阶段需要调用的内容: Do I have to create separate buffers per webgl program?

我必须使用帧缓冲区更改部分,以使用与放入数据的纹理不同的纹理。

delete

所以sTexture需要像这样改变:

gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,  gl.TEXTURE_2D, sTexture, 0);
gl.activeTexture(gl.TEXTURE0 + 1);
gl.bindTexture(gl.TEXTURE_2D, sTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 
             sTexture.width, sTexture.height, 0,
             gl.RGBA, gl.UNSIGNED_BYTE, pixels);
相关问题