【问题标题】:webGL 2 readPixels on framebuffers with FLOAT textures带有 FLOAT 纹理的帧缓冲区上的 webGL 2 readPixels
【发布时间】:2018-01-16 05:03:17
【问题描述】:

是否可以将像素值作为具有多个附件的帧缓冲区上的浮点数检索? (WebGL 2)

我试过这个:

var framebuffer = _gl.createFramebuffer();

_gl.bindFramebuffer(_gl.FRAMEBUFFER, framebuffer);

_gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, texture1, 0);
_gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT1, _gl.TEXTURE_2D, texture2, 0);

_gl.drawBuffers([_gl.COLOR_ATTACHMENT0, _gl.COLOR_ATTACHMENT1]);

浮动纹理设置如下:

_gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.RGBA32F, 256, 256, 0, _gl.RGBA, _gl.FLOAT, null);

然后我绑定帧缓冲区并调用 readPixels 来获取第一个附件的值:

_gl.readPixels(0, 0, 1, 256, _gl.RGBA, _gl.FLOAT, 0);

没有浮动纹理,这项工作但有浮动纹理,帧缓冲区保持不完整。

WebGL 2 规范似乎说这应该可以工作,但我现在有一些疑问,似乎 _gl.RGBA32F 似乎是问题所在,内部格式为 _gl.RGBA,它会产生不兼容的类型错误。

【问题讨论】:

  • "framebuffer保持不完整" framebuffer不完整的具体原因是什么?帧缓冲区完整性有很多失败的原因。
  • 我正在使用github.com/vorg/webgl-debug 并且没有抛出错误,但是 checkFramebufferStatus 函数仍然报告它不完整,没有浮点数,使用相同的调用但使用不同的参数(_gl .RGBA 用于内部格式,_gl.UNSIGNED_BYTE 用于格式)。
  • "checkFramebufferStatus 函数报告它不完整" 不,它没有。它报告帧缓冲区不完整的特定原因。我问你想要那个原因。
  • 确实,它报告了一个不完整的附件。

标签: javascript webgl2


【解决方案1】:

首先,渲染到浮点需要 WebGL2 中的扩展,EXT_color_buffer_float

您可以在从spec section 3.8.3.2 复制的table here 中看到,浮点纹理默认情况下在 WebGL2 中是不可渲染的。

否则你调用gl.readBuffer来设置缓冲区在调用gl.readPixels之前读取

例子:

function main() {
  const gl = document.createElement("canvas").getContext("webgl2");
  if (!gl) {
    alert("need WebGL2");
    return;
  }
  const ext = gl.getExtension("EXT_color_buffer_float");
  if (!ext) {
    alert("need EXT_color_buffer_float");
    return;
  }
  
  const tex1 = createTexture(gl, [12, 0, 0, 34]);
  const tex2 = createTexture(gl, [0, 56, 78, 0]);
  
  const fb = gl.createFramebuffer();
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex1, 0);

  gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT1, gl.TEXTURE_2D, tex2, 0);

  gl.drawBuffers([gl.COLOR_ATTACHMENT0, gl.COLOR_ATTACHMENT1]);
  
  readPixelsFromBuffer(gl, gl.COLOR_ATTACHMENT0);
  readPixelsFromBuffer(gl, gl.COLOR_ATTACHMENT1);
}

function readPixelsFromBuffer(gl, attachment) {
  gl.readBuffer(attachment);
  const data = new Float32Array(4);
  const x = 0;
  const y = 0;
  const width = 1;
  const height = 1;
  const format = gl.RGBA;
  const type = gl.FLOAT;
  gl.readPixels(x, y, width, height, format, type, data);
  log(glEnumToString(gl, attachment), data);
}

function createTexture(gl, color) {
  const tex = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, tex);
  const level = 0;
  const internalFormat = gl.RGBA32F;
  const width = 1;
  const height = 1;
  const border = 0;
  const format = gl.RGBA;
  const type = gl.FLOAT;
  const data = new Float32Array(color);
  gl.texImage2D(gl.TEXTURE_2D, level, internalFormat, width, height, border,
                format, type, data);
  // unless we get `OES_texture_float_linear` we can not filter floating point
  // textures
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  
  return tex;
}

function glEnumToString(gl, value) {
  for (let key in gl) {
    if (gl[key] === value) {
      return key;
    }
  }
  return `0x${value.toString(16)}`;
}

function log(...args) {
  const elem = document.createElement("pre");
  elem.textContent = [...args].join(' ');
  document.body.appendChild(elem);
}

main();

【讨论】:

  • 一次从第一个缓冲区读取,再次从第二个缓冲区读取。
  • 抱歉,我知道这可能会造成混淆。我编辑了函数名称。希望现在不再那么混乱
  • 谢谢你,这项工作并从该代码中学到了一些东西,我不知道需要 EXT_color_buffer_float。
猜你喜欢
  • 2014-12-05
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 2012-07-26
  • 2018-04-13
  • 1970-01-01
  • 2015-03-26
  • 1970-01-01
相关资源
最近更新 更多