介绍在Unity Shader里面常见的渲染状态选项

  1. Cull
  2. ZTest
  3. ZWrite
  4. Blend

Cull

在Unity Shader里,Cull 指令的作用是控制哪些面的三角形会被渲染,哪些会被剔除(不渲染),从而提高渲染效率并影响物体的显示效果。具体来说:

  1. 背面剔除(Backface Culling)
    当物体是一个封闭的3D模型时,其背面(从摄像机视角看不到的面)通常不需要渲染。通过剔除背面,可以减少约50%的渲染工作量,提高性能。
    示例

    Cull Back  // 剔除背面(默认值)
    
  2. 正面剔除(Frontface Culling)
    某些特殊效果(如内部结构展示、玻璃效果)可能需要渲染物体的内部,此时可以剔除正面,只渲染背面。
    示例

    Cull Front  // 剔除正面
    
  3. 双面渲染(No Culling)
    如果需要同时渲染物体的正面和背面(如树叶、飘动的旗帜),可以禁用剔除。但注意,这会增加渲染开销,且可能需要额外处理深度写入。
    示例

    Cull Off  // 双面渲染(不剔除)
    

应用场景

  • 性能优化:默认使用 Cull Back 剔除不可见的背面。
  • 特殊效果
    • 使用 Cull Front 实现内部结构的可见性。
    • 使用 Cull Off 配合 ZWrite Off 实现半透明物体的双面渲染。

注意事项

  • 深度冲突(Z-Fighting):双面渲染时,正反两面可能因深度值相近而产生闪烁,需通过调整深度偏移(Offset)解决。
  • 性能开销:双面渲染会增加片元处理量,慎用。

通过合理使用 Cull 指令,可以在保证视觉效果的同时优化渲染性能。


ZTest

在Unity Shader中,ZTest 指令用于控制深度测试的行为,决定哪些片段(pixels)会被最终渲染到屏幕上。深度测试是图形渲染中的一个关键步骤,它通过比较新片段与已存储在深度缓冲区(Z-buffer)中的深度值来确定是否绘制该片段。

ZTest 的语法

ZTest [ComparisonFunction]

其中 [ComparisonFunction] 是一个比较函数,定义了新片段的深度值与深度缓冲区中值的比较规则。常用的比较函数包括:

  • Less:仅当新片段的深度值 小于 缓冲区中的值时通过测试(默认值)。
  • Greater:仅当新片段的深度值 大于 缓冲区中的值时通过测试。
  • LEqual:仅当新片段的深度值 小于或等于 缓冲区中的值时通过测试。
  • GEqual:仅当新片段的深度值 大于或等于 缓冲区中的值时通过测试。
  • Equal:仅当新片段的深度值 等于 缓冲区中的值时通过测试。
  • NotEqual:仅当新片段的深度值 不等于 缓冲区中的值时通过测试。
  • Always:始终通过测试(所有片段都会被渲染)。
  • Never:始终不通过测试(所有片段都会被丢弃)。

应用场景

1. 默认行为(ZTest Less

  • 最常见的模式,确保离摄像机近的物体遮挡远的物体,实现正确的遮挡关系。
ZTest Less  // 默认值,近的物体覆盖远的物体

2. 透明物体(ZTest LEqual

  • 透明物体需要渲染所有片段(即使深度值相同),否则可能出现部分缺失。
ZTest LEqual  // 允许深度值相同的片段被渲染

3. 特殊效果(如轮廓、阴影)

  • ZTest Greater:可用于在已有的物体表面后方绘制轮廓或特效。
  • ZTest Always:强制渲染所有片段,常用于全屏后处理或UI元素。

与其他深度指令的配合

  • ZWrite:控制是否将片段的深度值写入深度缓冲区。
    • ZWrite On(默认):写入深度值,影响后续片段的深度测试。
    • ZWrite Off:不写入深度值,常用于半透明物体(避免遮挡后面的物体)。
  • Offset:调整深度值,用于解决深度冲突(Z-fighting)。

示例:透明物体的深度测试

以下是一个半透明材质的常见配置:

Tags { "RenderType"="Transparent" "Queue"="Transparent" }
ZWrite Off      // 不写入深度,避免遮挡其他物体
ZTest LEqual    // 允许深度相同的片段渲染(处理重叠部分)
Blend SrcAlpha OneMinusSrcAlpha  // 标准透明混合

注意事项

  1. 性能影响:复杂的深度测试(如 ZTest Always)可能增加GPU负担,尤其是在片段着色器计算量较大时。
  2. 渲染顺序:对于透明物体,通常需要调整渲染队列(Queue 标签)以确保从远到近渲染。
  3. 深度冲突:当两个物体深度值非常接近时,可能出现Z-fighting,可通过 Offset 或调整几何体解决。

通过合理配置 ZTest 和相关指令,可以精确控制3D场景中的遮挡关系和视觉效果。


ZWrite

在Unity Shader中,ZWrite 指令用于控制是否将片段的深度值写入深度缓冲区(Z-buffer)。深度缓冲区存储了每个像素位置上最近物体的深度信息,用于后续的深度测试(ZTest)。通过控制 ZWrite,可以影响物体之间的遮挡关系和渲染效果。

ZWrite 的语法

ZWrite [On|Off]
  • ZWrite On(默认值):将当前片段的深度值写入深度缓冲区。
  • ZWrite Off:不写入深度值,保留缓冲区中的原有值。

核心作用

1. 控制遮挡关系

  • 默认情况下,物体的每个片段都会写入深度值(ZWrite On),确保后续的片段正确被遮挡。
  • 示例
    ZWrite On  // 正常写入深度,近的物体遮挡远的物体
    

2. 实现特殊效果

  • 透明物体:通常需要 ZWrite Off,避免遮挡后面的物体。
    ZWrite Off  // 不写入深度,允许后面的物体透过透明物体显示
    
  • 重叠渲染:如光晕、粒子效果,需要多个物体同时可见。

ZTest 的配合

ZWrite ZTest 效果
On Less(默认) 正常遮挡,近的物体覆盖远的物体。
Off Less 不影响深度缓冲区,但自身会被其他物体正确遮挡(如半透明效果的基础配置)。
Off Always 强制渲染所有片段,不写入深度(常用于全屏特效或UI覆盖)。

典型应用场景

1. 半透明材质

半透明物体需要渲染所有层(如玻璃、水),但不应该遮挡后面的物体:

ZWrite Off      // 不写入深度,避免阻挡其他物体
ZTest LEqual    // 允许深度相同的片段渲染(处理重叠部分)
Blend SrcAlpha OneMinusSrcAlpha  // 透明混合模式

2. 叠加效果

如发光轮廓、UI元素,需要在已有物体上叠加渲染:

ZWrite Off      // 不写入深度,避免覆盖原有深度信息
ZTest Always    // 强制通过深度测试,确保片段被渲染

3. 双面渲染的透明物体

双面渲染时,若正反两面都写入深度,可能导致错误的遮挡:

Cull Off        // 双面渲染
ZWrite Off      // 禁用深度写入,防止自遮挡

注意事项

  1. 渲染顺序影响

    • ZWrite Off 的物体依赖渲染顺序,需通过 Queue 标签控制(如 Queue=Transparent)。
    • 通常需要从远到近渲染透明物体,确保正确的混合效果。
  2. 性能考虑

    • ZWrite Off 可能增加Overdraw(重复渲染),因为深度缓冲区未更新。
  3. 深度冲突(Z-Fighting)

    • 当两个物体深度相近且 ZWrite On 时,可能出现闪烁,可通过 Offset 指令调整。

错误配置示例

  • 错误:透明物体使用 ZWrite On,会导致后续透明片段被错误遮挡。
  • 正确:透明物体必须使用 ZWrite Off,并配合 Blend 指令实现混合。

通过合理控制 ZWrite,可以精确控制物体的遮挡关系,实现透明、叠加等复杂视觉效果。


Blend

在Unity Shader中,Blend 指令用于控制片段着色器输出的颜色如何与帧缓冲区中已有的颜色进行混合。这对于实现透明、半透明、发光效果等至关重要。

Blend 的基本语法

Blend [源因子] [目标因子]        // 基本混合模式
Blend [源因子] [目标因子], [源因子A] [目标因子A]  // 分离RGB和Alpha通道的混合

其中:

  • 源因子:表示新渲染片段的颜色权重。
  • 目标因子:表示帧缓冲区中已有颜色的权重。

常见混合因子

因子名 含义
Zero 0
One 1
SrcColor 源颜色值
OneMinusSrcColor 1 - 源颜色值
DstColor 目标颜色值(已在缓冲区中)
OneMinusDstColor 1 - 目标颜色值
SrcAlpha 源Alpha值
OneMinusSrcAlpha 1 - 源Alpha值
DstAlpha 目标Alpha值
OneMinusDstAlpha 1 - 目标Alpha值

常见混合模式及应用场景

1. 标准透明(Alpha Blending)

Blend SrcAlpha OneMinusSrcAlpha
  • 效果:根据源Alpha值,将新颜色与目标颜色混合。
  • 应用:半透明物体(如玻璃、树叶)。

2. 加法混合(Additive Blending)

Blend One One
  • 效果:颜色叠加,常用于发光效果(如粒子、光晕)。
  • 应用:特效、灯光、能量场。

3. 乘法混合(Multiplicative Blending)

Blend DstColor Zero
  • 效果:新颜色乘以目标颜色,常用于阴影或变暗效果。

4. Alpha 预乘(Premultiplied Alpha)

Blend One OneMinusSrcAlpha
  • 效果:源颜色已包含Alpha信息,适合纹理本身已预乘Alpha的情况。

分离RGB和Alpha通道的混合

Blend SrcAlpha OneMinusSrcAlpha, One Zero
  • 含义:RGB通道使用标准透明混合,Alpha通道完全替换目标Alpha。

配合其他指令的典型配置

1. 半透明物体

Tags { "RenderType"="Transparent" "Queue"="Transparent" }
ZWrite Off           // 不写入深度,避免遮挡后面的物体
Blend SrcAlpha OneMinusSrcAlpha  // 标准透明混合

2. 发光效果

ZWrite Off           // 不影响深度缓冲区
Blend One One        // 加法混合,增强亮度

3. 双面透明物体

Cull Off             // 双面渲染
ZWrite Off           // 避免自遮挡
Blend SrcAlpha OneMinusSrcAlpha  // 透明混合

注意事项

  1. 渲染顺序:透明物体通常需要从远到近渲染,通过 Queue 标签控制:

    Tags { "Queue"="Transparent" }  // 在不透明物体后渲染
    
  2. 性能开销:混合操作通常比直接覆盖(Blend Off)更消耗性能。

  3. Alpha 测试 vs Alpha 混合

    • Alpha 测试discard 指令):非黑即白的透明度(如草叶)。
    • Alpha 混合:平滑的半透明效果,但需要正确的渲染顺序。

特殊混合模式示例

1. 屏幕混合(Screen Blend)

Blend OneMinusDstColor One  // 常用于HDR效果

2. 减色混合

Blend OneMinusDstColor Zero  // 从目标颜色中减去源颜色

通过灵活配置 Blend 指令,可以实现从简单透明到复杂特效的各种视觉效果。