《Unity Shader入门精要》读书笔记07

铁名_IronName Lv2

第 8 章 透明效果

  • 透明通道(Alpha Channel)
  • 实现透明效果的两种方法:透明度测试(Alpha Test);透明度混合(Alpha Blending)。
  • 透明度测试:简单,根据透明度舍弃片元,但是效果极端。
  • 透明度混合:真正的半透明效果。

渲染顺序很重要

前面说到,对于透明度混合技术,需要关闭深度写入,此时我们就需要小心处理透明物体的渲染顺序。那么,我们为什么要关闭深度写入呢?如果不关闭深度写入,一个半透明表面背后的表面本来是可以透过它被我们看到的,但由于深度测试时判断结果是该半透明表面距离摄像机更近,导致后面的表面将会被剔除,我们也就无法透过半透明表面看到后面的物体了。但是,我们由此就破坏了深度缓冲的工作机制,而这是一个非常非常非常(重要的事情要讲3遍)糟糕的事情,尽管我们不得不这样做。关闭深度写入导致渲染顺序将变得非常重要。

半透明和不透明物体之间,半透明物体之间的渲染顺序都很重要。

为什么半透明物体之间也要考虑顺序?

假设有一个红色玻璃(透明度0.5)在一个蓝色玻璃(透明度0.5)后面。让我们看看两种渲染顺序的区别:

渲染顺序步骤1:先画蓝色步骤2:再画红色最终结果(数学计算)
先蓝后红缓冲区初始为黑色(0,0,0)
绘制蓝色:(0,0,0.5)
计算:(0,0,1)*0.5 + (0,0,0)*0.5 = (0,0,0.5)
在蓝色(0,0,0.5)上画红色(0.5,0,0)
计算:(1,0,0)*0.5 + (0,0,0.5)*0.5 = (0.5,0,0.25)
(0.5, 0, 0.25)
先红后蓝缓冲区初始为黑色(0,0,0)
绘制红色:(0.5,0,0)
计算:(1,0,0)*0.5 + (0,0,0)*0.5 = (0.5,0,0)
在红色(0.5,0,0)上画蓝色(0,0,0.5)
计算:(0,0,1)*0.5 + (0.5,0,0)*0.5 = (0.25,0,0.5)
(0.25, 0, 0.5)

由DeepSeek生成

渲染引擎一般都会先对物体进行排序,再渲染:
(1)先渲染所以不透明物体,并开启透明的深度测试和深度写入。
(2)把半透明的物体按照他们距离摄像机的远近进行排序,然后按照从后往前的顺序渲染这些半透明物体,并开启它们的深度测试,但是关闭深度写入。

无论选择哪种判断物体深度值的方法,某些情况下都会出现错误的遮挡关系。

常见的解决方法就是分割网格。还可以尽可能让模型是凸面体,将复杂的模型拆成可以独立排序的多个子模型;试着让透明通道更加柔和,使穿插看起来并不是那么明显;使用开启了透明深度写入的半透明效果,来近似模拟物体的半透明。

Unity Shader 的渲染顺序

使用SubShader 的 Queue 标签来决定模型归于哪个渲染队列(render queue)
-> Background :背景
-> Geometry :大多数物体使用;不透明物体使用
-> AlphaTest :需要透明度测试的物体
-> Transparent :从后往前渲染,使用了透明度混合的物体使用
-> Overlay : 叠加效果;最后渲染的物体
代码:

1
2
3
4
5
6
7
SubShader {
Tags { "Queue" = "AlphaTest" } // or Tags { "Queue" = "Transparent" }
Pass {
...
// ZWrite Off 关闭深度写入。也可以写在SubShader中,关闭所有Pass的深度写入
}
}

实践:透明度测试

在片元着色器中使用 clip 函数进行透明度测试。

实践

在 Unity 中实现透明度测试的效果。

我们需要把Queue标签设置为AlphaTest。而RenderType标签可以让Unity把这个Shader归入到提前定义的组(这里就是TransparentCutout组)中,以指明该Shader是一个使用了透明度测试的Shader。RenderType标签通常被用于着色器替换功能。我们还把IgnoreProjector设置为True,这意味着这个Shader不会受到投影器(Projectors)的影响。通常,使用了透明度测试的Shader都应该在SubShader中设置这三个标签。

1
2
3
4
5
6
// Alpha test
clip(texColor.a - _Cutoff);
// 等价于
// if((texColor.a-_Cutoff)<0.0) {
// discard;
// }

实践:透明度测试

真正的半透明效果。

实践

在 Unity 中实现透明度测试的效果。

混合命令——Blend

Blend Off 关闭混合;
Blend SrcFactor DstFactor 开启混合,并设置混合因子;
Blend SrcFactor DstFactor, SrcFactorA DstFactorA 如上,另外控制透明度的混合
BlendOp BlendOperation 使用 BlendOperation 进行其他操作

开启深度写入的半透明效果

由于关闭深度写入而造成的错误排序,一种解决方法是:使用两个Pass渲染模型。
第一个Pass开启深度写入,但不输出颜色;第二个 Pass 按照像素级别的深度排序结果进行透明渲染。

实践

在 Unity 中实现开启深度写入的半透明效果。

在原来的 Pass 前新增一个 Pass

1
2
3
4
Pass {
ZWrite On
ColorMask 0 // 该 Pass 不写入任何颜色通道
}

这个 Pass 只把模型的深度信息写入深度缓冲,从而剔除模型中被自身遮挡的片元。
ColorMask 用于设置颜色通道的写掩码(write mask)

1
ColorMask RGB | A | 0 | 其他任何 R G B A 的组合

ShaderLab的混合命令

总之就是控制混合的。用到再查。

双面渲染的透明效果

实践

在 Unity 中实现透明度测试的双面渲染。
加一行 Cull Off 来关闭背面剔除即可

1
Cull Back | Front | Off // 默认为Back,即背面剔除

透明度混合的双面渲染

注意

由于关闭了深度写入,如果只是关闭剔除,那么可能出现正面和背面渲染顺序错乱的情况。

所以我们用两个Pass,先渲染背面,再渲染正面。在原有代码上修改:
(1)复制原Pass的代码,得到另一个Pass。
(2)在两个 Pass 中分别使用 Cull 指令剔除不同朝向的渲染图元。

实践

在 Unity 中实现透明度混合的双面渲染。

  • 标题: 《Unity Shader入门精要》读书笔记07
  • 作者: 铁名_IronName
  • 创建于 : 2026-01-18 10:43:08
  • 更新于 : 2026-01-19 14:42:52
  • 链接: https://blog.ironname.top/2026/01/18/《Unity-Shader入门精要》读书笔记07/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论