我正在尝试在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]。我究竟做错了什么?我需要做一些与帧缓冲有关的事吗?
答案 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个选项
设置preserveDrawingBuffer: true
在您的活动中再次渲染
screenshotElement.addEventListener('click', event => {
render();
gl.readPixels(...);
});