# 自定义Effect

# 创建自定义Effect

开发者可以在资源管理器中新建Effect, 在物体使用的 Material 中可以选择创建的自定义Effect, 如下所示

可以看到,创建时生成三个文件:

  • custom.effect
  • custom.vertex.hlsl
  • custom.pixel.hlsl

其中 custom.effect 是Effect主文件,另外两个分别为顶点着色器和片元着色器代码。

下面将介绍如何编写自定义Effect。


# 编写自定义Effect

以下是一个简单的 effect 文件

{
  "name":"Effect3D",
  "shaderProperties": [
    {
      "key": "_MainTex_ST",
      "type": "Vector4",
      "default": [1,1,0,0]
    },
    {
      "key": "_TintColor",
      "type": "Vector4",
      "default": [1,1,1,1]
    },
    {
      "key": "_Bright",
      "type": "Float",
      "default": [1.0]
    }
  ],
  "textures": [
    {
      "key": "_MainTex",
      "type": "Texture2D",
      "default": "white"
    },
    {
      "key": "_MaskTex",
      "type": "Texture2D",
      "default": "white"
    }
  ],
  "defaultRenderQueue": 3000,
  "passes": [
    {
      "lightMode": "ForwardBase",
      "vs": "./effect3d.vertex.hlsl",
      "ps": "./effect3d.pixel.hlsl",
      "compileFlags": [
        "Skin" , "Particle" , "Line" , "Trail"
      ],
      "multiCompile": [
        ["CUSTOM_MACRO_A","__"],
        ["CUSTOM_MACRO_B","CUSTOM_MACRO_C"]
      ],
      "useMaterialRenderStates": true,
      "renderStates": {
        "blendOn": true,
        "blendSrc": "SRC_ALPHA",
        "blendDst": "ONE",
        "cullOn": false,
        "cullFace": "BACK",
        "depthWrite": false
      }
    }
  ]
}

一个 Effect 主要由以下几块组成

  1. name
  2. shaderProperties
  3. textures
  4. defaultRenderQueue
  5. passes

# shaderProperties

主要表示使用渲染中常量参数的格式,格式如下

  type ShaderProperties = Array<{
    // 对应 shader 中的 uniform 变量名
    key: string;
    // 数值类型,需与 shader 中uniform的类型对应
    type: "Float"|"Vector2"|"Vector3"|"Vector4";
    // 默认值,数组长度必须与 type 对应
    default: Array<number>;
  }>

# textures

主要表示使用渲染中用到的贴图的格式,格式如下

  type Textures = Array<{
    // 对应 shader 中的 texture 变量名
    key: string;
    // 贴图类型,需与 shader 中texture的类型对应
    type: "Texture2D" | "TextureCube";
    // 默认值,
    default: string;
  }>

其中,default的可选值有:

  • "white": 白色贴图,0xFFFFFFFF
  • "black": 黑色贴图,0x000000FF
  • "red": 红色贴图,0xFF0000FF
  • "green": 绿色贴图,0x00FF00FF
  • "blue": 蓝色贴图,0x0000FFFF
  • "bump": 默认法线贴图,0x808080FF
  • "transparent": 透明贴图,0xFFFFFF00

# defaultRenderQueue

指明使用该 Effect 创建的 Material 默认的RenderQueue

RenderQueue的定义,可见 Material 章节

# passes

描述具体的绘制流程。一个 Effect 可以拥有多个Pass, 每个 Pass 的格式如下:

type Pass = Array<{
    // vertexShader的相对路径
    vs:string;
    // fragmentShader的相对路径
    fs:string;
    // Pass的光照模式,默认是"ForwardBase"
    lightMode: string;
    // 内置编译的功能选项,每个选项实际上是一组内置宏的组合
    compileFlags?: PassCompileFlags[];
    // 该 pass 的多重编译选项
    multiCompile?: string[][];
    // 该 pass 的默认renderStates
    renderStates?: RenderStateDesc;
    // 该 pass 的默认 renderStates 是否会被 material 上的 renderStates 覆盖
    useMaterialRenderStates: boolean;
}>

type PassCompileFlags = "LightMap" | "Fog" | "Shadow" | "Skin" | "Particle" | "Line" | "Trail" | "Mesh.Color";

# renderStates

描述了该 pass 默认的渲染管线状态,格式如下

type RenderStateDesc = {
  blendOn?: boolean;
  blendSrc?: EnumBlendFactorString;
  blendDst?: EnumBlendFactorString;
  blendFunc?: EnumBlendOpString;
  cullOn?: boolean;
  cullFace?: EnumCullModeString;
  depthWrite?: boolean;
  depthTestOn?: boolean;
  depthTestComp?: EnumCompareFuncString;
  stencilWriteMask?: number;
  stencilTestOn?: boolean;
  stencilRef?: number;
  stencilReadMask?: number;
  stencilComp?: EnumCompareFuncString;
  stencilPass?: EnumStencilOpString;
  stencilFail?: EnumStencilOpString;
  stencilZFail?: EnumStencilOpString;
  primitiveType?: EnumPrimitiveTypeString;
}

enum EnumBlendFactorString {
	ZERO = "ZERO",
	ONE = "ONE",
	SRC_COLOR = "SRC_COLOR",
	ONE_MINUS_SRC_COLOR = "ONE_MINUS_SRC_COLOR",
	SRC_ALPHA = "SRC_ALPHA",
	ONE_MINUS_SRC_ALPHA = "ONE_MINUS_SRC_ALPHA",
	DST_COLOR = "DST_COLOR",
	ONE_MINUS_DST_COLOR = "ONE_MINUS_DST_COLOR",
	DST_ALPHA = "DST_ALPHA",
	ONE_MINUS_DST_ALPHA = "ONE_MINUS_DST_ALPHA",
	SRC_ALPHA_SATURATED = "SRC_ALPHA_SATURATED",
	BLEND_COLOR = "BLEND_COLOR",
	ONE_MINUS_BLEND_COLOR = "ONE_MINUS_BLEND_COLOR",
	BLEND_ALPHA = "BLEND_ALPHA",
	ONE_MINUS_BLEND_ALPHA = "ONE_MINUS_BLEND_ALPHA",
}

enum EnumBlendOpString {
	ADD = "ADD",
	SUBTRACT = "SUBTRACT",
	REVERSE_SUBTRACT = "REVERSE_SUBTRACT",
}

enum EnumCullModeString {
	NONE = "NONE",
	FRONT = "FRONT",
	BACK = "BACK",
}

enum EnumCompareFuncString {
	NEVER = "NEVER",
	LESS = "LESS",
	EQUAL = "EQUAL",
	LESS_EQUAL = "LESS_EQUAL",
	GREATER = "GREATER",
	NOT_EQUAL = "NOT_EQUAL",
	GREATER_EQUAL = "GREATER_EQUAL",
	ALWAYS = "ALWAYS",
}

enum EnumStencilOpString {
	KEEP = "KEEP",
	ZERO = "ZERO",
	REPLACE = "REPLACE",
	INCR_CLAMP = "INCR_CLAMP",
	DECR_CLAMP = "DECR_CLAMP",
	INVERT = "INVERT",
	INCR_WRAP = "INCR_WRAP",
	DECR_WRAP = "DECR_WRAP",
}

enum EnumPrimitiveTypeString {
	POINTS = "POINTS",
	LINES = "LINES",
	LINE_STRIP = "LINE_STRIP",
	TRIANGLES = "TRIANGLES",
	TRIANGLE_STRIP = "TRIANGLE_STRIP",
}

如果 useMaterialRenderStates 是false,则该 pass 上的 renderStates 将不会被 material 上的 renderStates 覆盖。可以用于如lightMode=ShaderCaster的 pass 上

# 多pass

一个 Effect 可以指定多个Pass,使用哪个 Pass 进行渲染是将根据 LightMode 进行自动选择。

在目前默认的内置 Forward 渲染管线中:

  • 如果定义了多个LightMode=ForwardBase的Pass,将会将同一个模型依次将每一个 Pass 渲染。可以用于绘制多层材质,例如头发;或者用于绘制双面材质。
  • 如果定义了LightMode=ShadowCaster的Pass,将会使用该 Pass 进行阴影投射的绘制,否则将使用内置的Fallback ShadowCaster Pass。可以用于定制阴影的效果,例如镂空阴影

# 自定义宏与变体

multiCompile配置指示需要编译哪些 Shader 变体组合

是一个二维数组,内层数组之间是互斥关系,外层数组之间是组合关系。

如示例

 [
    ["CUSTOM_MACRO_A","__"],
    ["CUSTOM_MACRO_B","CUSTOM_MACRO_C"]
  ]

将会被编译出4种 Shader 变体,分别为:

  1. CUSTOM_MACRO_A + CUSTOM_MACRO_B
  2. CUSTOM_MACRO_A + CUSTOM_MACRO_C
  3. CUSTOM_MACRO_B
  4. CUSTOM_MACRO_C

"__" 表示该项宏可为空

请不要使用__作为自定义宏名字的开头,以免与内置宏冲突。