1.ZTest & ZWrite
ZTest:深度测试,开启后测试结果决定片元是否被舍弃,可配置
ZWrite:深度写入,开启后决定片元的深度值是否写入深度缓冲,可配置
ZTest可设置的测试规则:
ZTest Less:深度小于当前缓存则通过
ZTest Greater:深度大于当前缓存则通过
ZTest LEqual:深度小于等于当前缓存则通过
ZTest GEqual:深度大于等于当前缓存则通过
ZTest Equal:深度等于当前缓存则通过
ZTest NotEqual:深度不等于当前缓存则通过
ZTest Always:不论如何都通过
注意,ZTest Off等同于ZTest Always,关闭深度测试等于完全通过。
ZWrite配置:
ZWrite On 深度写入开启 ZWrite Off 深度写入关闭
ZTest和ZWrite发生在逐片元操作过程,处于片元着色后,最终屏幕输出前。ZTest与ZWrite的具体操作流程:
因为ZWrite默认值为On,ZTest默认值为LEqual,所以这很好地解释了为什么在unity中,距离相机近的东西会阻挡住距离相机远的东西。如果我们先绘制一个距离较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制,会把距离近的物体覆盖掉,这时我们可以通过修改ZWrite和ZTest来改变物体的遮挡关系
所以对于透明物体的渲染,一般要关闭掉ZWrite,比如Unity中用于渲染Sprite的默认SpriteDefault材质的Shader:
加深对ZTest & ZWrite的理解,可以参考这篇文章的测试部分,把各例子理解明白非常有帮助。
https://www.jianshu.com/p/9137ee354dbd
2.Unity渲染顺序
能够影响渲染顺序的因素有:
- Camera Depth: 相机组件上设置的相机深度,深度越大越靠后渲染。
- Sorting Layer: 在Tags & Layers设置中可见
- Order In Layer: 相对于Sorting Layer的子排序,用这个值做比较时只有都在同一层时才有效。
- RenderQueue: Shader中对Tags设置的“Queue”。
- 物体距离相机的距离,ZDepth值
下面是结果:
1、Camera Depth
永远最高。Camera Depth小的一定先进渲染管线。
2、当Sorting Layer和Order In Layer不相同时
- 当两个材质使用了不同的RenderQueue,且这两个RenderQueue都在[0~2500]或[2501~5000]时,SortingLayer和OrderInLayer的排序生效。
- 当两个材质使用了不同的RenderQueue,且这两个RenderQueue分别在[0~2500]和[2501~5000]时,则一定会按照RenderQueue绘制,无视SortingLayer、OrderInLayer的排序。
3、当Sorting Layer和Order In Layer相同时
- RenderQueue不相等:
RenderQueue小的先进渲染管线。
- RenderQueue 相等
RenderQueue 2500以下,由近到远排序优先 (不透明)
RenderQueue 2500以上, 由远到近排序优先 (透明)
说明一下:2500是关键值,它是透明跟不透明的分界点,因此我们考虑层级的时候要注意着点:renderqueue > 2500的物体绝对会在renderqueue <= 2500的物体前面,即渲染时renderqueue大的会挡住renderqueue小的,不论它的sortingLayer和sortingOrder怎么设置都是不起作用的。知道了这点,其他的就很好理解了。当两个的RenderQueue都在同一侧时,在SortingLayer高的绝对会在sortingLayer前面,无视renderqueue跟soringOrder,只有在sortingLayer相同的前提下,soringOrder高的会在sortingOrder低的前面,无视renderqueue。当sortingLayer跟sortingOrder相同时,才看renderqueue的高低,高的在前面。
总结下Unity影响渲染顺序各参数的优先级
如果物体的RenderQueue在2500的同一侧:
Camera Depth > Sorting Layer > Order In Layer > RenderQueue > 距离相机的距离
如果物体的RenderQueue在2500的不同侧:
Camera Depth > RenderQueue > Sorting Layer > Order In Layer > 距离相机的距离
3.Unity中的一个坑
Properties | Value | 渲染队列描述 | 说明 |
---|---|---|---|
Background | 1000 | This render queue is rendered before any others. | 这个队列通常被最先渲染(比如 天空盒)。 |
Geometry | 2000 | Opaque geometry uses this queue. | 这是默认的渲染队列。它被用于绝大多数对象。不透明几何体使用该队列。 |
AlphaTest | 2450 | Alpha tested geometry uses this queue. | 需要开启透明度测试的物体。Unity5以后从Geometry队列中拆出来,因为在所有不透明物体渲染完之后再渲染会比较高效。 |
GeometryLast | 2500 | Last render queue that is considered “opaque”. | 所有Geometry和AlphaTest队列的物体渲染完后 |
Transparent | 3000 | This render queue is rendered after Geometry and AlphaTest, in back-to-front order. | 所有Geometry和AlphaTest队列的物体渲染完后,再按照从后往前的顺序进行渲染,任何使用了透明度混合的物体都应该使用该队列(例如玻璃和粒子效果) |
Overlay | 4000 | This render queue is meant for overlay effects. | 该队列用于实现一些叠加效果,适合最后渲染的物体(如镜头光晕)。 |
从Unity文档中这个图我们可以看出来,Background理应最先被渲染,Unity中的skybox 应该属于这个renderqueue,但是当你实际使用的时候,怪事发生了:
从FrameDebugger中可以看到,对于不透明物体的渲染,skybox是在opaque的最后渲染,从而减少OverDraw。这尼玛不跟RenderQueue写的1000冲突么?!Google一顿操作,结果是这样:
总结来说就是:Unity关于Skybox部分的文档好久没有更新了,目前Skybox应该是RenderQueue 值为2500.5时渲染,在Opaque和AlphaTest之后,Transparent之前。
Unity这个文档证明了这个说法:https://docs.unity3d.com/Manual/GraphicsCommandBuffers.html?_ga=2.53580588.563516390.1589165101-117244140.1588818896
4. 2.5D游戏渲染排序解决方案
上边总结了Unity中渲染顺序的相关知识,那利用这些知识,可以实现2D游戏中景深以及排序的问题,初步总结了几种方案:
1.Order In Layer
通过设置Order In Layer 为不同的值来进行排序,缺点是需要自定义一套标准来决定物体的Order In Layer值
下边这个插件用的是这个原理
https://assetstore.unity.com/packages/tools/sprite-management/isometric-toolkit-33032
2.用Shader自定义修改ZDepth
通过自己设置Shader中的ZDepth来达到排序的目的,也就是说Sprite在场景中的Z值都一样,通过制定一套标准,来人为定义物体的ZDepth值
下边这个插件用的是这个原理
https://assetstore.unity.com/packages/templates/systems/2-5d-isometric-engine-106321
3.利用Z轴,实际就是ZDepth
在场景中把各个Sprite摆放位置根据前后关系设置Z轴位置,这样2D游戏也可以拥有ZDepth的信息,从而可以正确渲染
4.修改UnityProject 的设置
改为Y轴为排序轴,这种方法不用考虑Z轴,完全根据Sprite的y轴大小设置,非常简便。我是用的这种方式,暂时的缺点是无法根据sprite大小精确控制排序。