【问题标题】:webgl readpixels is always returning 0,0,0,0webgl readpixels 总是返回 0,0,0,0
【发布时间】:2021-01-12 23:19:18
【问题描述】:

我正在尝试在 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]。我究竟做错了什么?我需要做一些与帧缓冲区相关的事情吗?

【问题讨论】:

    标签: javascript webgl


    【解决方案1】:

    您无需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 个选项

    1. 设置preserveDrawingBuffer: true

    2. 在您的活动中再次渲染

      screenshotElement.addEventListener('click', event => {
        render();  
        gl.readPixels(...);
      });
      

    【讨论】:

    • 如果我们使用没有preserveDrawingBuffer: true 的上下文进行渲染,然后通过设置preserveDrawingBuffer: true 从同一画布中获取另一个上下文并获取像素,那么后者readPixels 是否可以工作?第二个上下文的新配置对第一个上下文有影响吗?我希望它们是相同的对象。对吗?
    • 您无法从同一画布中获取具有不同属性的第二个上下文。第二次调用 getContext 将返回与第一次调用相同的上下文,并且设置将保持与第一次调用相同
    【解决方案2】:

    根据WebGL specs,需要调用getContext设置preserveDrawingBuffer标志,如:

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

    如果您打算在退出呈现 GL 上下文的事件后读取像素。这可以防止绘图缓冲区(颜色、深度、模板)在绘制到屏幕后被清除。请记住,这可能会导致性能下降。

    或者,您可以在像素出现之前读取它们,这也应该可以。

    【讨论】:

    • 这是错误的:(
    • 它不完整,我同意。已修复以包含替代方案。
    猜你喜欢
    • 1970-01-01
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多