Javascript webgl readpixels纹理着色器问题

Javascript webgl readpixels纹理着色器问题,javascript,glsl,textures,webgl,shader,Javascript,Glsl,Textures,Webgl,Shader,我一直在尝试学习一些webgl,基本上有两个程序,其中渲染的像素存储在纹理中,然后在另一个程序的着色器中使用 webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]); 这将调用并尝试读取屏幕像素,并将修改后的数据放回纹理中,以便在下一个程序渲染例程中使用 我得到的只是一个逐渐变得更透明的黑屏,但也应该看到u_图像(因为这是在第一个程序中渲染的,其中像素是用readpixels读取的) 如果我注释掉第二个程序的渲染: gl

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

webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);
这将调用并尝试读取屏幕像素,并将修改后的数据放回纹理中,以便在下一个程序渲染例程中使用

我得到的只是一个逐渐变得更透明的黑屏,但也应该看到u_图像(因为这是在第一个程序中渲染的,其中像素是用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_图像而不进行任何褪色。 所以我不确定问题出在哪里。似乎它没有正确读取像素?但是,如果是这样的话,为什么衰落会起作用呢?尝试使用这两种纹理是否有问题

希望有人能看看代码,看看可能是什么问题

//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);
    }
}
//webgl的东西
var webgl=新的webglData();
函数webglData(){
this.then=0;//用于渲染中的deltatime
this.request;//requestanimationframe,在停止/启动时使用
这是帆布;
这就是背景;
这个.div;
这个项目;
这是一个很好的计划;
this.texture=[];
this.frameBuffer=[];
this.cellVShader=`
属性向量2;
属性向量2 a_位置;
属性向量2 a_texCoord;
均匀vec2u_分辨率;
可变矢量2 v_texCoord;
可变矢量2 v_NW;
可变矢量2 v_N;
可变矢量2;
可变向量2 v_W;
可变向量2 v_E;
可变vec2 v_SW;
可变vec2v_;
可变vec2电压;
vec2 getOffset(整数x,整数y){
vec2 v=地板(a_-texCoord*u_分辨率);
v、 x+=浮点数(x),v.y+=浮点数(y);
v/=u_分辨率;
返回v;
}
void main(){
//v_texCoord=a_texCoord;
//gl_位置=vec4(0.0,1.0);
//将矩形从像素转换为0.0到1.0
vec2 zeroToOne=a_位置/u_分辨率;
//从0->1转换为0->2
vec2 zeroToTwo=zeroToOne*2.0;
//从0->2转换为-1->+1(剪辑空间)
vec2 clipSpace=zeroToTwo-1.0;
gl_Position=vec4(clipSpace*vec2(1,-1),0,1);
//将texCoord传递给片段着色器
//GPU将在点之间插值该值。
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=`
#国际财务报告准则
高精度浮点;
#恩迪夫
均匀采样2D u_画布1;
均匀的维柯色;
//我们的质地
前2D u_均匀采样;
均匀采样2D u_后;
均匀采样二维u_图像;
//从顶点着色器传入的texCoords。
可变矢量2 v_texCoord;
可变矢量2 v_NW;
可变矢量2 v_N;
可变矢量2;
可变向量2 v_W;
可变向量2 v_E;
可变vec2 v_SW;
可变vec2v_;
可变vec2电压;
void main(){
//从纹理中查找颜色。
gl_FragColor=纹理2D(u_图像,v_W);
//gl_FragColor=uColor;
}
`;
this.vertexShader=`
属性向量2;
属性向量2 a_位置;
属性向量2 a_texCoord;
均匀vec2u_分辨率;
可变矢量2 v_texCoord;
void main(){
//v_texCoord=a_texCoord;
//gl_位置=vec4(0.0,1.0);
//将矩形从像素转换为0.0到1.0
vec2 zeroToOne=a_位置/u_分辨率;
//从0->1转换为0->2
vec2 zeroToTwo=zeroToOne*2.0;
//从0->2转换为-1->+1(剪辑空间)
vec2 clipSpace=zeroToTwo-1.0;
gl_Position=vec4(clipSpace*vec2(1,-1),0,1);
//将texCoord传递给片段着色器
//GPU将在点之间插值该值。
v_texCoord=a_texCoord;
}
`;
this.fragmentShader=`
#国际财务报告准则
高精度浮点;
#恩迪夫
均匀采样2D u_画布1;
均匀的维柯色;
//我们的质地
前2D u_均匀采样;
均匀采样2D u_后;
均匀采样二维u_图像;
//从顶点着色器传入的texCoords。
可变矢量2 v_texCoord;
void main(){
//从纹理中查找颜色。
gl_FragColor=纹理2d(u_before,v_texCoord);
//gl_FragColor=uColor;
}
`;
this.init=函数(){
this.div=innerDoc.getElementById('webglDiv');
gui.Window.get().showDevTools();
this.canvas=document.createElement('canvas');
this.context=this.canvas.getContext(“实验性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);
如果(!this.context)返回;
var gl=this.context;
总图视口(0,0,this.canvas.width,this.canvas.height);
gl.clearColor(0,0.5,0,1);
总账清除(总账颜色缓冲位);
//编译着色器并为webgl创建程序
var vs=gl.createShader(gl.VERTEX\u着色器);
gl.shaderSource(vs,this.vertexShader);
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);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,  gl.TEXTURE_2D, someOtherTexture, 0);