基本概念
如何实现
通过控制模型的透明通道来实现透明效果
透明度
片元属性
0(完全透明,不显示)~1(完全不透明)
Unity中实现透明效果的方法
透明度测试
- 无需关闭深度写入,根据透明度决定是否舍弃片元(若透明度小于某值则舍弃,否则视为不透明物体)
- 由上面的处理方式可知,得到的效果只有完全透明和完全不透明两种
透明度混合(真正的半透明)
- 使用当前片元的透明度作为混合因子,与已存储在颜色缓冲中的颜色进行混合得到新颜色
- 需关闭深度写入(若不关闭则会导致无法显示半透明物体后面的物体(因距离摄像机远于半透明物体而被剔除),需开发者注意控制渲染顺序),未关闭深度测试(即在进行透明度混合时,深度缓冲只读)
- 比较片元的深度与深度缓冲中的深度,若片元更远则不进行处理,从而确保不透明物体能挡住半透明物体
- 深度缓冲(z-buffer)解决了不透明物体的渲染顺序
- 渲染片元时,将其深度值与已存在于深度缓冲中的值进行比较,若其距离摄像机更远,则可知不应将其渲染,否则,将其渲染并用其深度值更新深度缓冲(即深度缓冲中始终保存当前最靠近摄像机的内容,作为对照量来确认片元是否应被渲染)
渲染顺序
含义
因为事先透明效果需关闭深度写入,因此需开发者控制渲染顺序,按如下规则进行渲染
- 渲染所有不透明物体(开启深度测试和深度写入)
- 将半透明物体按距摄像机距离由远至近排序,按由远至近的顺序依次渲染(开启深度测试,关闭深度写入)
问题
上述规则的问题:循环重叠
- “将半透明物体排序”,深度缓冲中的值是像素级别的,一个物体与摄像机的距离无法确切反映其每个像素与摄像机的距离(无法解决3个物体循环重叠的问题)
解决问题的方法
准确的说是缓解,因为仍可能出错
- 减少错误排序
让模型是凸面体
复杂模型拆分为多个可独立排序的子模型 - 让错误(穿插)不明显
让透明通道更柔和
用开启了深度写入的半透明效果来近似模拟半透明
Unity中的渲染顺序
render queue
通过SubShader的Queue标签决定模型所属渲染队列
用整数索引表示各渲染队列,索引数越小越早被渲染
- Background 1000 背景上的物体
- Geometry 2000 默认(不透明)
- AlphaTest 2450 需使用透明度测试的物体
- Transparent 3000 按从后往前的顺序渲染,使用了透明度混合的物体都应使用本队列
- Overlay 4000 叠加效果
关闭深度写入的方法
- ZWrite Off:可以写在Pass或SubShader中
Unity中实现透明Shader
透明度测试
- 逐片元判断,若其透明度不满足条件(如小于指定阈值),舍弃片元,否则视为不透明物体
- 结果:只有透明和不透明两种情况
透明度混合
- 用片元的透明度作为混合因子,与颜色缓冲中的颜色进行混的得到新的颜色
- 混合时需关闭深度写入(开发者要自行留意渲染顺序)
关闭后无法对模型进行像素级别的深度排序,当模型网格间互相交叉时,得到的半透明效果是错误的(相互交叉) - Unity的Blend指令:Blend SrcFactor(源颜色的混合因子) DstFactor(目标颜色的混合因子)
源颜色和目标颜色各自乘以自己的混合因子,再相加
半透明效果(开启深度写入)
实现模型与其背景的混合效果,而模型内部之间不产生半透明效果(避免出现相互交叉的错误)
用两个Pass渲染模型(性能问题:因为多用了一个Pass)
- 开启深度写入,不输出颜色:将模型的深度值写入深度缓冲
Pass
{
ZWrite On // 开启深度写入
ColorMask 0 // 渲染命令:设置颜色通道的写掩码 0表示不写入任何颜色通道(不输出任何颜色)
}
- 进行正常的透明度混合
ShaderLab混合命令
混合等式和参数
混合是逐片元操作,不可编程,高度可配置
混合等式:已知源颜色和模板颜色,通过混合等式得到输出颜色
- 2个混合等式:混合RGB 和 混合A
- 每个等式有2个因子:与源颜色相乘的因子 和 与目标颜色相乘的因子
混合操作
对颜色和因子进行操作:加、减、取最小(源颜色和目标颜色中)、取最大(源颜色和目标颜色中)
常见的混合类型
混合类型:混合操作和混合因子命令的组合(类似PS的混合模式)
双面渲染的透明效果
默认情况下,渲染引擎剔除了物体背面(相对于摄像机方向)的渲染图元,只渲染了物体正面
对于半透明的物体,需要能在其正面看到其内部及背面的形状
使用Cull指令控制要剔除哪个面的渲染图元
Cull Back(不渲染背对摄像机的) | Front(不渲染朝向摄像机的) | Off (关闭剔除功能,渲染所有图元)
透明度测试的双面渲染
直接在Pass的渲染设置中使用Cull指令关闭剔除(Off)
透明度混合的双面渲染
不能直接关闭剔除(透明度混合关闭了深度写入,如果关闭剔除,会无法保证同一物体的正面和背面图元的渲染顺序,渲染顺序的错误会导致错误的半透明效果)
分2个Pass (保证背面一定在正面前被渲染,原因是Unity是顺序执行SubShader的各Pass的),第一个渲染背面(Cull Front)、第二个渲染正面(Cull Back)