内置 Legacy Shader 导读

Legacy Shader 相关的源码,有两个目录:

  • internal/chunks/legacy/
  • internal/effects/legacy/

chunks/legacy/ 目录中,存放的是一些公共函数,如解码器、雾效、输入、输出、阴影、骨骼蒙皮等等。

Legacy Shader 和 Surface Shader 都会调用 internal/chunks/builtin/ 和 internal/chunks/common/ 提供的函数。

effects/legacy/ 目录中,提供了三个内置的 Legacy Shader:

  • standard: 标准材质
  • terrain:用于地形渲染
  • toon:用于卡通渲染

基本结构

Legacy Shader 代码通常由几个部分组成:

  • 信息描述(CCEffect):描述此 Shader 的技术、渲染过程组成部分,以及每个渲染过程使用的 Shader、渲染状态、属性等。
  • 共享常量(Shared UBOs):把 vs 和 fs 都需要用到的 uniforms 定义在一起,方便管理。
  • 主体函数(Shader Body):用于实现具体的 Shader 主体。

Legacy Shader 中的 CCEffect 和 共享常量部分与 Surface Shader 一致,可前往 内置 Surface Shader 导读 了解详情。

着色函数

为了更好地理解渲染流程,请先查看 前向渲染与延迟渲染 Shader 执行流程

standard(PBR)

在 legacy/standard.effect 中,定义了着色相关的Shader代码:

  1. CCProgram standard-vs %{
  2. //...
  3. void main(){
  4. StandardVertInput In;
  5. CCVertInput(In);
  6. //...
  7. gl_Position = cc_matProj * (cc_matView * matWorld) * In.position;
  8. }
  9. }%
  10. CCProgram standard-fs %{
  11. //...
  12. void surf(out StandardSurface s){
  13. //s.albedo = ...
  14. //s.occlusion = ...
  15. //s.roughness = ...
  16. //s.metallic = ...
  17. //s.specularIntensity = ...
  18. //s.normal = ...
  19. }
  20. CC_STANDARD_SURFACE_ENTRY()
  21. }%

可以看到,在 vs 中,直接使用了 main 函数作为入口,而在 fs 中,只有一个 surf 函数。

这是因为 CC_STANDARD_SURFACE_ENTRY 宏展开后,就是 main 函数,这个 main 函数会调用 surf 函数。

terrain

terrain 使用 StandardSurface 作为材质表面数据结构,使用 CC_STANDARD_SURFACE_ENTRY 作为入口。这就说明,terrain 的渲染流程与光照计算和 standard 完全一致。

只是由于地形采用的是多层纹理混合,所以 terrain 使用的纹理以及 surf 函数实现细节与 standard 的有较大区别。

toon

在 legacy/toon.effect 中,我们可以看到:

  1. CCProgram toon-vs %{
  2. //...
  3. void main(){
  4. StandardVertInput In;
  5. CCVertInput(In);
  6. //...
  7. gl_Position = cc_matProj * (cc_matView * matWorld) * In.position;
  8. }
  9. }%
  10. CCProgram toon-fs %{
  11. //...
  12. void surf(out ToonSurface s){
  13. //s.baseStep = ...
  14. //s.baseFeather = ...
  15. //s.shadeStep = ...
  16. //s.shadeFeather = ...
  17. //s.shadowCover = ...
  18. }
  19. void frag(){
  20. ToonSurface s; surf(s);
  21. vec4 color = CCToonShading(s);
  22. return CCFragOutput(color);
  23. }
  24. }%

toon 最大的特征是在 CCEffect 中,多定义了一个 outline pass,outline pass 的代码在 chunks/legacy/main-functions/outline-vs(fs) 中。

toon 材质表面数据结构为 ToonSurface,与 standard 使用的不一样。 在 frag 函数中可以看到, toon 的光照计算使用了专门的 CCToonShading 函数。

并且,toon 自己定义了一个 frag 入口函数,未使用 CC_STANDARD_SURFACE_ENTRY 宏。这也意味着,toon 是不支持延迟渲染的。

shadow-caster

可以看到,standard,terrain,toon 都有关于 shadow 的代码片段:

  1. CCProgram shadow-caster-vs %{
  2. //...
  3. }%
  4. CCProgram shadow-caster-fs %{
  5. //...
  6. }%

这个套 vs/fs 用于阴影贴图生成,引擎渲染管线会在阴影贴图生成阶段,查找 phase 为 shadow-add 的 pass 进行绘制。