webgl readpixels总是返回0,0,0,0

时间:2011-08-23 06:16:44

标签: javascript webgl

我正在尝试在WebGl中进行选择。我有两个渲染的形状,每个都映射了不同的纹理。我试图在某些坐标上抓取像素。这是一个例子。

var pixelValues = new Uint8Array(4);
gl.readPixels(10, 35, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixelValues);
console.log(pixelValues);

但是pixelValues总是包含[0,0,0,0]。我究竟做错了什么?我需要做一些与帧缓冲有关的事吗?

2 个答案:

答案 0 :(得分:13)

根据WebGL latest specs,您现在需要致电getContext设置preserveDrawingBuffer标记,例如:

var ctx = canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true});

这可以防止绘图缓冲区(颜色,深度,模板)在绘制到屏幕后被清除。请记住,这可能会导致性能下降。

答案 1 :(得分:8)

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

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

render
read

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

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("webgl");

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("webgl");

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. 在您的活动中再次渲染

    screenshotElement.addEventListener('click', event => {
      render();  
      gl.readPixels(...);
    });