readPixels 函数返回未修改的纹理

Posted

技术标签:

【中文标题】readPixels 函数返回未修改的纹理【英文标题】:readPixels function returns not modified texture 【发布时间】:2013-07-13 00:02:50 【问题描述】:

我正在尝试将图像(作为纹理)绘制到帧缓冲区,应用清晰度过滤器(通过在 UI 上拖动滑块),然后从帧缓冲区读取结果并通过调用将数据复制到简单的 2d 画布(不是 webgl)使用绑定的帧缓冲区读取像素,获取像素数组并将它们复制到 ImageData.data,但该函数返回原始纹理。

也许有人可以向我解释一下,因为据我了解,屏幕上的东西实际上是帧缓冲区的内容。

抱歉有很多代码,但我希望它可以帮助理解我在做什么。

(function () 
  var anotherContext = null;
  var canvas = $("#canvas");

  main();
  setupCanvas();

  function setupCanvas () 
    anotherContext = document.getElementById("anothercanvas").getContext("2d");
  

  function main () 
    var image = new Image();
    image.src = "http://localhost:9292/img/ava.jpg";
    image.onload = function () 
      render(image);
    
  

  function render (image) 
    //-----get contexts----
    var canvas = document.getElementById('canvas');
    var gl = canvas.getContext('experimental-webgl');

    //----define shaders-----
    var vs = document.getElementById('vshader').textContent;
    var fs = document.getElementById('fshader').textContent;

    //----create program-----
    var program = createProgram(vs, fs);
    gl.useProgram(program);

    //----setup vertex data-----
    var positionLocation = gl.getAttribLocation(program, "a_position");
    var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");

    //----setup texture-----
    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);

    // Create a texture.
    var texture = createAndSetupTexture();
    // Upload the image into the texture.
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);

    //---framebuffer----
    var framebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
    var canRead = (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE);
    console.log("Can read: ", canRead);

    //----lookup uniforms and set the resolution-----
    var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
    var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
    var kernelLocation = gl.getUniformLocation(program, "u_kernel[0]");

    gl.uniform2f(textureSizeLocation, image.width, image.height);

    //----kernels-----
    var kernel = [
       0, 0, 0,
       0, 1, 0,
       0, 0, 0
    ];

    var sharpnessKernel = [
       0,-1, 0,
      -1, 5, -1,
       0,-1, 0
    ];

    //-----bind buffer------
    var vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.enableVertexAttribArray(positionLocation);
    gl.vertexAttribPointer(program.vertexPosAttrib, 2, gl.FLOAT, false, 0, 0);

    setRectangle(gl, 0, 0, image.width, image.height);

    draw(kernel);

    function draw (krn) 
      // gl.bindTexture(gl.TEXTURE_2D, texture);

      setFramebuffer(framebuffer);
      drawWithKernel(krn);

      copyImage();

      // gl.bindTexture(gl.TEXTURE_2D, texture);
      setFramebuffer(null);

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

    function setFramebuffer (fbuf) 
      gl.bindFramebuffer(gl.FRAMEBUFFER, fbuf);

      gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

      gl.viewport(0, 0, canvas.width, canvas.height);
    

    function drawWithKernel (kernel) 
      gl.uniform1fv(kernelLocation, kernel);

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

    function createAndSetupTexture () 
      var texture = gl.createTexture();
      gl.bindTexture(gl.TEXTURE_2D, texture);

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

      return texture;
    

    function setRectangle (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);
    

    function createShader(str, type) 
      var shader = gl.createShader(type);

      gl.shaderSource(shader, str);
      gl.compileShader(shader);

      return shader;
    

    function createProgram (vstr, fstr) 
      var program = gl.createProgram();
      var vshader = createShader(vstr, gl.VERTEX_SHADER);
      var fshader = createShader(fstr, gl.FRAGMENT_SHADER);

      gl.attachShader(program, vshader);
      gl.attachShader(program, fshader);
      gl.linkProgram(program);

      return program;
    

    function copyImage () 
      var pixels = new Uint8Array(image.width * image.height * 4);
      gl.readPixels(0, 0, image.width, image.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);

      var imageData = anotherContext.createImageData(image.width, image.height);
      for (var i = pixels.length - 1; i >= 0; i--) 
        imageData.data[i] = pixels[i];
      ;

      // console.log(imageData.data);
      anotherContext.putImageData(imageData, 0, 0);
    

    $("#slider").slider(
      min: 0,
      max: 99,
      slide: function (event, ui) 
        var currentKernel = null;

        //do not use any filtering if slider is on 0 position
        if(ui.value == 0) 
          currentKernel = kernel;
        
        else 
          currentKernel = sharpnessKernel.slice(0);
          currentKernel[4] -= (ui.value / 100);
        

        draw(currentKernel);
      
    );
  
)()

【问题讨论】:

只是一个快速的建议(我要上床了):在将纹理附加到帧缓冲区对象之前取消绑定。关于帧缓冲区的纹理绑定和附加状态有一些规则,这些规则禁止对帧缓冲区进行操作。最简单的部分是取消绑定纹理:bindTexture(…, 0); - 但是在您的情况下,渲染缓冲区可能更适合作为附件,即纹理。 to datenwolf - 这也不起作用。 【参考方案1】:

您当前的函数和括号设置已完全损坏,这也表明您没有使用firebug 或任何其他web-console 来调试您的javascript

首先,您应该将一些函数移到主函数之外并获得modern editor,因为它们中的大多数都有显示属于一起的括号的方法。

编辑:看起来类似于来自WebGL fundamentals 的代码。回答您的问题:仅当绑定的帧缓冲区为空时(您可以在该站点上阅读),您才会在屏幕上绘图。

无论如何,您可能会在这个方面得到帮助:Creating texture from getImageData (Javascript) 或可能是 fabric.js image filters

【讨论】:

请指出损坏的地方。代码有点乱,但它是一种概念证明,并且有效。顺便说一句,我正在使用 chrome dev。工具和 sublime 文本编辑器 - 突出显示括号没有问题。 投反对票的答案对您没有帮助,如果您手头有这些工具,请使用它们!保持代码有序是编程的一半,它实际上应该可以解决您的问题,在您当前的代码中,浏览器会在执行任何代码之前退出,因为该代码无效。 您能告诉我您认为代码中的哪些问题吗?否则你的答案根本不相关,与阅读帧缓冲区的内容无关。 一旦代码中的右括号与左括号不匹配,它们需要按照打开时的顺序关闭。同样如前所述,您应该将功能移出主要功能,以提高编码器和浏览器的可读性。只要您正在测试,您就可以(并且应该)使用全局变量和函数,即使您想封装功能,也可以使用classes。将所有内容都放在一个函数中可能会起作用,但这是一种不好的做法,并且代码越长,您就会遇到更多问题。 看,这根本不是生产代码。感谢您告诉我最佳实践,但这并不重要,因为我只需要查看原型是否正常工作。括号匹配并且代码工作正常,除了帧缓冲区有问题。请,如果您对实际问题没有什么要说的,请不要向问题发送垃圾邮件。

以上是关于readPixels 函数返回未修改的纹理的主要内容,如果未能解决你的问题,请参考以下文章

SpriteKit 示例游戏错误:纹理未加载?

片段着色器中未使用纹理数据 - OpenGL

Amazon CloudFront 未针对未更改的静态内容始终返回 304(未修改)?

CORS 尝试,php 未修改响应标头

python urllib2.request.add_header 未返回 HTTP 错误 304(未修改)异常

为啥在关闭/打开应用程序后未保存的修改后的 NSManagedObject 在 isUpdated 上返回 FALSE?