Доступен ли объект imageData CanvasPixelArray напрямую для контекста холста WebGL?

Я использую Three.js для рисования 3D-моделей на рендерере холста webgl над простыми элементами DOM, и мне нужно выполнить обнаружение столкновений между ними. В настоящее время мой рабочий метод заключается в использовании renderer.domElement.toDataURL(), загрузке его как объекта imageData, затем рисовании в отдельном контексте 2D-холста, затем извлечении массива пикселей getImageData() и повторении с использованием эта потрясающая функция столкновения пикселей.

Это невероятно медленно, и снижает частоту кадров до почти неиграбельных ~5-8 кадров в секунду. Без запуска этого обнаружения попаданий я получаю около 40-50 FPS.

Я думаю, что замедление связано с невероятно громоздкой функцией toDataURL()->load image->drawImage()->getImageData().

У меня возникает вопрос: Есть ли лучший способ получить доступ к сглаженным 2D-пиксельным данным, доступным на холсте WebGL? или, возможно, лучший метод экстраполяции координат моего 3D-объекта без параллакса? Честно говоря, любой способ получить какое-то обнаружение столкновений быстрее, чем я сейчас делаю, будет чрезвычайно полезен.

EDIT: WebGL context.readPixels() работает отлично для меня и очень быстро по сравнению с моим предыдущим кладжем. Хотя следует отметить, что массив данных зеркально отображается сверху вниз по сравнению с обычным массивом данных пикселей изображения. Я просто перевернул свою процедуру проверки значения Y при столкновении и заставил это работать, хотя другие могут споткнуться более хитрыми способами. Удачи!


person TechNinja    schedule 27.02.2012    source источник


Ответы (2)


Вы можете использовать gl.readPixels:

// Render your scene first then...
var left = 0;
var top = 0;
var width = canvas.width;
var height = canvas.height;
var pixelData = new Uint8Array(width * height * 4);
gl.readPixels(left, top, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixelData);

pixelData теперь содержит пиксельные данные сцены в виде байтов без знака (0-255), расположенных как [R, G, B, A, R, G, B, A...]. Должны быть те же данные, что и getImageData, но с гораздо меньшей стоимостью.

[ИЗМЕНИТЬ:]

Я забыл упомянуть, что если вы собираетесь это делать, вам нужно создать контекст WebGL с параметром preserveDrawingBuffer, например так:

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

Это предотвращает очистку буфера внутренней работой WebGL до того, как вы доберетесь до него (что приведет к чтению большого количества пустых пикселей). Включение этой опции может замедлить рендеринг, но он все равно должен загружаться быстрее, чем 5-8 кадров в секунду! :)

person Toji    schedule 28.02.2012
comment
Хороший! Я удивлен, что упустил это из виду раньше. Это работает, но... если вы отрисуете эти данные обратно на другой холст, чтобы посмотреть на них, они отобразятся сверху вниз! Можете ли вы придумать какой-нибудь простой способ перевернуть это? Я мог бы, вероятно, просто перевернуть Y в своей процедуре обнаружения столкновений... - person TechNinja; 29.02.2012
comment
Если вам нужен простой способ сохранения порядка, вы можете создать еще один холст. используйте первый как источник drawImage, а затем getImageData на временном. - person DARK_DUCK; 24.08.2016

 renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer:true });



 var gl = renderer.getContext()
 var buf = new Uint8Array(200 * 200 * 4);
 gl.readPixels(0, 0, 200, 200, gl.RGBA, gl.UNSIGNED_BYTE, buf);


console.log(buf);

это работает нормально.

person Ashkan Ghodrat    schedule 11.08.2013