WebGL Ping-Pong循环为何无法使用新RenderTarget?
问题:Ping-Pong循环中动态创建RenderTarget为何无法实现叠加效果?
我了解Ping-Pong循环基于两个固定的RenderTarget设置,示例代码如下:
this.fbo_material.uniforms.particle_time.value = this.accumulate_time; this.fbo_material.uniforms.fbo_texture.value = this.fbo_rendertarget_1.texture; this.controls.update(); this.renderer.setRenderTarget(null); this.renderer.render(this.scene, this.camera); this.renderer.setRenderTarget(null); this.renderer.setRenderTarget(this.fbo_rendertarget_0); this.renderer.render(this.fbo_scene, this.fbo_camera); let temp = this.fbo_rendertarget_0; this.fbo_rendertarget_0 = this.fbo_rendertarget_1; this.fbo_rendertarget_1 = temp; window.requestAnimationFrame(this.create_tick.bind(this));
但尝试动态创建RenderTarget的写法却无法生效:
this.fbo_material.uniforms.particle_time.value = this.accumulate_time; this.fbo_material.uniforms.fbo_texture.value = this.fbo_rendertarget_1.texture; this.controls.update(); this.renderer.setRenderTarget(null); this.renderer.render(this.scene, this.camera); // 新增的动态创建代码 this.fbo_rendertarget_0 = this.createRenderTarget(); this.renderer.setRenderTarget(null); this.renderer.setRenderTarget(this.fbo_rendertarget_0); this.renderer.render(this.fbo_scene, this.fbo_camera); let temp = this.fbo_rendertarget_0; this.fbo_rendertarget_0 = this.fbo_rendertarget_1; this.fbo_rendertarget_1 = temp; window.requestAnimationFrame(this.create_tick.bind(this));
理论上新的RenderTarget应该能继承this.fbo_material.uniforms.fbo_texture.value = this.fbo_rendertarget_1.texture;的内容,但实际无法继续叠加效果。使用两个固定RenderTarget时能成功实现Ping-Pong效果,动态创建就失败,期望结果与固定RenderTarget的效果一致。
解答
核心原因是动态创建的RenderTarget是全新的空白缓冲区,直接破坏了Ping-Pong循环的帧间数据传递链路:
- 固定双RenderTarget的Ping-Pong逻辑:每一帧都把上一帧渲染完成的
rendertarget_1数据作为输入,渲染到rendertarget_0里,随后交换两者引用,让下一帧能继续用最新的渲染结果作为输入,形成持续叠加的闭环。 - 而你每次tick都重新创建
rendertarget_0,这个新的RenderTarget没有任何历史渲染数据——哪怕你把rendertarget_1的纹理传给材质,渲染到新rendertarget_0后,交换引用时rendertarget_1会指向这个全新的空白缓冲区,下一帧的输入直接变成空白,自然无法形成叠加效果。
简单来说,Ping-Pong循环依赖两个缓冲区持续交替读写、传递帧间数据,动态创建新缓冲区会直接打断这个数据传递链条,导致每一轮循环的输入都丢失了历史叠加信息。
如果确实需要动态创建(比如需调整缓冲区尺寸),必须在创建新RenderTarget后,先把旧rendertarget_1的纹理内容复制到新缓冲区中,再进行后续渲染步骤,才能保证数据链路不中断。
内容的提问来源于stack exchange,提问作者bents
相关产品推荐
相关产品推荐

