我想从Three.js演示中获取像素数据。 据我所知,有两种方法可以继续:
1)在2D画布中绘制webGl-canvas并使用Context2D.getImageData:
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(renderer.domElement,0,0);
var data = ctx.getImageData(0,0,w,h).data;
2)直接使用带有readPixels的context3D,如:
var ctx = renderer.domElement.getContext("webgl");
var data = new UInt8Array(w*h*4);
ctx.readPixels(0, 0, w,h, ctx.RGBA, ctx.UNSIGNED_BYTE, data);
这两种方式继续工作并给出相同的结果,但第二种方法几乎比使用context2d.getImageData的方式慢2倍。
听起来很奇怪。如何将3D内容绘制到2D画布中比直接使用context3D更快?我不明白,我几乎可以肯定我没有正确使用gl.readPixels。
然后我的问题是:如何使用gl.readPixels比context2d.drawImage + context2d.getImageData更快?
我试着像那样使用Float32Array
var ctx = renderer.domElement.getContext("webgl");
var data = new Float32Array(w*h*4);
ctx.readPixels(0, 0, w,h, ctx.RGBA, ctx.FLOAT, data);
我认为它应该更快,因为没有从Float到UInt8的转换,但它看起来不像那样,因为我的'data'数组在调用ctx.readPixels之后保持空白
感谢您的帮助!
(请原谅我,如果我的英语不完美,那不是我的母语)
答案 0 :(得分:2)
在我的机器上,我得到的readPixels比drawImage / getImageData快2到20倍。在MacOS Chrome,Firefox,Windows 10 Chrome和Firefox上进行了测试。 Safari出现readPixels速度较慢。听起来像Safari中的一个错误,实际上正如预期的那样检查Safari Technology Preview Release 46,readPixels比drawImage / getImageData快3到1.2倍
const gl = document.createElement("canvas").getContext("webgl");
const ctx = document.createElement("canvas").getContext("2d");
const w = 512;
const h = 512;
gl.canvas.width = w;
gl.canvas.height = h;
ctx.canvas.width = w;
ctx.canvas.height = h;
const readPixelBuffer = new Uint8Array(w * h * 4);
const tests = [
{ fn: withReadPixelsPreAlloc, msg: "readPixelsPreAlloc", },
{ fn: withReadPixels, msg: "readPixels", },
{ fn: withDrawImageGetImageData, msg: "drawImageGetPixels", },
];
let ndx = 0;
runNextTest();
function runNextTest() {
if (ndx >= tests.length) {
return;
}
const test = tests[ndx++];
// use setTimeout to give the browser a change to
// do something between tests
setTimeout(function() {
log(test.msg, "iterations in 5 seconds:", runTest(test.fn));
runNextTest();
}, 0);
}
function runTest(fn) {
const start = performance.now();
let count = 0;
for (;;) {
const elapsed = performance.now() - start;
if (elapsed > 5000) {
break;
}
fn();
++count;
}
return count;
}
function withReadPixelsPreAlloc() {
gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, readPixelBuffer);
}
function withReadPixels() {
const readPixelBuffer = new Uint8Array(w * h * 4);
gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, readPixelBuffer);
}
function withDrawImageGetImageData() {
ctx.drawImage(gl.canvas, 0, 0);
ctx.getImageData(0, 0, w, h);
}
function log(...args) {
const elem = document.createElement("pre");
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
对于转换为float,画布本身以字节存储。没有转换为浮动,您可能会出现GL错误
const gl = document.createElement("canvas").getContext("webgl");
const buf = new Float32Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, buf);
log("ERROR:", glEnumToString(gl, gl.getError()));
function log(...args) {
const elem = document.createElement("pre");
elem.textContent = [...args].join(' ');
document.body.appendChild(elem);
}
function glEnumToString(gl, val) {
if (val === 0) { return 'NONE'; }
for (key in gl) {
if (gl[key] === val) {
return key;
}
}
return `0x${val.toString(16)}`;
}
检查控制台我看到错误是
WebGL: INVALID_ENUM: readPixels: invalid type