着色器语法

Cocos Creator 中的着色器(Cocos Shader ,文件扩展名为 *.effect),是一种基于 YAMLGLSL 的单源码嵌入式领域特定语言(single-source embedded domain-specific language),YAML 部分声明流程控制清单,GLSL 部分声明实际的 Shader 片段,这两部分内容相互补充,共同构成了一个完整的渲染流程描述。

注意:推荐使用 Visual Studio Code 编写 Cocos Shader,并在应用商店中安装 Cocos Effect 扩展,提供编写时的语法高亮提示。

Cocos Effect

语法框架概览

Cocos Shader 通常由两个部分组成:

  • CCEffect:用于声明渲染技术(Technique)、渲染过程(Pass)、渲染状态、材质参数等属性。
  • CCProgram:用于声明顶点着色器(Vertex Shader)和片元着色器(Fragment Shader)代码片段。

此处以内置着色器 builtin-unlit.effect 为例,说明 Cocos Shader 的语法框架。

在 VS Code 中打开 Cocos Creator 资源管理器 面板中 internal/effects/ 目录下的 builtin-unlit.effect 文件,可以看到主要内容如下:

  1. CCEffect %{
  2. techniques:
  3. - name: opaque
  4. passes:
  5. - vert: unlit-vs:vert
  6. frag: unlit-fs:frag
  7. properties: &props
  8. mainTexture: { value: grey }
  9. tilingOffset: { value: [1, 1, 0, 0] }
  10. mainColor: { value: [1, 1, 1, 1], linear: true, editor: { type: color } }
  11. colorScale: { value: [1, 1, 1], target: colorScaleAndCutoff.xyz }
  12. alphaThreshold: { value: 0.5, target: colorScaleAndCutoff.w, editor: { parent: USE_ALPHA_TEST } }
  13. ...
  14. - name: transparent
  15. passes:
  16. - vert: unlit-vs:vert
  17. frag: unlit-fs:frag
  18. depthStencilState: &d1
  19. ...
  20. }%
  21. CCProgram unlit-vs %{
  22. precision highp float;
  23. #include <...>
  24. #include <....>
  25. vec4 vert(){
  26. vec4 position;
  27. CCVertInput(position);
  28. ....
  29. return cc_matProj * (cc_matView * matWorld) * position;
  30. }
  31. }%
  32. CCProgram unlit-fs %{
  33. precision highp float;
  34. #include <...>
  35. #include <....>
  36. vec4 frag(){
  37. vec4 o = mainColor;
  38. ....
  39. return CCFragOutput(o);
  40. }
  41. }%

CCEffect

在 Cocos Shader 中由 CCEffect 包裹的部分是由 YAML 语法 声明的渲染流程相关的描述信息。对 YAML 不熟悉的开发者可以前住 YAML 101 了解详情。

CCEffect 的整体结构如下:

  1. CCEffect %{
  2. techniques:
  3. - name: tag
  4. passes:
  5. - vert: vs:entry
  6. frag: fs:entry
  7. <optional: material properties>
  8. <optional: pipeline states>
  9. <optional: one or more definitions>
  10. ...
  11. ...
  12. }%

一个 CCEffect 中支持定义多个渲染技术,但在实际渲染时,同一个材质实例只能应用其中一个技术。

builtin-unlit.effect 为例,其中包含了 4 个技术:

  • opaque
  • transparent
  • add
  • alpha-blend

opaque 专门用于渲染不透明物体的渲染技术,transparentaddalpha-blend 则用来渲染半透明物体。

每个渲染技术(technique)都包含了名称(name)和渲染过程(pass)。

名称用于标记渲染技术的用途,渲染过程则定义了一个完整的渲染流程所需要的全部信息。

渲染过程(Pass)

渲染过程的特点如下:

  1. 一个渲染技术可以包含多个渲染过程,渲染过程按定义的先后顺序逐一执行。
  2. 一个渲染过程必须包含一个顶点着色器(Vertex Shader,VS)和一个片元着色器(Fragment Shader,FS),其余都是可选配置项。详情请参考 Pass 可选配置参数

  3. VS/FS 着色器需要指定使用的 CCProgram ,以及指定着色器的入口函数。 如果不指定入口函数,会默认使用 main。

格式如下

  1. CCEffect %{
  2. techniques:
  3. - name: opaque # 定义一个不透明的渲染技术
  4. passes:
  5. - vert: vs: entry # 选择一个 CCProgram 声明的顶点着色器 ‘vs’,入口函数是 ‘entry’
  6. frag: fs: entry # 选择一个 CCProgram 声明的片元着色器 ‘fs’,入口函数是 ‘entry’
  7. ...
  8. ...
  9. }%

每个渲染过程都只有 vertfrag 两个必填参数,分别用于声明当前渲染过程使用的顶点着色器和片元着色器,格式为 片段名: 入口函数名

片段名可以是本文件中声明的 CCProgram 片段名,也可以是引擎提供的标准头文件。

注意:自定义着色器的代码中不应该使用 main 函数,Cocos Shader 在编译时会自动添加一个 main 函数并调用渲染过程的入口函数(例如 vertfrag),main 函数会将入口函数的返回值作为当前 Shader 的输出(例如 gl_Positiongl_FragColor)。

渲染过程属性

渲染过程中的 properties 用于配置相关属性描述。通过它,可以定义了一个 uniform 在面板上的显示方式,如下所示:

  1. CCEffect %{
  2. techniques:
  3. - name: opaque # 定义一个不透明的渲染技术
  4. passes:
  5. - vert: vs: entry # 选择一个 CCProgram 声明的顶点着色器 ‘vs’,入口函数是 ‘entry’
  6. frag: fs: entry # 选择一个 CCProgram 声明的片元着色器 ‘fs’,入口函数是 ‘entry’
  7. properties:
  8. mainTexture: { value: grey } # 着色器中需要同步定义一个 ‘uniform mainTexture’,该属性可在编辑器的属性检查器中进行配置
  9. colorScale: { value: [1, 1, 1], target: colorScaleAndCutoff.xyz } # 基于 ‘target’ 属性配置机制,着色器中需要同步定义一个 ‘uniform colorScaleAndCutoff’,并选取它的 x、y、z 分量填充 ‘colorScale’ 设置的数据
  10. depthStencilState: # 配置深度测试、模板测试和写入状态
  11. depthTest: true
  12. depthWrite: true
  13. ...
  14. ...
  15. }%

详情请参考 Pass 可选配置参数

CCProgram

在 Cocos Shader 中由 CCProgram 包裹的部分是由 GLSL 语法 声明的 Shader 片段。建议在编写 CCProgram 之前,先了解 GLSL 基础语法

它的结构如下:

  1. CCProgram shader-name %{
  2. <required: precision settings>
  3. <optional: include>
  4. <optional: ubo>
  5. <optional: custom attribute>
  6. <optional: >
  7. vec4 entry(){
  8. // 需要返回一个 vec4 类型数据
  9. }
  10. }%

预处理宏定义

通过预处理宏,可在 Cocos Shader 编译时控制代码分支和组合,以实现高效便捷的 Shader 代码管理。

更多详细内容请参考:

更多

如果想要查看更为复杂的着色器示例,可以参考 Surface Shader 结构 以及 内置 Surface Shader