深度测试是在模板测试之后
# 深度测试简要框架
所谓深度测试,就是针对当前对象在屏幕上 (更准确说是 frame buffer) 对应的像素点,将对象自身的深度值与当前该像素点缓存的深度值作比较,如果通过了,本对象在该像素点才会将颜色写入颜色缓冲。
- 控制渲染顺序
- 控制 Z-Buffer 对深度的存储
- 控制不同类型物体渲染顺序
- 减少 overdraw
Z-Buffer 存储的是当前的深度信息,对于每个像素都会有一个深度值
通过 Z Write 和 Z Test 来调用 Z-Buffer, 实现想要的效果
深度写入包括两种状态: ZWrite On 与 ZWrite Off 当我们开启深度写入的时候,该物体会写入深度缓冲,否则不写入 但是,如果 ZWrite On 但是 Z Test 失败,也不会写入深度缓冲区 分为四种情况:
# 深度测试的状态
# 渲染队列
首先看一下 Unity 的几种内置渲染队列,按照渲染顺序,从先到后进行排序, 队列越小的,越先渲染,队列数越大的,越后渲染
不透明物体的渲染顺序,从前往后,透明的物体是从后往前 (overdraw) 所以透明物体会多渲染一次,产生性能上的问题
# Early-Z 技术
传统的渲染管线中,ZTest 其实是在片元着色器之后的,所以它是一定会执行的,而且如果测试失败,也会渲染一次,所以现代 GPU 优化了这个问题,现代 GPU 使用 Early-Z 技术,在顶点阶段和片元阶段之间进行一次检测,如果失败了,就不会继续执行片元的渲染。 深度测试 源码
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 53 54 55
| Shader "ZTest/ZTest" { Properties{ [HideInInspector] _MainTex("Texture",2D) = "white" {} _MainColor("Color",Color) = (1,1,1,1) [Enum(off,0,on,1)]_ZWriteMode("ZWrite Mode",Float) = 1 [Enum(UnityEngine.Rendering.CompareFunction)]_ZComp("ZTest Comp",Float) = 4 }
SubShader{ Pass { Tags {"RenderType" = "Opaque" "Queue" = "Geometry"} ZWrite [_ZWriteMode] ZTest [_ZComp] Cull off CGPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog
#include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv:TEXCOORD0; };
struct v2f { float2 uv:TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; };
sampler2D _MainTex; float4 _MainTex_ST; float4 _MainColor;
v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o, o.vertex); return o; }
fixed4 frag(v2f i) : SV_Target{ half4 col = _MainColor; UNITY_APPLY_FOG(i.fogColor, col); return col; }
ENDCG } }
}
|
# 可实现的效果
人物被遮挡时显示描边
不写入深度,但开启深度测试
实现思路,两个 Pass, 一个 Pass 正常渲染,另一个 Pass 在深度 Greater 时渲染为描边
这个代码可以见百人计划 1:23:30
# 深度测试扩展