简体   繁体   English

帧缓冲区和制服的非常奇怪的情况(意外反馈)

[英]Very Weird Situation With Framebuffers And Uniforms (Unexpected Feedback)

I have this situation with framebuffers which I don't understand at all.我对帧缓冲区有这种情况,我根本不明白。 Have a look at the following:看看以下内容:

 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>

I tried to keep things as simple as possible.我试图让事情尽可能简单。 There are two programs, write and read , where write reads from a texture, translates by one pixel and writes to the output. Then read reads from a framebuffer, inverts the image and writes to the output. In the current situation, I let write render to the framebuffer and read render to the screen.有两个程序, writeread ,其中write从纹理读取,转换一个像素并写入 output。然后read从帧缓冲区读取,反转图像并写入 output。在当前情况下,我让write渲染到帧缓冲区并read渲染到屏幕。 Everything works as expected.一切都按预期工作。

Now if I uncomment the first commented line in the JS, I get the error Feedback loop formed between Framebuffer and active Texture , which is weird, as the uniform u_framebuffer in read is always set to the same framebuffer, I just rebind a uniform already bound.现在,如果我取消注释 JS 中的第一个注释行,我会得到Feedback loop formed between Framebuffer and active Texture ,这很奇怪,因为read中的统一u_framebuffer总是设置为相同的帧缓冲区,我只是重新绑定一个已经绑定的统一. Also it should create no feedback loop, as write doesn't have the framebuffer bound while read doesn't attempt to render to the framebuffer.此外,它不应创建反馈循环,因为write没有绑定帧缓冲区,而read不会尝试渲染到帧缓冲区。

If I uncomment both commented lines in the JS, so that the framebuffer get switched out every frame, I can see the texture 'walk' across the screen.如果我取消注释 JS 中的两条注释行,以便每帧都切换帧缓冲区,我可以看到纹理在屏幕上“行走”。 So that is clearly a feedback loop (the one pixel offset getting accumulated), but I can't see where it is coming from.所以这显然是一个反馈回路(一个像素的偏移量被累积),但我看不出它是从哪里来的。 write just reads from the texture, which should be absolutely static, but somehow it seems to consume its own output. write只是从纹理中读取,它绝对应该是 static,但不知何故它似乎消耗了它自己的 output。

I'm quite lost here, either there is some logic in uniforms and framebuffers which I don't understand at all, or some bug I never encountered before?我在这里很迷茫,要么是制服和帧缓冲区中存在一些我根本不理解的逻辑,要么是我以前从未遇到过的错误?

Textures are not like uniforms, textures are bound to one of the globally available texture units which is a stateful operation, aka once you bind a texture to a unit it remains bound until you unbind it, just like framebuffers.纹理不像制服,纹理绑定到全局可用的纹理单元之一,这是一个有状态的操作,也就是一旦你将纹理绑定到一个单元,它就会保持绑定直到你解除绑定,就像帧缓冲区一样。 So when you call setUniforms with a texture, it binds the texture to a unit and tells the sampler which of the global units to read from, omitting this results in the following shaders reading from whatever was bound previously, in your case the framebuffer texture.因此,当您使用纹理调用setUniforms时,它会将纹理绑定到一个单元并告诉采样器要从哪个全局单元读取,省略这会导致以下着色器从之前绑定的任何内容读取,在您的情况下是帧缓冲区纹理。 So what you want to do is rebind the read texture before you render with your read program:所以你想要做的是在你用你的读取程序渲染之前重新绑定读取的纹理:

    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]
    });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM