WebGL 2何时清除绘图缓冲区?

时间:2017-06-12 23:45:06

标签: webgl2

我目前正致力于调用readPixels的演示。

This answer on SO是我在preserveDrawingBuffer选项中可以找到的大部分信息。

在测试过程中,我发现在WebGL 2中this answer仍然存在 - 您必须将preserveDrawingBuffer设置为true

这实际上是对的吗?

是否有preserveDrawingBuffer的OpenGL等效项?

有没有办法将preserveDrawingBuffer设置为false并仍然调用readPixels?

This answer让您觉得可以拨打gl.flush

如何将preserveDrawingBuffer与刷新上下文相同?

1 个答案:

答案 0 :(得分:1)

您不需要preserveDrawingBuffer: true来致电readPixels。您需要的是在退出当前事件之前调用readPixels

规范说如果你调用影响画布的任何函数(gl.clear,gl.drawXXX),那么浏览器将在下一次复合操作后清除画布。当复合操作发生时,由浏览器决定。可能是在它处理了几个鼠标事件或键盘事件或点击事件之后。订单未定义。定义的是,在当前事件退出之前它不会这样做

render
read

const gl = document.querySelector("canvas").getContext("webgl2");

render();
read();  // read in same event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

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

适用于

render
setTimeout(read, 1000);  // some other event

不起作用

const gl = document.querySelector("canvas").getContext("webgl2");

render();
setTimeout(read, 1000);  // read in other event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

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

请注意,因为它是复合操作(浏览器实际上在页面上绘制画布,其余的HTML)触发清除,如果画布不在页面上,那么它不会被合成,也不会被清除

换句话说,上面没有工作的情况可以在这里工作

// create an offscreen canvas. Because it's offscreen it won't be composited
// and therefore will not be cleared.
const gl = document.createElement("canvas").getContext("webgl2");

render();
setTimeout(read, 1000);  // read in other event

function render() {
  gl.clearColor(.25, .5, .75, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
}

function read() {
  const pixel = new Uint8Array(4);
  gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
  log(pixel);
}

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

如果您想在其他事件中调用readPixels,例如当用户点击某个元素时,您至少有2个选项

  1. 设置preserveDrawingBuffer: true

  2. 在您的活动中再次渲染

    screenshotButton.addEventListener('click', () => {
       render();
       read();
    });
    
  3. 来自the spec section 2.2

      

    WebGL在合成操作之前立即向HTML页面合成器提供其绘图缓冲区,但前提是自上一次合成操作后至少发生以下一种情况:

         
        
    • 上下文创建
    •   
    • Canvas resize
    •   
    • clear,drawArrays或drawElements已被调用,而绘图缓冲区是当前绑定的帧缓冲区
    •   
         

    在绘制缓冲区用于合成之前,实现应确保所有渲染操作都已刷新到绘图缓冲区。默认情况下,合成后,绘图缓冲区的内容应清除为默认值,如上表所示。

         

    可以通过设置WebGLContextAttributes对象的preserveDrawingBuffer属性来更改此默认行为。如果此标志为true,则应保留绘图缓冲区的内容,直到作者清除或覆盖它们为止。如果此标志为false,则在返回呈现函数后尝试使用此上下文作为源图像执行操作可能会导致未定义的行为。这包括readPixels或toDataURL调用,或使用此上下文作为另一个上下文的texImage2D或drawImage调用的源图像。