2017-06-12 30 views
0

我目前正在致电readPixels的演示。WebGL 2何时清除绘图缓冲区?

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

在测试过程中我观察到在WebGL 2中this answer保持不变 - 您必须将preserveDrawingBuffer设置为true

这是真的吗?

是否有一个等效于preserveDrawingBuffer的OpenGL?

有什么办法可以将preserveDrawingBuffer设置为false而仍然调用readPixels?

This answer使它看起来像你可以改为gl.flush

preserveDrawingBuffer与刷新上下文是一样的吗?

回答

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其余页面上的帆布)触发清楚,如果画布不是页面,则它不会合成并赢得了不会被清除。

换句话说,如果你想调用readPixels在其他一些情况下是没有上述工作的情况下就在这里工作

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

,当用户点击一个元素一样,那么你至少有2个选项

  1. preserveDrawingBuffer: true

  2. 在事件再次渲染

    screenshotButton.addEventListener('click',() => { 
        render(); 
        read(); 
    }); 
    

the spec section 2.2

WebGL的介绍其绘制缓冲区到HTML页面合成立即合成操作之前,但只有当至少有一个从以前的合成操作开始发生以下情况:

  • 上下文创建
  • 帆布调整
  • 清晰,drawArrays,或drawElements被称为同时绘制缓冲区是当前绑定的帧缓冲区

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

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

+0

梦幻般的答案。我假设,即使'preserveDrawingBuffer'设置为'true'合成需要发生。所以。如何将它设置为'true'允许'readPixels'以“定义”或一致的方式工作? – Startec

+1

@Startec gman有另外一个很好的答案:https://stackoverflow.com/a/27747016/3190758基本上它的“定义”在于绘图缓冲区不会被清除为默认值,而是被复制到显示缓冲区每次(可能以某些性能为代价,因为绘图和显示缓冲区不能再被交换) – grovesNL