WebGL使用TWGL时Framebuffer与Uniform意外形成反馈循环问题求助
问题核心原因
所有异常都源于两个底层逻辑的叠加:
- WebGL的纹理单元是全局状态,不是每个着色器程序独立持有
- 你的两个着色器程序的采样器默认被TWGL分配到了同一个纹理单元0,导致纹理绑定互相覆盖
对异常现象的具体解释
1. 最初的“正常运行”是假象
你以为的正常逻辑(write写入帧缓冲→read读帧缓冲反色输出)实际没有执行:
- 构造函数中给read程序的
u_framebuffer分配了纹理单元0,将帧缓冲纹理绑定到单元0 - 加载图片时给write程序的
u_texture也分配了纹理单元0,静态图片纹理覆盖了单元0的原有绑定 - 后续你没有再修改过单元0的绑定,所以read程序实际一直采样静态图片,根本没有读取你写入的帧缓冲内容,只是刚好输出结果符合你的预期而已。
2. 取消第一段注释后报反馈循环错误
你在每帧read绘制前重新设置u_framebuffer,TWGL会把当前帧缓冲纹理重新绑定到单元0:
- 每帧结束时,纹理单元0绑定的是当前帧缓冲的纹理
- 下一帧开始你直接绑定同一个帧缓冲为绘制目标,此时触发WebGL的反馈循环检测规则:只要当前绘制帧缓冲的附件纹理被绑定到任意一个纹理单元,不管当前程序是否采样该单元,都会判定为非法反馈循环,浏览器直接抛出错误。
3. 取消两段注释后出现偏移累积
你开启帧缓冲交换逻辑后:
- 每帧设置read的
u_framebuffer时,都会把上一帧的输出纹理绑定到单元0 - write程序的
u_texture使用的也是单元0,导致write程序本应采样静态图片,实际采样到了上一帧的帧缓冲输出 - 每帧的1像素偏移被逐帧累积,就出现了纹理持续移动的现象。
解决方案
手动给两个采样器指定不同的纹理单元,避免TWGL自动分配导致冲突:
- 给write程序的
u_texture固定使用纹理单元0 - 给read程序的
u_framebuffer固定使用纹理单元1
修改代码示例:
// 构造函数中设置read程序uniform时手动指定单元 this.gl.useProgram(this.pgi.read.program); twgl.setUniforms(this.pgi.read, { u_framebuffer: { texture: this.fbs[0].attachments[0], unit: 1 }, u_resolution: dim }); // 加载图片时给u_texture手动指定单元 twgl.setUniforms(this.pgi.write, { u_texture: { texture: twgl.createTexture(this.gl, { src }, handler), unit: 0 } }); // 后续重新设置u_framebuffer时也指定单元 twgl.setUniforms(this.pgi.read, { u_framebuffer: { texture: this.fbs[0].attachments[0], unit: 1 } });
修改后两个采样器使用独立的纹理单元,不会互相覆盖绑定,所有异常都会消失。
内容的提问来源于stack exchange,提问作者fweth
相关产品推荐
相关产品推荐

