2016-02-19 202 views
0

我一直在試圖學習一些webgl,基本上有兩個程序渲染像素存儲在紋理中,然後在其他程序的着色器中使用。webgl readpixels紋理着色器問題

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

這將調用,並嘗試在屏幕的readpixels,並把修改後的數據返回到紋理在接下來的程序中使用的渲染程序。

我得到的只是一個逐漸變得更加透明的黑色屏幕,但是也應該看到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); 
    } 
} 

回答

0

好吧,我設法讓事情奏效。 我必須學會在不同的階段被稱爲究竟需要: Do I have to create separate buffers per webgl program?

我曾與幀緩衝改變部分使用不同質地比它是將數據放入。

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); 

所以sTexture需要改變,像這樣:

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