从WebGL 3D画布中读取像素信息,返回所有[0, 0, 0, 255]。

4

我试图完成一个目标,即获取特定WebGL Web软件ArcGIS Scene Viewer的图像副本。它使用了一个画布(canvas),我尝试过以下方法:

    var canvas = document.getElementsByTagName("canvas")[0];
    var resultDOM = document.getElementById("result");
    resultDOM.innerText = canvas;
    var gl = canvas.getContext("webgl", {preserveDrawingBuffer: true});
    var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
    gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    console.log(pixels); // Uint8Array

但是控制台记录的数组总是充满了 [0, 0, 0, 255]。 所以我无法完全控制用于创建画布的 JSAPI,因此当第一次初始化 canvas 时,我不能设置 preserveDrawingBuffer: true。所有我能做的就是在 canvas 加载地图后执行一些JS。那么我该如何获取所需的图像呢? 我这里有问题吗?我也尝试过帧缓冲区,但它也不起作用:
canvas.addEventListener('click', function(ev) {
    var gl = canvas.getContext("webgl", {
      preserveDrawingBuffer: true
    });
    var framebuffer = gl.createFramebuffer();
    //insert code to get mouse x,y position on canvas
    var top = canvas.offsetTop;
    var left = canvas.offsetLeft;
    var x = ev.clientX - left;
    var y = ev.clientY - top;
    var pixels = new Uint8Array(4);
    gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
    gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    console.log(x, y, pixels);
});

返回的像素值也是[0, 0, 0, 0]。

以下是您可以尝试的示例:https://jsfiddle.net/qvtt87ky/ 它总是返回整个黑色图像。


https://developers.arcgis.com/javascript/latest/api-reference/esri-views-3d-externalRenderers.html - LJᛃ
如果WebGL上下文是由您无法控制的第三方库创建的,则可以更新HTMLCanvasElement.prototype.getContext以强制使用preserveDrawingBuffer: true。https://jsfiddle.net/w8cjdyr1/ - Mike
2个回答

4
如果您只需要网页GL画布的副本,最简单的方法是将网页GL画布绘制到离屏画布中,并使用CanvasRenderingContext2D提取像素数据。
var webglCanvas;

var offscreenCanvas = document.createElement("canvas");
offscreenCanvas.width = webglCanvas.width;
offscreenCanvas.height = webglCanvas.height;
var ctx = offscreenCanvas.getContext("2d");

ctx.drawImage(webglCanvas,0,0);
var imageData = ctx.getImageData(0,0, offscreenCanvas.width, offscreenCanvas.height);

console.log(imageData.data);

imageData.data是一个Uint8ClampedArray,包含你所需的像素数据。


这将得到与仅使用readPixels相同的结果 - 有时是真实的颜色,但通常只是[0, 0, 0, 255]。 - Doguleez

1

帧缓冲仅是附件的集合。您没有添加任何附件,因此您的帧缓冲未设置。

除此之外,如果您想从帧缓冲中读取某些内容,则必须将数据放入(渲染到)帧缓冲中。即使您添加了附件,您的示例代码也不会执行此操作。

示例:

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

// Clear the canvas to red
gl.clearColor(1, 0, 0, 1); // red
gl.clear(gl.COLOR_BUFFER_BIT);

// Make a framebuffer
var fb = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);

// Make a texture
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
var width = 1;
var height = 1;
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);

// Attach the texture to the framebuffer
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);

// Clear the texture to green
gl.clearColor(0, 1, 0, 1); // green
gl.clear(gl.COLOR_BUFFER_BIT);

var pixel = new Uint8Array(4);
// Read from texture (because it's attached to the current
// framebuffer
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
console.log("texture:", pixel);

// Read from canvas to show it's a different color
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
console.log("canvas:", pixel);
<canvas></canvas>

其他

这段代码对我来说毫无意义

var resultDOM = document.getElementById("result");
resultDOM.innerText = canvas;

将画布附加为innerText只意味着它将尝试将HTMLCanvasElement转换为字符串,这很可能只会打印出像[object HTMLCanvasElement]这样的内容,因此我不确定该代码想要做什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接