为什么gl.readPixels从Firefox给出全0?

yon*_*ran 5 firefox opengl-es webgl

我正在使用WebGL运行一些图像处理(类似于Brad Larson的GPUImage或教程WebGL基础),然后执行消耗像素的CPU步骤。不幸的是,当我调用时gl.readPixels,Firefox中的缓冲区全为黑色。为什么?

这是一个独立的示例:http : //jsfiddle.net/yonran/8C3n5/在Chrome中,结果是“在帧缓冲区中,有924个黑色像素和100个蓝色像素”,而在Firefox中,结果是:“ Within帧缓冲区,有1024个黑色像素和0个蓝色像素。”

这就是我设置帧缓冲区的方法:

function createTextureAndFramebuffer(gl, width, height) {
  var outputTexture = createAndSetupTexture(gl);
  // Make the texture the same size as the image.
  gl.bindTexture(gl.TEXTURE_2D, outputTexture);
  gl.texImage2D(
      gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0,
      gl.RGBA, gl.UNSIGNED_BYTE, null);
  gl.bindTexture(gl.TEXTURE_2D, null);

  // create a framebuffer
  var fbo = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
  // attach a texture to it.
  gl.framebufferTexture2D(
      gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, outputTexture, 0);
  return {texture: outputTexture, framebuffer: fbo};
}
function createAndSetupTexture(gl) {
  var texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);

  // Set up texture so we can render any size image and so we are
  // working with pixels.
    // This is necessary for non-power-of-two textures
  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;
}
Run Code Online (Sandbox Code Playgroud)

这就是我绘制到帧缓冲区的方法:

ImageFilter.prototype = {
  ...,
  draw: function() {
    var gl = this.gl;
    // Use the texture
    gl.bindTexture(gl.TEXTURE_2D, this.texture);

    // make this the framebuffer we are rendering to.
    gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    // Tell webgl the viewport setting needed for framebuffer.
    gl.viewport(0, 0, this.outputWidth, this.outputHeight);

    gl.useProgram(this.program);
    this.applyUniforms();

    // Draw the rectangle.
    gl.drawArrays(gl.TRIANGLES, 0, 6);
    gl.flush();
  },
  vertexShaderString:
      "attribute vec4 position;\n" +
      "attribute vec4 inputTextureCoordinate;\n" +
      "\n" +
      "varying vec2 textureCoordinate;\n" +
      "\n" +
      "void main()\n" +
      "{\n" +
      "     gl_Position = position;\n" +
      "     textureCoordinate = inputTextureCoordinate.xy;\n" +
      "}\n",
  fragmentShaderString:
      "varying highp vec2 textureCoordinate;\n" +
      "\n" +
      "uniform sampler2D inputImageTexture;\n" +
      "\n" +
      "void main()\n" +
      "{\n" +
      "  gl_FragColor = texture2D(inputImageTexture, textureCoordinate);\n" +
      "}\n"
};
Run Code Online (Sandbox Code Playgroud)

然后我像这样从帧缓冲区中读取:

gl.bindFramebuffer(gl.FRAMEBUFFER, imageFilter.framebuffer);
var width = imageFilter.outputWidth, height = imageFilter.outputHeight;
var array = new Uint8ClampedArray(width * height * 4);
gl.finish();
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, array);
var blackPixels = 0, bluePixels = 0;
var firstBlueX, firstBlueY;
for (var y = 0; y < height; y++) {
  for (var x = 0; x < width; x++) {
    var idx = 4*(x + y*width);
    var r = array[idx], g = array[idx+1], b = array[idx+2], a = array[idx+3];
    if (r === 0 && g === 0 && b === 0)
      blackPixels++;
    else if (b === 255) {
      bluePixels++;
      if (firstBlueX == null) {
        firstBlueX = x;
        firstBlueY = y;
      }
    }
  }
}
var el = document.createElement("div");
document.body.appendChild(el);
el.textContent = "The first canvas is drawn to a framebuffer and then drawn again on the second canvas. " +
  "Within the framebuffer, there are " + blackPixels + " black pixels and " +
  bluePixels + " blue pixels The first blue pixel is at (" + firstBlueX+ "," + firstBlueY + ") " +
  "(origin is at bottom left).";
Run Code Online (Sandbox Code Playgroud)

我以为这可能是同步问题,但是在阅读前添加gl.finish()setTimeout没有帮助。搜索时,我发现多重采样会导致帧缓冲区为0,但是antialias: falsecanvas.getContext调用中进行设置并没有帮助。

编辑:我只是尝试在之前设置像素readPixels,而Firefox并没有取消设置像素。也许readPixels尚未实施,并且从14.0.1开始为空?

fuz*_*zic 2

有问题的行在这里:

var array = new Uint8ClampedArray(width * height * 4);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, array);
Run Code Online (Sandbox Code Playgroud)

当您指定类型时,GL_UNSIGNED_BYTE您必须传入正确类型的数组,否则 FF 会失败。这里正确的类型是Uint8Array, 不是Uint8ClampedArray

如果您检查 FF 控制台日志,您将看到以下错误消息,可通过交换这些数组类型来解决:

Error: WebGL: readPixels: Mismatched type/pixels types
Run Code Online (Sandbox Code Playgroud)