【分享】3.x自定义管线之后期效果流,源码及使用说明附上

大家好,最近项目需要用到后期效果,但是3.x目前还没有提供后期效果管线Flow,所以抽时间自己定制了一个后期组件,在此与大家分享。

(注意,目前的源码是基于3.2.1,有同学反馈说3.3会报没有ShaderPool的错误,经测试,3.3已经没有renderer.ShaderPool了;将这所有ShaderPool的报错代码直接改为pass.getShaderVariant()即可,其它无变化。

什么是后期?

后期也就是游戏界面输出到最后阶段,对最终的输出画面进行一系列的处理。
在此阶段界面已经是2D内容,不过其实如果你有3D世界的其它信息如深度信息,那么在此阶段也能处理一些3D的计算。这是个很深的话题,不在此帖讨论范围内。

后期有什么效果

bloom发光
模糊
径向模糊
风格化
等等
更多可参阅这篇文章

目前与大家分享的组件,实现了管线后期渲染流PostEffectFlow,及两个Stage

  1. BloomStage(泛光)
  2. VignetteStage(黑边)

1,BloomStage

这个后期是我写这个组件的目的,也就是全屏泛光效果,先看下效果
bloom
(里面的绿点是录GIF的问题,和效果无关)

目前bloom的模糊pass是使用的Dual Blur,所以性能是所有模糊中最好的,另外为了性能我折中了一下效果,将模糊pass降低至了2个,如果需要更大的模糊范围及质量,可以自行修改代码中的BloomStage中的iteration值。(但我没有具体测试过占用的GPU时间,有兴趣的同鞋可以测试一下,最好分享一下结果,感谢!)
关于Dual Blur及性能对比,可以参阅 高品质后处理:十种图像模糊算法的总结与实现 - 知乎 这篇文章,这里直接帖上对比结果:

2,VignetteStage

这个效果也就是可以看见的图里的边缘的黑边,主要是我为了将它作为一个示例来写的,毕竟两个后期肯定满足不了大家的胃口,那么如果需要扩展自己的后期,参照这个来写就可以了,不难,写好后,在PostEffectComponent内添加即可。
vignette

3,关于DrawCall

  1. BloomStage因为有很多步骤,所以占用了5个DrawCall,但是由于子pass都被降了一半的分辨率,并且由于Dual Blur的pass间降尺寸的特性,所以基本上中间的子pass几乎不会占用GPU时间,所以大体总的算来,大概是3个DrawCall左右所占用的时间。
    这里顺便解释一下,并不是DrawCall越多越慢,而是要看这个drawcall具体做了什么事,如果你一个drawcall,FBO尺寸是1x1,并且渲染shader里只直接输出了一个颜色。那么像这种drawcall你在一帧调一万次估计都不见得会卡。不过总的,性能的调节及取舍,需要自己来根据自己的项目调节哈。

  2. VignetteStage占1 DrawCall

4,源码类说明及使用方法

  1. 类说明(简单说明,具体的自己看源码吧)

    • PostEffectComponent
      主组件类

    • post-effect-flow
      管线扩展Flow

    • post-stages/bloom-effect.ts / .effect
      BloomStage渲染逻辑及shader

    • post-stages/vignette-stage.ts / .effect
      VignetteStage渲染逻辑及shader

    • IEffectStage.ts
      后期Stage需要实现的接口

  2. 工作原理
    post-effect-flow渲染流是使用摄像机的输出来作为输入的,所以,使用时你必须将它挂到一个带有Camera组件的node上,在这里说个小插曲,一开始写完所有FlowStage后,发现FlowStage无法绑定CameraEffectAsset资源,导致一度以为是IDE的BUG,纯代码测试都跑通了,就是卡在这步不知道要怎么办,后来转念一想,管线是引擎启动最开始就会创建的,它是不太可能会去加载额外的资源再来创建的,而且还是用户的自定义资源,所以后来就改为封装了一个Component,这样就可以自己把这个组件拖到任意摄像机上了。

  3. 特性

    • 因为是依赖摄像机的输出的,所以和具体使用什么管线无关。
    • flow内的后期stages顺序无关(bloom除外,bloom会被强制放到第一渲染位)。
    • 可实时调整各个stage的属性及启用禁用。
  4. 使用方法

    1. 添加PostEffectComponent至某个带有摄像机组件的node
    2. bloom-effect.effectvignette-effect.effect拖至对应的槽中。
    3. 调节参数即可。
    4. 注意,由于后期效果是针对Camera的,所以如果你的游戏内容和UI内容在同一个摄像机,那么UI也会被后期掉,所以建议使用Cocos的摄像机分屏功能,将游戏内容及UI内容分为两个摄像机,然后只为游戏内容的摄像机添加后期效果即可。

5,缺点

  1. 无法预览,因为这是管线的渲染流程,组件在编辑状态时并不会执行逻辑代码,所以渲染flow在编辑状态时并没有被加入到当前IDE的渲染管线内,所以效果就不会显示。
  2. 目前PostEffectComponent.ts这个组件代码可以优化,比如改成后期stage数组,目前我懒我直接判断的if (bloom && vignette) { work },这种方式,但是事实上,post-effect-flow是支持动态添加删除的,看各位童鞋自己优化吧:+1:

点击下载,并点赞~ :crossed_fingers:
assets.zip (11.7 KB)
MIT License


后记:
在这整个扩展过程中,学到了cocos的很多东西,3.x的架构特别是gfx的抽象真的是太赞了,虽然接触cocos还没有很长时间,但确实已爱上:smiling_face_with_three_hearts:,并且希望cocos越来越好!:heart:

56赞

可以啊,终于有了

我说我不赞,作者非让我来赞!

等好久了,lz太给力啦
话说如果项目中用自定义管线原生层是不是也要写一份C++代码

牛逼!大佬,带弟!

作者让我来点赞 太赞了

除了赞,其它无能为力

给大佬助威!欢迎来CocosStore分享资源,将你的作品打磨的更加耀眼,帮助到更多的人 :heartpulse:

1赞

3.3没有了ShaderPool

:heart_eyes: :star_struck: :star_struck: :star_struck: :star_struck:

膜拜大佬~

要是能解析一下就更好了

库拉牛批!啊不对,大佬牛批,带带弟弟!

额。不好意思。版本是3.2.1写的。我修改一下文章把版本号加上,另外3.3我抽时间看看,谢谢反馈

我试着把renderer.ShaderPool.get去掉,直接用pass.getShaderVariant返回的shader,好像可以达到效果,不知道有没有其他影响。

以前已经有大佬写过的


不过里面的UML类图是基于3.0的,现在的的版本已经修改掉了。比如UI,On Off Screen,些全部集成到Camera里或管线里了。

1赞

刚测了下。直接改为pass.getShaderVariant()就可以啦,没有别的影响。

:smiley:

emm这个就不清楚了,没用建过x项目,不过按理来说应该不用吧,因为管线只是生成一些command队列进行提交,和各种buff的绑定而已,这些操作在底层已经都写好了。

大佬邀请我来点赞 赞!!!