用three.js构建自己的后处理渲染器第三篇---架构设计

863 阅读3分钟

上一篇主要讨论性能问题,这一篇我们开始设计后处理渲染器架构

effectComposer ---(默认生成 sourceTarget(原场景), readBuffer(后续每一个pass的最终结果),writeBuffer(负责与readBuffer进行交换))
			---renderPass (负责渲染一遍原场景,最终渲染到sourceTarget)
			---pass1 (针对物体的后处理)
			---pass2
			...
			---screenPass1(针对屏幕的后处理)
			---screenPass2
			...

1.系统架构大概是这样,由于我们考虑使用MSAA和FXAA两种方式,首先需要封装一个createRenderTarget的方法,用于动态切换WebGLRenderTarget和WebGLMultisampleRenderTarge。然后封装setDepth方法来为它们创建深度贴图和深度缓冲对象。 2.为了照顾到显存,如果使用MSAA,我们最多只给原图使用WebGLMultisampleRenderTarge以及每一张scheme图(针对物体的后处理效果中渲染物体的那张图称为scheme图)使用WebGLMultisampleRenderTarget, 其余renderTarget尽量使用WebGLRenderTarget。同时我们要注意尽量少使用额外的renderTarget,以便减少内存多消耗。 3.renderTarget处理完后我们开始着手设计物体级的Pass 物体级的Pass的第一步是要生成一张scheme图,如下:

 			var strategy = SchemeStrategyPool.getStrategy( this.name, schemeName);//设计一个schemeStrategy策略用于修改scheme物体的材质
            strategy.getRenderStrategy();
            renderer.materialManager.setMode(schemeName);//设置当前渲染策略
            renderer.setRenderTarget( this.schemeTargetBuffer );//绑定schemeBuffer
           renderer.clear(true, false, true);//清除颜色和模版,不清除深度。如果不考虑深度可以将深度清除
            renderer.initRenderList = false;//禁止渲染列表更新
            renderer.render(this.renderScene, this.renderCamera);
            renderer.initRenderList = true;//重新开启渲染列表更新
            renderer.materialManager.setMode(0);//重置为three.js默认渲染策略

strategy是当前的渲染策略,比如在渲染scheme图的时候很多时候都需要替换成一个自定义的材质等等。 现在scheme图到手了,但是如果设置后处理的物体过多,这一步的开销还是比较大的,因此需要设计一个静帧策略(如果有MRT则可以一次性把所有scheme图和原图渲染出来就不需要静帧了),如

if (this._dirty) {
            this._updateSchemeBuffer(renderer, readBuffer);
            this._dirty = false;
 }

非常简单,设计一个dirty,只有需要更新时将dirty设置为true就行,静止的时候我们不需要更新。 接下来就是你需要后期的代码了,不过最后一定要切换到readBuffer,然后把结果更新过去。如果要渲染到屏幕,则拿readBuffer的结果渲染到屏幕即可。这样每一个pass就可以串起来了。

---后期相关代码,如outLine
renderer.setRenderTarget(this.readBuffer);
  renderer.clear();
 renderer.render(this.scene, this.camera);
  if (this.renderToScreen) {
                     this.quad.material = this.materialCopy;
                     this.copyUniforms['tDiffuse'].value = this.readBuffer.texture;
                     renderer.setRenderTarget(null);
                     renderer.clear();
                     renderer.render(this.scene, this.camera);
             }

这样pass就设计完了。如果是全屏级的,直接跳过scheme图的步骤,拿readBuffer的结果开始处理即可。 4.设计好最核心的pass,基本上一个简单版的后处理渲染器就设计好了。 5.当然某些情况下你可以设计一些策略来实现高性能的多glow效果(比如在渲染的时候通过某些参数一般是颜色或者透明度来决定发光的颜色和强度等等,但是一次渲染也有它的一些小问题,总之看需求吧)。很多情况,多个不同glow效果还是需要创建多个glowpass的。下面是一些高性能一次渲染不同glow的一些例子,理论上一次渲染和创建多个glowpass的方式都要实现,这样可以给用户更多的选择。 截几个图吧: 一次渲染多个不同内发光效果: 在这里插入图片描述一次渲染多种不同强度glow效果 在这里插入图片描述