UnityShander开发之透明
透明中需要关注的点
1.深度写入
简单来说就是缓存像素的深度值,通过比较深度值,较浅的显示,较深的被覆盖。
1.1 两物体交叉时
1.1.1 无深度写入时
会有当红色的面片的中心点低于白色的面片时:
出现在交叉区域一直都是白色显示在上方,而实际上是有时候白色在上方,后时候红色在上方
这是由于没有深度的数据,较后渲染的面片会直接将较先渲染的面片作为底色进行透明度混合
1.1.2 有深度写入时
会有当红色的面片的中心点低于白色的面片时:
出现红色面片盖住白色面片区域红色直接覆盖了,而白色面片盖住红色的区域正常显示
这是由于有深度的数据,较后渲染的面片会因为深度比较浅,导致颜色值无法写入颜色缓冲区、进行颜色透明度混合
1.1.3 Unity中的使用
ZWrite Off 为关闭
ZWrite On 为开启
SubShader {
Tags {"Queue"="Transparent" }
Pass {
...
ZWrite Off
...
}
}
1.2 自身有复杂层次关系的
1.2.1 无深度写入时
1.2.2 有深度写入时
该情况较为特殊,由于上面提到的深度写入时写在一个通道里面的,而一边自身渲染一边获取深度是不行的,所以需要再创建一个只用作深度写入的通道。
1.2.3 Unity中的使用
SubShader {
Tags {"Queue"="Transparent" }
// Extra pass that renders to depth buffer only
Pass {
ZWrite On
ColorMask 0
}
Pass {
...
ZWrite Off
...
}
}
2.渲染顺序
物体类型 | 深度写入 | 颜色写入 |
---|---|---|
半透明物体 | 不开启 | 开启 |
不透明物体 | 开启 | 开启 |
复杂半透明的物体通常会关闭单通道的深度写入(如表格所示),不会往深度缓冲区写入数据,那么这个时候由两个物体,分别为透明物体A(圆形)与不透明物体B(正方形),且A在B前方。
2.1 举例说明
1.当B在A之前渲染
B先渲染 :B访问深度缓冲区与颜色缓冲区,都没有数据,直接写入
A后渲染:A访问颜色缓冲区,有颜色,通过混合因子进行颜色混合
出来的渲染图是合理的
2.当A在B之前渲染
A先渲染:A访问颜色缓冲区,无数据,直接写入数据
B后渲染:B访问深度缓冲区,无数据,直接写入,根据深度缓冲区的数据,A无深度,B将会直接将A的颜色缓冲盖掉
这样子出来的渲染图明显是错误的
所以,在透明的开发中,渲染的顺序十分重要
2.2 在Shader需要的配置
名称 | 索引号 | 描述 |
---|---|---|
Background | 1000 | 这个渲染队列会在任何其他队列之前被渲染,我们通常使用该队列来渲染那些需要绘制在背景上的物体 |
Geometry | 2000 | 默认渲染队列,大多数物体都是用这个队列,不透明物体使用这个队列 |
AlphaTest | 2450 | 需要透明度测试的物体使用这个队列 |
Transparent | 3000 | 这个队列中的物体会在所有Geometry和AlphaTest物体渲染后,再按从后往前的顺序进行渲染,任何使用了透明度混合(例如关闭了深度写入)都应使用该队列 |
Overlay | 4000 | 该队列用于实现一些叠加效果,任何需要在最后渲染的物体都应该使用该队列 |
通常需要在子着色器中设置渲染队列为 “Transparent”,这样Unity在渲染时就会将该物体放到Transparent渲染队列中
SubShader {
Tags { "Queue"="Transparent" }
Pass{
...
}
}
3.混合因子
3.1 语义
语义 | 描述 |
---|---|
Blend Off | 关闭混合 |
Blend SrcFactor DstFactor | 开启混合,并设置混合因子,源颜色(该片元产生的颜色)会乘于SrcFactor,而目标颜色(已经存在于颜色缓存的颜色)会乘以DstFactor,然后把两者相加后再存入颜色缓冲中 |
Blend SrcFactor DstFactor,SrcFactorA DstFactorA | 和上面几乎一样,只是使用不同的因子来混合透明通道 |
BlendOp BlendOperation | 并非是把源颜色和目标颜色简单地加减后混合,而是使用BlendOperation来对他们进行其他操作 |
3.2 参数
参数 | 描述 |
---|---|
One | 因子为 1 |
Zero | 因子为 0 |
SrcColor | 因子为源颜色值,当用于混合RGB通道的混合等式时,使用SrcColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用SrcColor的A分量作为混合因子 |
SrcAlpha | 因子为源颜色的透明度值(A通道) |
DstColor | 因子为目标颜色值。当用于混合RGB通道的混合等式时,使用DstColor的RGB分量作为混合因子;当用于混合A的混合等式时,使用DstColor的A分量作为混合因子 |
DstAlpha | 因子为目标颜色的透明度值(A通道) |
OneMinusSrcColor | 因子为(1-源颜色)。当用于混合RGB通道的混合等式时,使用结果的的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子 |
OneMinusSrcAlpha | 因子为(1-源颜色的透明度值) |
OneMinusDstColor | 因子为(1-目标颜色)。当用于混合RGB通道的混合等式时,使用结果的的RGB分量作为混合因子;当用于混合A的混合等式时,使用结果的A分量作为混合因子 |
OneMinusDstAlpha | 因子为(1-目标颜色的透明度值) |
操作 | 描述 |
---|---|
Add | 将混合后的源颜色和目标颜色相加。默认的混合操作。使用的混合等式是: O r g b = S r c F a c t o r ∗ S r g b + D s t F a c t o r ∗ D r g b O_{rgb}=SrcFactor *S_{rgb}+DstFactor *D_{rgb} Orgb=SrcFactor∗Srgb+DstFactor∗Drgb O a = S r c F a c t o r A ∗ S a + D s t F a c t o r A ∗ D a O_{a}=SrcFactorA *S_{a}+DstFactorA *D_{a} Oa=SrcFactorA∗Sa+DstFactorA∗Da |
Sub | 将混合后的源颜色减去混合后的目标颜色。使用的混合等式是: O r g b = S r c F a c t o r ∗ S r g b − D s t F a c t o r ∗ D r g b O_{rgb}=SrcFactor *S_{rgb}-DstFactor *D_{rgb} Orgb=SrcFactor∗Srgb−DstFactor∗Drgb O a = S r c F a c t o r A ∗ S a − D s t F a c t o r A ∗ D a O_{a}=SrcFactorA *S_{a}-DstFactorA *D_{a} Oa=SrcFactorA∗Sa−DstFactorA∗Da |
RevSub | 将混合后的目标颜色减去混合后的源颜色。使用的混合等式是: O r g b = D s t F a c t o r ∗ D r g b − S r c F a c t o r ∗ S r g b O_{rgb}=DstFactor *D_{rgb}-SrcFactor *S_{rgb} Orgb=DstFactor∗Drgb−SrcFactor∗Srgb O a = D s t F a c t o r A ∗ D a − S r c F a c t o r A ∗ S a O_{a}=DstFactorA *D_{a}-SrcFactorA *S_{a} Oa=DstFactorA∗Da−SrcFactorA∗Sa |
Min | 使用源颜色和目标颜色中较小的值,是逐分量比较的,使用的混合等式为: O r g b a = ( m i n ( S r , D r ) , m i n ( S g , D g ) , m i n ( S b , D b ) , m i n ( S a , D a ) ) O_{rgba}=(min(S_r,D_r),min(S_g,D_g),min(S_b,D_b),min(S_a,D_a)) Orgba=(min(Sr,Dr),min(Sg,Dg),min(Sb,Db),min(Sa,Da)) |
Max | O r g b a = ( m a x ( S r , D r ) , m a x ( S g , D g ) , m a x ( S b , D b ) , m a x ( S a , D a ) ) O_{rgba}=(max(S_r,D_r),max(S_g,D_g),max(S_b,D_b),max(S_a,D_a)) Orgba=(max(Sr,Dr),max(Sg,Dg),max(Sb,Db),max(Sa,Da)) |
3.3 在Unity中的使用
在通道内设置
SubShader {
Tags { "Queue"="Transparent" }
Pass{
...
Blend SrcAlpha OneMinusSrcAlpha
...
}
}
4.双面渲染
将双面的面片都渲染出来
4.1 在Unity中的使用
SubShader {
Tags { "Queue"="Transparent" }
Pass{
...
Cull Front
...
}
Pass{
...
Cull Back
...
}
}