webgl readpixels всегда возвращает 0,0,0,0 - PullRequest
13 голосов
/ 23 августа 2011

Я пытаюсь сделать сбор в 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 ]

13 голосов
/ 25 августа 2011

В соответствии с последними спецификациями WebGL , теперь вам нужно позвонить getContext, установив флаг preserveDrawingBuffer, например:

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

это предотвращает очистку буфера рисования (цвет, глубина, трафарет) после их рисования на экране. Имейте в виду, что настройки могут привести к снижению производительности.

8 голосов
/ 14 июня 2017

Вам не нужно 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);
}
* * 1010

работает где

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(...);
    });
    
...