深度测试-透明测试

Reference

鄙人知识浅薄仅仅是对大佬的文章以自己的理解描述了一下,有些实在自己描述不好就摘抄了
如果实在觉得写的不好,是本人水平有限,还请前往前往原文处观看

图形学|shader|用一篇文章理解半透明渲染、透明度测试和混合、提前深度测试并彻底理清渲染顺序。 - 知乎 (zhihu.com)

深度测试

如果在渲染的时候我们仅仅按照绘制物体的先后顺序来渲染那么会出现以下情况无法绘制:

图1 物体的互相遮挡关系

这个时候我们就可以使用深度测试,也就是z-buffer算法

我们需要维护两个容器,一个存储了屏幕上所有像素的颜色值,我们管他叫帧缓冲Frame buffer
另外一个存储了屏幕上所有像素的深度值,我们管他叫深度缓冲Z-buffer

何为深度值呢?深度值是这个点与摄象机之间的距离,深度值越小越接近摄象机。

所以我们开始讲解一下深度测试,流程如下:

C++伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//伪代码
color[][] frame_buffer;
int[][] z_buffer;

void z_test(fragements){
for(item in fragements) {
int x = item.x;
int y = item.y;
if(z_buffer[x][y] > item.z) {
if(z_write) {
z_buffer[x][y] = item.z;
}
frame_buffer[x][y] = item.color;
}
}
}

透明测试

那么透明的物体该怎么办呢?,如果一个透明的物体在一个不透明的物体前面那么不是只显示透明的物体了吗?

但是这是不对的,想象一下,你站在一块窗户面前,却看不到任何窗户外的景色这不对吧?

步骤一 关闭深度写入

所以为了让透明物体不挡住不透明物体,我们需要关闭透明物体的深度写入,那么透明物体无法写入深度值,即使透明物体的深度值更加小,但是只有开启了深度写入的物体的深度值才可以写入,这样我们就可以让不透明物体透明物体前面了(具体地说是像素)。

在Shader中对应的就是, **ZWrite Off ** ,

这里祭出我已近很久没用的Shader基本功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Shader "Unlit/NewUnlitShader"  
{
Properties
{
_Color("Color",Color) = (0.5,0.5,0.5,1)

}

SubShader
{
LOD 100

Pass
{
ZWrite Off

CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"

struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};

struct v2f
{
float4 vertex : SV_POSITION;
};

float4 _Color;

v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_FOG(o, o.vertex);
return o;
}

fixed4 frag(v2f i) : SV_Target
{
// sample the texture
fixed4 col = _Color;
return col;
}
ENDCG
}
}
}

步骤二 渲染队列

但是,仅仅关闭深度写入的话就会出现,遮挡关系错乱的情况,例如:

一个透明物体在不透明物体的前面,然而渲染出来确是,不透明物体遮挡了透明物体。

因为,透明物体关闭了深度写入,意味着即使不透明在透明物体后面,不透明物体也可以写入深度值,从而更新颜色。

在Shader中对应的就是,**”Queue” = “Transparent”**

  1. 先渲染不透明物 :对于不透明物,渲染顺序并不影响其渲染结果,因此谁先谁后无所谓。当然为了优化效率,unity的不透明物里是按照从近往远绘制。
  2. 再渲染全透明物 :对于全透明物,unity使用透明度测试(AlphaTest)进行优化,当片元的透明度小于设置的阈值时,就当作全透明处理,否则就当作不透明处理。
  3. 最后渲染半透明物 :由远及近严格顺序绘制。

步骤三 Alpha混合 Alpha Blending

但是的话作为一个半透明物体,也可以有颜色呀!如果仅仅是想上面一样那么就只有完完全全的后面的物体的颜色了,更像是一个,而不像是玻璃

所以这里我们使用了Alpha混合,将缓冲区中已有的颜色与新绘制的半透明片元的透明色做混合

混合有很多种算法,比如,算了太多了直接给图,比较常用的:

通过最后的颜色就是,上面的公式计算出的颜色,我们通过填写Blend 的两个参数来控制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Shader "Unlit/Transparent"  
{
//...

SubShader
{
Tags
{
"Queue" = "Transparent"
}
LOD 100

Pass
{
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

//...
}
}
}

半透明物体间相互交叠