US3S3L3——设置混合命令

混合

在进行渲染状态的混合相关设置中,我们的步骤为:

  1. 进行混合操作的设置(非必须,默认为 Add​ )
  2. 进行混合方式的设置(主要设置混合因子)

常见的混合类型包括:透明度混合、柔性相加、正片叠底、两倍相乘、变暗、变亮、滤色、线性减淡

混合的基本原理

当我们在进行渲染时,当片元通过了深度测试后,会进入到混合流程中。

image

在混合流程中:

  • 当前片元的颜色被称为 源颜色
  • 颜色缓冲区中的颜色被称为 目标颜色

混合 就是将 源颜色 和 目标颜色 用对应的混合算法进行计算后
输出一个新的颜色 更新到颜色缓冲区中

注意:这些颜色都是 RGBA,包含透明通道A

混合方式

我们之前在学习 SubShader 语法时学过,
在编写Shader时可以通过添加 混合方式 Blend​ 的渲染状态
来控制 源颜色 和 目标颜色 如何进行混合计算

以正常透明混合为例:

1
2
3
4
5
6
Pass
{
Tags { "LightMode" = "ForwardBase" }
ZWrite Off //关闭深度写入
Blend SrcAlpha OneMinusSrcAlpha //设置混合模式,以正常透明混合为例
}

混合默认是关闭的,当我们在使用了 Blend​ 混合命令时(除 Blend off​),Unity内部就会自动的帮助我们开启混合
我们在实现透明效果时,需要设置混合方式这个渲染状态

混合的计算规则

我们假设

  • 当前片元的颜色被称为 源颜色=S (source)源颜色 = S\ (source)
  • 颜色缓冲区中的颜色被称为 目标颜色=D (destination)目标颜色 = D\ (destination)
  • 混合后的 输出颜色=O (out)输出颜色 = O\ (out)

混合计算的规则就是需要构建两个混合等式:

  • 计算 RGB 通道的混合等式

    Orgb=源因子×Srgb+目标因子×DrgbO_{rgb} = 源因子 \times S_{rgb} + 目标因子 \times D_{rgb}

  • 计算 A 通道的混合等式

    Oa=源透明因子×Sa+目标透明因子×DaO_a = 源透明因子 \times S_a + 目标透明因子 \times D_a

从渲染状态上体现,如下段代码所示,包括两种写法:

1
2
3
4
5
6
7
Pass
{
Tags { "LightMode" = "ForwardBase" }
ZWrite Off //关闭深度写入
Blend 原因子 目标因子, 原透明因子 目标透明因子 //写法一:混合方式的基本格式
Blend 原因子 目标因子 //写法二:混合方式的省略格式
}

如果我们使用方式二来设置因子,由于没有指定透明相关因子,因此,在计算时:

  • 源透明因子 = 源因子
  • 目标透明因子 = 目标因子

混合计算的混合等式为

  • 计算 RGB 通道的混合等式

    Orgb=源因子×Srgb+目标因子×DrgbO_{rgb} = 源因子 \times S_{rgb} + 目标因子 \times D_{rgb}

  • 计算 A 通道的混合等式

    Oa=源因子×Sa+目标因子×DaO_a = 源因子 \times S_a + 目标因子 \times D_a

混合因子

在 Unity 当中 ShaderLab 为我们提供了很多设定好的混合因子,我们根据需求直接使用即可

混合因子 描述
One 因子为 1
Zero 因子为 0
SrcColor 因子为源颜色值,混合RGB时用它的RGB作因子;混合A时用它的A
SrcAlpha 因子为源颜色的透明度值(A通道)
DstColor 因子为目标颜色值,混合RGB时用它的RGB作因子;混合A时用它的A
DstAlpha 因子为目标颜色的透明度值(A通道)
OneMinusSrcColor 因子为 (1源颜色)(1-源颜色),混合RGB时用它的RGB作因子;混合A时用它的A
OneMinusSrcAlpha 因子为 (1源颜色的透明度值)(1-源颜色的透明度值)(A通道)
OneMinusDstColor 因子为 (1目标颜色)(1-目标颜色),混合RGB时用它的RGB作因子;混合A时用它的A
OneMinusDstAlpha 因子为 (1目标颜色的透明度值)(1-目标颜色的透明度值)(A通道)

以下面两个渲染状态为例:

1
2
3
4
5
6
Pass
{
Tags { "LightMode" = "ForwardBase" }
ZWrite Off //关闭深度写入
Blend SrcAlpha OneMinusSrcAlpha, One Zero //设置混合因子
}

根据上面的混合计算公式,得到该渲染状态的混合计算公式为:

{Orgb=Sa×Srgb+(1Sa)×DrgbOa=1×Sa+0×Da\begin{cases} O_{rgb} = S_a \times S_{rgb} + (1 - S_a) \times D_{rgb} \\ O_a = 1 \times S_a + 0 \times D_a \end{cases}

1
2
3
4
5
6
Pass
{
Tags { "LightMode" = "ForwardBase" }
ZWrite Off //关闭深度写入
Blend SrcAlpha OneMinusSrcAlpha //设置混合因子
}

根据上面的混合计算公式,得到该渲染状态的混合计算公式为:

{Orgb=Sa×Srgb+(1Sa)×DrgbOa=Sa×Sa+(1Sa)×Da\begin{cases} O_{rgb} = S_a \times S_{rgb} + (1 - S_a) \times D_{rgb} \\ O_a = S_a \times S_a + (1 - S_a) \times D_a \end{cases}

混合操作

刚才学习的混合计算规则当中,都是使用对应混合因子和源颜色与目标颜色相乘后再相加。
其实 Unity 当中还可以选择其他的计算方式来进行混合计算
在 ShaderLab 当中除了可以使用 Blend​ 混合命令来设定混合因子
还提供了一个 BlendOp​ 混合操作命令来设定混合的计算方式,它的基本语法是:

1
2
3
4
5
6
7
Pass
{
Tags { "LightMode" = "ForwardBase" }
ZWrite Off //关闭深度写入
BlendOp 混合操作 //设置混合操作
Blend 原因子 目标因子, 原透明因子 目标透明因子 //混合方式的基本格式
}
混合操作 描述
Add​(默认操作) 用混合后的源颜色和目标颜色相加
{Orgb=源因子×Srgb+目标因子×DrgbOa=源透明因子×Sa+目标透明因子×Da\begin{cases} O_{rgb} = 源因子 \times S_{rgb} + 目标因子 \times D_{rgb} \\ O_a = 源透明因子 \times S_a + 目标透明因子 \times D_a \end{cases}
Sub 用混合后的源颜色和目标颜色相减
{Orgb=原因子×Srgb目标因子×DrgbOa=目标透明因子×Sa源透明因子×Da\begin{cases} O_{rgb} = 原因子 \times S_{rgb} - 目标因子 \times D_{rgb} \\ O_a = 目标透明因子 \times S_a - 源透明因子 \times D_a \end{cases}
RevSub 用混合后的目标颜色减去混合后的源颜色
{Orgb=目标因子×Drgb原因子×SrgbOa=目标透明因子×Da源透明因子×Sa\begin{cases} O_{rgb} = 目标因子 \times D_{rgb} - 原因子 \times S_{rgb} \\ O_a = 目标透明因子 \times D_a - 源透明因子 \times S_a \end{cases}
Min 使用源颜色和目标颜色中较小的值(逐分量比较,无需和因子计算)
Orgba=(min(Sr,Dr),min(Sg,Dg),min(Sb,Db),min(Sa,Da))O_{rgba}=(min(S_r,D_r),min(S_g,D_g),min(S_b,D_b),min(S_a,D_a))
Max 使用源颜色和目标颜色中较大的值(逐分量比较,无需和因子计算)
Orgba=(max(Sr,Dr),max(Sg,Dg),max(Sb,Db),max(Sa,Da))O_{rgba}=(max(S_r,D_r),max(S_g,D_g),max(S_b,D_b),max(S_a,D_a))
其他混合操作 无法全平台支持,部分仅支持 Windows DX11 及以上,部分仅支持高版本 OpenGL
所有混合操作及其支持平台,详见:ShaderLab 命令:BlendOp - Unity 手册

常见混合类型

  1. 透明度混合(Normal)

    1
    Blend SrcAlpha OneMinusSrcAlpha

    image

  2. 柔和相加(Soft Additive)

    1
    Blend OneMinusSrcColor One

    image

  3. 正片叠底(Multiply),相当于源和目标相乘

    1
    Blend DstColor Zero

    image

  4. 两倍相乘(2x Multiply)

    1
    Blend DstColor SrcColor

    image

  5. 变暗(Darken)

    1
    2
    BlendOp Min
    Blend One One

    image

  6. 变亮(Lighten)

    1
    2
    BlendOp Max
    Blend One One

    image

  7. 滤色(Screen)

    1
    Blend OneMinusDstColor One

    相当于

    1
    Blend One OneMinusSrcColor

    image

  8. 线性减淡(Linear Dodge)

    1
    Blend One One

    image