一、前言
实现透明效果,通常会采取在渲染模型时控制它的透明通道。
一个物体被渲染到屏幕上时,一个片元除了颜色值和深度值外,还有一个透明度属性。透明度为1表示该像素完全不透明,透明度为0表示,像素完全不会显示。
对于渲染顺序问题:
对于不透明物体,不考虑渲染顺序也可以得到正确的排序效果,这是因为强大的深度缓冲的效果:根据深度缓冲中的值来判断该片元距离摄像机的距离,当渲染一个片元时,需要把它的深度值和已经存在与深度缓冲中的值进行比较(开启了深度测试),如果它的值距离摄像机更远,那么这个片元就不应该被渲染到屏幕上,否则这个片元应该覆盖掉此时颜色缓冲中的像素值,并把它的深度值更新到深度缓冲中(开启了深度写入)。
对于透明物体,就不是那么简单了。
实现透明效果的两种方法:
1.透明度测试:
采用了一种机制,只要一个片元的透明度不满足条件(通常是小于某个阙值),那么它对应的片元就会被舍弃。被舍弃的将不会再进行任何处理,也不会对颜色缓冲进行影响。透明度测试不需要关闭深度写入,他只会根据透明度来舍弃一些片元。虽然简单但是极端,要么完全看不到,要么完全不透明。
2.透明度混合:
这种方法可以得到真正的半透明效果,他会使用当前的透明度作为混合因子,与已经存储在颜色缓冲中的颜色值进行混合,得到新的颜色。但透明度混合需要关掉深度写入(否则透明物体后面的物体将会被判断为更远,就会让后面物体消失,从而看不见透明后面的物体),所以我们需要非常注意物体的渲染顺序,但其并没有关闭深度测试。这意味着,使用透明度混合渲染一个片元时,还是会比较深度值和当前存储在深度缓冲中的深度值。如果它的深度值距离摄像机更远,那么就不会进行混合操作。这一点决定了,当一个不透明物体出现在一个透明物体前面时,而我们先渲染了不透明物体,他仍然可以正常的遮住透明物体,也就是说,对于透明度混合来说,深度缓冲是只读的。
二、渲染顺序的重要性
163页做了为什么顺序重要的讲解,结论:
渲染引擎一般会对物体进行排序、再渲染,常用的方法:
1.先渲染所有的不透明物体,并开启他们的深度测试和深度写入。
2.把半透明物体按他们距离摄像机的远近进行排序,然后按照从后向前的顺序渲染这些半透明物体,并开启他们的深度测试,关闭深度写入。
对于一些特殊情况:
1、如果3个物体相互重叠,那么可以进行物体拆分成两部分再进行排序。
2、如果两个物体成竖直错位方式,进行分割网格。
建议:
1、为了减少错误排序的情况,物体模型尽量采用凸面体,并且将复杂的模型拆分成可以独立排序的多个子模型。
2、如果对于一些错误结果我们不行拆分网格,那我们也可以让透明通道更加柔和,使其穿插起来看起来不那么明显。
3、我们也可以使用开启了深度写入的半透明效果来近似模拟物体的半透明。
三、Untiy中的渲染顺序
也就是说如果我们想要
1.通过透明度测试实现透明效果,代码中应该包含:
Subshader
{
Tags{"Queue"="AlphaTest"}
Pass{...}
}
2.通过透明度混合来实现透明效果,代码应该:
Subshader
{
Tags{"Queue"="Transparent"}
Pass
{
ZWrite Off //意为关闭深度写入,也可写在Subshader中,起到影响所有Pass的结果。
}
}