Surface Shader 执行流程

Surface Shader 统一了着色流程,同时为 vs 和 fs 提供了大量的自定义函数,大家可以根据自己的需求,重写相关函数。

请参考 Surface Shader 内置函数使用宏定义实现函数替换

本文主要目的在于帮助开发者熟悉 Surface Shader 执行流程,弄清楚各函数调用时机。

函数入口

我们先看一下内置的 Surface Shader 文件的 CCEffect 部分:

  1. CCEffect %{
  2. techniques:
  3. - name: opaque
  4. passes:
  5. - vert: standard-vs
  6. frag: standard-fs
  7. ...
  8. }%

可以看到, 每一个 pass 的 vert 和 frag 没有指定专有的入口函数,这就表示,它所用到的 vs 和 fs 的入口函数为 main。

Surface Shader 结构 中,我们可以了解到, 在 Surface Shader 组装 环节,每一个 Surface Shader 会根据不同的 渲染用途,引入不同的头文件。 这个头文件就是我们的入口函数。

VS 主函数

以内置 Surface Shader 的 standard-vs 为例:

  1. CCProgram standard-vs %{
  2. #include <shading-entries/main-functions/render-to-scene/vs>
  3. }%

可以看到,它引入的是 render-to-scene 下面的 vs.chunk。

打开 render-to-scene/vs.chunk,可以看到,它只有一个 main 函数。代码和注释如下:

  1. void main()
  2. {
  3. //声明一个表面材质数据结构
  4. SurfacesStandardVertexIntermediate In;
  5. //获取顶点基本数据
  6. CCSurfacesVertexInput(In);
  7. //获取顶点动画数据
  8. CCSurfacesVertexAnimation(In);
  9. // ===== 本地坐标相关 ====
  10. //处理本地坐标,用户可用宏替换
  11. In.position.xyz = SurfacesVertexModifyLocalPos(In);
  12. //处理本地法线,用户可用宏替换
  13. In.normal.xyz = SurfacesVertexModifyLocalNormal(In);
  14. //处理本地切线,用户可用宏替换
  15. #if CC_SURFACES_USE_TANGENT_SPACE
  16. In.tangent = SurfacesVertexModifyLocalTangent(In);
  17. #endif
  18. //进一步处理自定义本地数据,用户可用宏替换
  19. SurfacesVertexModifyLocalSharedData(In);
  20. //==== 世界坐标相关======
  21. //进行世界坐标转换,并填充数据结构
  22. CCSurfacesVertexWorldTransform(In);
  23. //额外的处理世界坐标函数,用户可用宏替换
  24. In.worldPos = SurfacesVertexModifyWorldPos(In);
  25. //投影空间坐标
  26. In.clipPos = cc_matProj * cc_matView * vec4(In.worldPos, 1.0);
  27. //进一步处理投影空间坐标,用户可用宏替换
  28. In.clipPos = SurfacesVertexModifyClipPos(In);
  29. //其它一些数据变换
  30. vec3 viewDirect = normalize(cc_cameraPos.xyz - In.worldPos);
  31. In.worldNormal.w = dot(In.worldNormal.xyz, viewDirect) < 0.0 ? -1.0 : 1.0;
  32. //进一步处理世界法线,用户可用宏替换
  33. In.worldNormal.xyz = SurfacesVertexModifyWorldNormal(In);
  34. //进一步处理UV,用户可用宏替换
  35. SurfacesVertexModifyUV(In);
  36. //进一步处理自定义数据,用户可用宏替换
  37. SurfacesVertexModifySharedData(In);
  38. //其它变换
  39. //UV
  40. CCSurfacesVertexTransformUV(In);
  41. //雾效
  42. CCSurfacesVertexTransferFog(In);
  43. //阴影
  44. CCSurfacesVertexTransferShadow(In);
  45. //光照贴图UV
  46. CCSurfacesVertexTransferLightMapUV(In);
  47. //最终输出
  48. CCSurfacesVertexOutput(In);
  49. }

FS 主函数

同样的,我们以内置 Surface Shader 的 standard-fs 为例:

  1. CCProgram standard-fs %{
  2. #include <shading-entries/main-functions/render-to-scene/fs>
  3. }%

render-to-scene/fs.chunk 文件内容如下:

  1. #if (CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_FORWARD || CC_FORCE_FORWARD_SHADING)
  2. #include <shading-entries/main-functions/render-to-scene/pipeline/forward-fs>
  3. #elif CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_DEFERRED
  4. #include <shading-entries/main-functions/render-to-scene/pipeline/deferred-fs>
  5. #endif

可以看到它区分了 forward 和 deferred 管线。

forward-fs

  1. //定义颜色输出目标
  2. layout(location = 0) out vec4 fragColorX;
  3. void main() {
  4. #if CC_DISABLE_STRUCTURE_IN_FRAGMENT_SHADER
  5. //获取基本颜色和透明度,用户可用宏替换
  6. vec4 color = SurfacesFragmentModifyBaseColorAndTransparency();
  7. #else
  8. //获取表面材质数据
  9. SurfacesMaterialData surfaceData;
  10. CCSurfacesFragmentGetMaterialData(surfaceData);
  11. //计算阴影参数
  12. vec2 shadowBias = vec2(0.0);
  13. ...
  14. //计算雾效参数
  15. #if !CC_FORWARD_ADD
  16. float fogFactor = 1.0;
  17. #endif
  18. //计算光照
  19. LightingResult lightingResult;
  20. CCSurfacesLighting(lightingResult, surfaceData, shadowBias);
  21. //渲染调试相关
  22. ...
  23. //像素着色计算
  24. vec4 color = CCSurfacesShading(surfaceData, lightingResult);
  25. ...
  26. //颜色输出
  27. #if CC_USE_RGBE_OUTPUT
  28. fragColorX = packRGBE(color.rgb); // for reflection-map
  29. return;
  30. #endif
  31. //HDR,LinearToSRGB 等最终运算
  32. #if CC_USE_HDR
  33. #if CC_USE_DEBUG_VIEW == CC_SURFACES_DEBUG_VIEW_COMPOSITE_AND_MISC && CC_SURFACES_ENABLE_DEBUG_VIEW
  34. if (IS_DEBUG_VIEW_COMPOSITE_ENABLE_TONE_MAPPING)
  35. #endif
  36. color.rgb = ACESToneMap(color.rgb);
  37. #endif
  38. #if CC_USE_DEBUG_VIEW == CC_SURFACES_DEBUG_VIEW_COMPOSITE_AND_MISC
  39. if (IS_DEBUG_VIEW_COMPOSITE_ENABLE_GAMMA_CORRECTION)
  40. #endif
  41. color.rgb = LinearToSRGB(color.rgb);
  42. #if !CC_FORWARD_ADD && CC_USE_FOG != CC_FOG_NONE
  43. CC_APPLY_FOG_BASE(color, fogFactor);
  44. #endif
  45. fragColorX = CCSurfacesDebugDisplayInvalidNumber(color);
  46. }

deferred-fs

延迟渲染由于分成两个阶段:GBuffer 和 Lighting。

在 GBuffer 阶段主要是填充各个渲染目标,只需要收集对应的材质表面数据即可,代码如下:

  1. //GBuffer 0,1,2
  2. layout(location = 0) out vec4 fragColor0;
  3. layout(location = 1) out vec4 fragColor1;
  4. layout(location = 2) out vec4 fragColor2;
  5. void main () {
  6. //收集表面材质数据
  7. SurfacesMaterialData surfaceData;
  8. CCSurfacesFragmentGetMaterialData(surfaceData);
  9. //填充 GBuffer
  10. fragColor0 = CCSurfacesDeferredOutput0(surfaceData);
  11. fragColor1 = CCSurfacesDeferredOutput1(surfaceData);
  12. fragColor2 = CCSurfacesDeferredOutput2(surfaceData);
  13. //调试渲染相关
  14. #if CC_USE_DEBUG_VIEW == CC_SURFACES_DEBUG_VIEW_SINGLE && CC_SURFACES_ENABLE_DEBUG_VIEW
  15. vec4 debugColor = vec4(0.0, 0.0, 0.0, 1.0);
  16. CCSurfacesDebugViewMeshData(debugColor);
  17. CCSurfacesDebugViewSurfaceData(debugColor, surfaceData);
  18. if (IS_DEBUG_VIEW_ENABLE_WITH_CAMERA) {
  19. fragColor0 = debugColor;
  20. }
  21. #endif
  22. }

延迟渲染的 Lighting 阶段,是受引擎渲染管线控制的,会统一使用 GBuffer 进行光照计算,可参考 internal/effects/deferred-lighting.effect。

其余的渲染用途主函数同理,可以到 internal/chunks/shading-entries/ 目录下查看。

提示:可以被替换的代码,都以 Surface###Modify### 方式命名。