【问题标题】:Reading From WebGL Canvas Seems To Work Inconsistently [duplicate]从 WebGL Canvas 读取似乎不一致[重复]
【发布时间】:2021-04-21 10:07:06
【问题描述】:

我遇到了一个非常奇怪的情况,我试图从 WebGL 画布中读取像素,但没有成功。然后我写了同一个程序的另一个版本,只是没有类,并且由于某种原因它在这里工作。也许我犯了一些非常基本的错误,但我真的无法发现这两者之间的(语义)差异。

在下面的 sn-p 中,我(Linux 5.11.15-arch1-2 上的 Firefox 88.0)看到控制台打印 128 和 0,128 源于类之外的代码,这似乎是正确的,作为着色器为每个像素和通道绘制 0.5,而 0 源于类内的代码。

[编辑] 我已经看到this 的问题,但他们说读取必须与抽签发生在同一事件中,据我所知,这对于我的两种情况都是正确的(两个连续行)。他们还在谈论屏幕上的画布,而我渲染到帧缓冲区时,不确定这是否会有所不同,但我认为帧缓冲区更持久。

class Gpgpu {
  constructor(w, h, vs, fs, ans, uns) {
    this.gl = document.createElement("canvas").getContext("webgl");
    this.gl.canvas.width = w;
    this.gl.canvas.height = h;
    this.gl.viewport(0, 0, w, h);
    this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.gl.createFramebuffer());
    this.out = new Uint8Array(w * h * 4);
  }
  spg(vs, fs, ans, uns) {
    let p = this.gl.createProgram();
    for (let ss of [
      { t: this.gl.VERTEX_SHADER, d: vs },
      { t: this.gl.FRAGMENT_SHADER, d: fs }
    ]) {
      let s = this.gl.createShader(ss.t);
      this.gl.shaderSource(s, ss.d);
      this.gl.compileShader(s);
      this.gl.attachShader(p, s);
    }
    this.gl.linkProgram(p);
    this.gl.useProgram(p);
    this.als = {};
    for (let an of ans) {
      this.als[an] = {
        l: this.gl.getAttribLocation(p, an),
        b: this.gl.createBuffer()
      };
    }
    this.uls = {};
    for (let un of uns) {
      this.uls[un] = this.gl.getUniformLocation(p, un);
    }
  }
  sad(n, ads) {
    this.n = n;
    for (let an in ads) {
      let al = this.als[an];
      let ad = ads[an];
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, al.b);
      this.gl.bufferData(
        this.gl.ARRAY_BUFFER,
        Float32Array.from(ad),
        this.gl.STATIC_DRAW
      );
      this.gl.enableVertexAttribArray(al.l);
      this.gl.vertexAttribPointer(al.l, 2, this.gl.FLOAT, false, 0, 0);
    }
  }
  drw() {
    this.gl.drawArrays(this.gl.TRIANGLES, 0, this.n);
  }
}

class Cloth {
  constructor(w, h) {
    this.gpu = new Gpgpu(w, h);
    this.tex = this.gpu.gl.createTexture();
    this.gpu.spg(
      document.getElementById("vs").innerHTML,
      document.getElementById("fs").innerHTML,
      ["a_position"],
      []
    );
    this.gpu.sad(6, {
      a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
    });
    this.gpu.gl.bindTexture(this.gpu.gl.TEXTURE_2D, this.tex);
    this.gpu.gl.texImage2D(
      this.gpu.gl.TEXTURE_2D,
      0,
      this.gpu.gl.RGBA,
      w,
      h,
      0,
      this.gpu.gl.RGBA,
      this.gpu.gl.UNSIGNED_BYTE,
      null
    );
  }
  t() {
    this.gpu.gl.framebufferTexture2D(
      this.gpu.gl.FRAMEBUFFER,
      this.gpu.gl.COLOR_ATTACHMENT0,
      this.gpu.gl.TEXTURE_2D,
      this.tex,
      0
    );
    this.gpu.drw();
    this.gpu.gl.readPixels(
      0,
      0,
      this.w,
      this.h,
      this.gpu.gl.RGBA,
      this.gpu.gl.UNSIGNED_BYTE,
      this.gpu.out
    );
    console.log(this.gpu.out[0]);
  }
}

const w = 10;
const h = 10;
const gpu = new Gpgpu(w, h);
const tex = gpu.gl.createTexture();

gpu.spg(
  document.getElementById("vs").innerHTML,
  document.getElementById("fs").innerHTML,
  ["a_position"],
  []
);
gpu.sad(6, {
  a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
});
gpu.gl.bindTexture(gpu.gl.TEXTURE_2D, tex);
gpu.gl.texImage2D(
  gpu.gl.TEXTURE_2D,
  0,
  gpu.gl.RGBA,
  w,
  h,
  0,
  gpu.gl.RGBA,
  gpu.gl.UNSIGNED_BYTE,
  null
);
gpu.gl.framebufferTexture2D(
  gpu.gl.FRAMEBUFFER,
  gpu.gl.COLOR_ATTACHMENT0,
  gpu.gl.TEXTURE_2D,
  tex,
  0
);
gpu.drw();
gpu.gl.readPixels(0, 0, w, h, gpu.gl.RGBA, gpu.gl.UNSIGNED_BYTE, gpu.out);
console.log(gpu.out[0]);

new Cloth(10, 10).t();
<script type="x-shader/x-vertex" id="vs">
  attribute vec4 a_position;
              
  void main() {
    gl_Position = a_position;
  }
</script>
<script type="x-shader/x-fragment" id="fs">precision highp float;
  void main() {
    gl_FragColor = vec4(0.5, 0.5, 0.5, 0.5);
  }
</script>

【问题讨论】:

  • 我已经看到了,但我认为它不适合我的问题,因为在我的情况下,我在 drawArrays 之后立即执行 readPixels 在两种情况下(课堂内外) .另外,我正在渲染到帧缓冲区,在这个问题中还不清楚帧缓冲区是否存在。

标签: javascript canvas webgl


【解决方案1】:

这是一个简单的错字,您从未为 Cloth 实例定义 this.wthis.h 属性,但在 t() 中,当执行 readPixel 调用时,您尝试使用它。

只需在构造函数中定义这些即可。

class Gpgpu {
  constructor(w, h, vs, fs, ans, uns) {
    this.gl = document.createElement("canvas").getContext("webgl");
    this.gl.canvas.width = w;
    this.gl.canvas.height = h;
    this.gl.viewport(0, 0, w, h);
    this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.gl.createFramebuffer());
    this.out = new Uint8Array(w * h * 4);
  }
  spg(vs, fs, ans, uns) {
    let p = this.gl.createProgram();
    for (let ss of [
      { t: this.gl.VERTEX_SHADER, d: vs },
      { t: this.gl.FRAGMENT_SHADER, d: fs }
    ]) {
      let s = this.gl.createShader(ss.t);
      this.gl.shaderSource(s, ss.d);
      this.gl.compileShader(s);
      this.gl.attachShader(p, s);
    }
    this.gl.linkProgram(p);
    this.gl.useProgram(p);
    this.als = {};
    for (let an of ans) {
      this.als[an] = {
        l: this.gl.getAttribLocation(p, an),
        b: this.gl.createBuffer()
      };
    }
    this.uls = {};
    for (let un of uns) {
      this.uls[un] = this.gl.getUniformLocation(p, un);
    }
  }
  sad(n, ads) {
    this.n = n;
    for (let an in ads) {
      let al = this.als[an];
      let ad = ads[an];
      this.gl.bindBuffer(this.gl.ARRAY_BUFFER, al.b);
      this.gl.bufferData(
        this.gl.ARRAY_BUFFER,
        Float32Array.from(ad),
        this.gl.STATIC_DRAW
      );
      this.gl.enableVertexAttribArray(al.l);
      this.gl.vertexAttribPointer(al.l, 2, this.gl.FLOAT, false, 0, 0);
    }
  }
  drw() {
    this.gl.drawArrays(this.gl.TRIANGLES, 0, this.n);
  }
}

class Cloth {
  constructor(w, h) {
    this.w = w;
    this.h = h;
    this.gpu = new Gpgpu(w, h);
    this.tex = this.gpu.gl.createTexture();
    this.gpu.spg(
      document.getElementById("vs").innerHTML,
      document.getElementById("fs").innerHTML,
      ["a_position"],
      []
    );
    this.gpu.sad(6, {
      a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
    });
    this.gpu.gl.bindTexture(this.gpu.gl.TEXTURE_2D, this.tex);
    this.gpu.gl.texImage2D(
      this.gpu.gl.TEXTURE_2D,
      0,
      this.gpu.gl.RGBA,
      w,
      h,
      0,
      this.gpu.gl.RGBA,
      this.gpu.gl.UNSIGNED_BYTE,
      null
    );
  }
  t() {
    this.gpu.gl.framebufferTexture2D(
      this.gpu.gl.FRAMEBUFFER,
      this.gpu.gl.COLOR_ATTACHMENT0,
      this.gpu.gl.TEXTURE_2D,
      this.tex,
      0
    );
    this.gpu.drw();
    this.gpu.gl.readPixels(
      0,
      0,
      this.w,
      this.h,
      this.gpu.gl.RGBA,
      this.gpu.gl.UNSIGNED_BYTE,
      this.gpu.out
    );
    console.log(this.gpu.out[0]);
  }
}

const w = 10;
const h = 10;
const gpu = new Gpgpu(w, h);
const tex = gpu.gl.createTexture();

gpu.spg(
  document.getElementById("vs").innerHTML,
  document.getElementById("fs").innerHTML,
  ["a_position"],
  []
);
gpu.sad(6, {
  a_position: [-1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1]
});
gpu.gl.bindTexture(gpu.gl.TEXTURE_2D, tex);
gpu.gl.texImage2D(
  gpu.gl.TEXTURE_2D,
  0,
  gpu.gl.RGBA,
  w,
  h,
  0,
  gpu.gl.RGBA,
  gpu.gl.UNSIGNED_BYTE,
  null
);
gpu.gl.framebufferTexture2D(
  gpu.gl.FRAMEBUFFER,
  gpu.gl.COLOR_ATTACHMENT0,
  gpu.gl.TEXTURE_2D,
  tex,
  0
);
gpu.drw();
gpu.gl.readPixels(0, 0, w, h, gpu.gl.RGBA, gpu.gl.UNSIGNED_BYTE, gpu.out);
console.log(gpu.out[0]);

new Cloth(10, 10).t();
<script type="x-shader/x-vertex" id="vs">
  attribute vec4 a_position;
              
  void main() {
    gl_Position = a_position;
  }
</script>
<script type="x-shader/x-fragment" id="fs">precision highp float;
  void main() {
    gl_FragColor = vec4(0.5, 0.5, 0.5, 0.5);
  }
</script>

【讨论】:

  • 嗯,这很尴尬 :) 非常感谢,祝你玩得开心!
  • 我将其设为社区 Wiki,因为我不想从中获得任何“代表”。然而,赏金确实属于 CW 的主要作者......所以如果有一种方法(我不记得在自己的问题上设置赏金时的 UI)让你不授予赏金并可能取消它,那将很棒。
  • 我认为我无法撤消赏金,但如果取消选中您的答案作为已接受的答案,我认为赏金将变为无效。赏金到期后将重新检查答案。
猜你喜欢
  • 1970-01-01
  • 2020-10-27
  • 1970-01-01
  • 2015-03-22
  • 2020-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
相关资源
最近更新 更多