用实例说明Queue,ZWrite ,ZTest对渲染循序的影响
新建两个一样的Shader(Test1.shader与Test2.shader) 并分别创建材质球,然后赋值给两个Cube, shader代码如下:
Shader "Custom/Test1" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = v.uv; return o; } fixed4 frag (v2f i) : SV_Target { fixed4 col = tex2D(_MainTex, i.uv); return col; } ENDCG } } }
这个shader非常简单,就是采样一张贴图,我们分别给它们一张绿色和一张紫色的图,注意此时我们没有写任何关于Queue,ZWrite ,ZTest的代码,但事实上Unity帮我们默认设置这三个属性,首先是渲染队列默认设置(缺省代码如下)
Tags { "Queue"="Geometry" }
我们可以通过Inspector面板来观察它
渲染队列(RenderQueue)
Unity允许我们通过一个叫渲染队列的值来决定物体渲染的先后顺序(可以忽略物体的摆放顺序),它规定渲染队列值越小的物体优越被渲染
(特别注意 越小越优先被渲染说明后渲染的物体有可能会挡住先渲染的物体)
Unity将不同类型的物体渲染顺序划分了一个区间,比如不透明物体(Geometry)默认值是2000,透明度测试的物体(AlphaTest)默认值是2450。(代码 Tags { "Queue"="Geometry-1" } 对应 1999,同理Tags { "Queue"="Geometry+1" }对应2001,其他以此类推)
实际验证
我们将两个cube放到距离相机一样远的位置,并让它们有一部分重叠,然后分别调整它们的渲染队列值进行观察
首先我们将cube2的RenderQueue调整到2001,发现Cube2显示到前面
然后我们将cube1的RenderQueue调整到2002,发现Cube1显示到前面
看来RenderQueue确实可以改变物体的渲染顺序,越小的值越先被渲染,所以RenderQueue大的物体会挡住RenderQueue小的物体
继续实验
我们将Cube1往后移一米继续观察
Cube1跑到后面了,此时出现了一个问题,明明Cube1的RenderQueue大于Cube2的,为什么会跑后面去了?说好的可以忽略物体摆放位置呢?
这个问题涉及到Unity的另外两个缺省设置,深度测试与深度缓冲区
ZTest&ZWrite
缺省代码如下
ZTest LEqual ZWrite On
ZTest:深度测试 LEqual 是 测试标准
ZTest LEqual 表示 当一个颜色的深度(代表距离相机的远近的值)小于等于 时才有资格写入深度缓存 (除了LEqual之外还有Less (<) 、 Greater (>) 、 GEqual (>=)、 Equal (==) 、 NotEqual (!=) 、 Always (全部通过) 、Never(全部不通过)、On(开启深度测试 等同于ZTest LEqual)、Off (关闭深度测度 等同于ZTest Always) )
ZWrite: 是否允许写入深度缓存(Depth-Buffer) On (开启) 、 Off (关闭)
先说结论: ZTest与Zwrite的作用就是用来保证物体之间的遮挡顺序可以正确的显示,也就是离我们近的物体会挡住离我们远的物体,这符合自然规律
现在我们来将这两个默认设置都关闭
ZTest Off ZWrite Off
再看一下效果:
现在渲染的顺序以渲染队列为准了
继续回过头来看ZTest与ZWrite的原理,这里需要提两个概念,一个是颜色缓冲区,另一个是深度缓冲区
颜色缓冲区(COLOR_BUFFER)就是帧缓冲区(FRAME_BUFFER),摄像机需要渲染的场景最终每一个像素都要写入该缓冲区,然后由它在渲染到屏幕上显示
深度缓冲区(DEPTH_BUFFER)与帧缓冲区对应,用于记录上面每个像素的深度值,通过深度缓冲区,我们可以进行深度测试,从而确定像素的遮挡关系,保证渲染正确.
逻辑执行顺序:
1.当ZTest开启时,以深度缓冲为判断基准,来判断是否满足通过条件,如果不满足则直接丢弃,如果满足执行2
2. 更新颜色缓存,同时判断是否可以更新 深度缓冲,(也就是 ZWrite 是On还是 Off),如果Off,不更新深度缓冲(之后如果有同位置的颜色要深度测试,用的还是之前深度缓冲里对应颜色的深度),如果满足执行3
3.更新深度缓冲
(深度缓冲创建时,默认里面的值都是无穷大,设置ZTest Greater(>=)时会发现一个有趣的现象:Cube1消失了,因为它无法通过深度测试)
ZTest与ZWrite的所有组合关系如下
1.深度测试通过,深度写入开启:更新颜色缓冲区,更新深度缓冲区;
2.深度测试通过,深度写入关闭:更新颜色缓冲区,不更新深度缓冲区;
3.深度测试失败,深度写入开启:不更新颜色缓冲区,不更新深度缓冲区;
4.深度测试失败,深度写入关闭:不更新颜色缓冲区,不更新深度缓冲区。
文章评论