你不需要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 个选项
放preserveDrawingBuffer: true
在您的活动中再次渲染
screenshotButton.addEventListener('click', () => {
render();
read();
});
来自规范第 2.2 节
WebGL 在合成操作之前立即将其绘图缓冲区呈现给 HTML 页面合成器,但前提是自上一次合成操作以来至少发生了以下情况之一:
- 上下文创建
- 画布调整大小
- 当绘图缓冲区是当前绑定的帧缓冲区时,已调用 clear、drawArrays 或 drawElements
在呈现绘图缓冲区以进行合成之前,实现应确保所有渲染操作都已刷新到绘图缓冲区。默认情况下,合成后绘图缓冲区的内容将被清除为其默认值,如上表所示。
可以通过设置 WebGLContextAttributes 对象的 preserveDrawingBuffer 属性来更改此默认行为。如果此标志为真,则绘图缓冲区的内容将被保留,直到作者清除或覆盖它们。如果此标志为 false,则在渲染函数返回后尝试使用此上下文作为源图像执行操作可能会导致未定义的行为。这包括 readPixels 或 toDataURL 调用,或将此上下文用作另一个上下文的 texImage2D 或 drawImage 调用的源图像。