【问题标题】:Very Weird Situation With Framebuffers And Uniforms (Unexpected Feedback)帧缓冲区和制服的非常奇怪的情况(意外反馈)
【发布时间】:2021-11-27 06:03:38
【问题描述】:

我完全不了解帧缓冲区的这种情况。请看以下内容:

class Shader {
  constructor(cvs, dim) {
    cvs.width = dim[0];
    cvs.height = dim[1];
    this.gl = twgl.getContext(cvs);
    this.bfi = twgl.createBufferInfoFromArrays(this.gl, {
      a_position: {
        numComponents: 2,
        data: [-1, -1, -1, 3, 3, -1]
      }
    });
    this.pgi = {
      write: twgl.createProgramInfo(this.gl, ["vs", "fs_write"]),
      read: twgl.createProgramInfo(this.gl, ["vs", "fs_read"])
    };
    this.fbs = Array(2)
      .fill()
      .map(() => twgl.createFramebufferInfo(this.gl));
    this.gl.useProgram(this.pgi.write.program);
    twgl.setUniforms(this.pgi.write, {
      u_resolution: dim
    });
    this.gl.useProgram(this.pgi.read.program);
    twgl.setUniforms(this.pgi.read, {
      u_framebuffer: this.fbs[0].attachments[0],
      u_resolution: dim
    });
  }
  ldImg(src, handler) {
    this.gl.useProgram(this.pgi.write.program);
    twgl.setUniforms(this.pgi.write, {
      u_texture: twgl.createTexture(
        this.gl,
        { src },
        handler
      )
    });
  }
  frame() {
    twgl.bindFramebufferInfo(this.gl, this.fbs[0]);
    this.gl.useProgram(this.pgi.write.program);
    twgl.setBuffersAndAttributes(this.gl, this.pgi.write, this.bfi);
    twgl.drawBufferInfo(this.gl, this.bfi);
    twgl.bindFramebufferInfo(this.gl, null);
    this.gl.useProgram(this.pgi.read.program);
    // twgl.setUniforms(this.pgi.read, {
    //   u_framebuffer: this.fbs[0].attachments[0]
    // });
    twgl.setBuffersAndAttributes(this.gl, this.pgi.read, this.bfi);
    twgl.drawBufferInfo(this.gl, this.bfi);
    // this.fbs = [this.fbs[1], this.fbs[0]];
  }
}
(function main() {
  const dim = [512, 512];
  const shr = new Shader(document.querySelector("canvas"), dim);
  shr.ldImg("https://assets.codepen.io/854924/ad.png", frame);
  function frame(ms) {
    shr.frame();
    window.requestAnimationFrame(frame);
  }
})();
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<script id="vs" type="x-shader/x-vertex">
  attribute vec4 a_position;

  void main() {
    gl_Position = a_position;
  }
</script>
<script id="fs_write" type="x-shader/x-fragment">
  precision highp float;
  
  uniform vec2 u_resolution;
  uniform sampler2D u_texture;

  void main() {
    gl_FragColor = texture2D(u_texture, (gl_FragCoord.xy + 1.0) / u_resolution);
  }
</script>
<script id="fs_read" type="x-shader/x-fragment">
  precision highp float;

  uniform sampler2D u_framebuffer;
  uniform vec2 u_resolution;
  
  void main() {
    gl_FragColor = vec4(
      1.0 - texture2D(u_framebuffer, gl_FragCoord.xy / u_resolution).rgb,
      1.0
    );
  }
</script>
<canvas></canvas>

我试图让事情尽可能简单。有两个程序,writeread,其中write 从纹理中读取,平移一个像素并写入输出。然后read 从帧缓冲区读取,反转图像并写入输出。在当前情况下,我让write 渲染到帧缓冲区,read 渲染到屏幕。一切正常。

现在,如果我取消注释 JS 中的第一行注释,我会收到错误 Feedback loop formed between Framebuffer and active Texture,这很奇怪,因为 read 中的统一 u_framebuffer 始终设置为相同的帧缓冲区,我只是重新绑定统一已经绑定。它也不应该创建反馈循环,因为write 没有绑定帧缓冲区,而read 不尝试渲染到帧缓冲区。

如果我取消注释 JS 中的两条注释行,以便帧缓冲区在每一帧都被切换,我可以看到纹理在屏幕上“行走”。所以这显然是一个反馈循环(一个像素偏移被累积),但我看不出它来自哪里。 write 只是从纹理中读取,它应该是绝对静态的,但不知何故它似乎消耗了自己的输出。

我在这里很迷茫,要么制服和帧缓冲区中有一些我根本不理解的逻辑,要么是我以前从未遇到过的错误?

【问题讨论】:

    标签: webgl framebuffer feedback twgl.js


    【解决方案1】:

    纹理不像制服,纹理绑定到全局可用的纹理单元之一,这是一个有状态的操作,也就是说,一旦你将纹理绑定到一个单元,它就会一直保持绑定,直到你取消绑定它,就像帧缓冲区一样。 因此,当您使用纹理调用 setUniforms 时,它将纹理绑定到一个单元并告诉采样器从哪个全局单元中读取,省略这会导致以下着色器从之前绑定的任何内容中读取,在您的情况下为帧缓冲区质地。因此,您要做的是在使用读取程序渲染之前重新绑定读取纹理:

        this.gl.useProgram(this.pgi.write.program);
        twgl.setUniforms(this.pgi.write, {
           u_texture: this.readTexture //@TODO: store read texture in ldImg
        });
        twgl.setBuffersAndAttributes(this.gl, this.pgi.write, this.bfi);
        twgl.drawBufferInfo(this.gl, this.bfi);
        twgl.bindFramebufferInfo(this.gl, null);
        this.gl.useProgram(this.pgi.read.program);
        twgl.setUniforms(this.pgi.read, {
           u_framebuffer: this.fbs[0].attachments[0]
        });
    

    【讨论】:

    • 非常感谢您的快速回答!
    猜你喜欢
    • 1970-01-01
    • 2013-01-30
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-25
    • 1970-01-01
    相关资源
    最近更新 更多