UNITY_REVERSED_Z的那点事
背景我们知道,深度图可是个好东西,各种花里胡哨的效果都离不开这玩意,得益于urp的深度拷贝我们能以很低的代价获取到深度图。那怎么用好这玩意呢,这里就不得不提一嘴UNITY_REVERSED_Z这个宏了,Unity文档是这么描述的:
提取出以下信息:
在不同平台上:
1.近平面->远平面的深度缓冲区是不一样的,在dx类平台上值是1->0,在OpenGL类平台上是0~1。
2.近平面->远平面对应的ClipSpace的z的值是不一样的,在dx类平台上值是0->far,在OpenGL类平台上是-near~far。
第一条,对应到我们的深度图上,就是说dx类平台上,深度图是近白远黑,而openGL类平台上就是近黑远白,啊这个比较符合直觉,所以我们说dx类平台的深度是反的,也就是 UNITY_REVERSED_Z。
第二条,是说ClipSpace的定义不一样,那这个对于对我们又有啥影响呢,好像没啥特别的影响,一般都不直接使用ClipSpace。嗯...但真的没啥影响吗?不着急,我们待会说。
为啥这么做呢,因为可以提高深度缓冲区的精度,那为啥这么做就能提高精度了呢,啊好问题,促使我关注这个问题的起因是一个5000米的远平面的配置,这导致在安卓上软粒子质量奇差,下面这篇文章解释的很好,为啥要用反向Z
使用深度图
OK,那我们知道有这么一回事了,然后Unity为了让我们不用关心这些乱七八糟的平台差异,给了我们这样两个接口,
Linear01Depth(float z)
LinearEyeDepth(float z)
只要我们输入对应的深度缓冲区值,就能获得此值相对于屏幕空间的深度。啊事情到这里好像就结束了....吗?再想想,假如我不关心平台差异,那是不是就不用走这个方法了?要搞清楚这个问题,我们需要先弄明白,这个输入的z到底是个啥。有些聪明的小伙伴就要说了,不就是采样到的深度图的值嘛,啊确实,那这个深度图的值,他又是个啥呢,这里就引出另一个问题了。
深度图里存的是啥
深度缓冲区的值只能是0~1,dx平台的深度好说,ClipSpace坐标做透视除法得到NDC坐标后,z轴值刚好是1~0,能直接写入。但openGl平台做完透视除法后区间是[-1,1]也就是他肯定是需要一个转换才能写入贴图的。于是我们得出结论:
1.在openGL平台上,NDC坐标的Z轴区间是[-1,1],为了把这个值保存进贴图,它被映射到了区间。
2.在DX类平台上,NDC坐标的Z轴值就是深度缓冲区的值。
妈妈生的
OK!现在我已经完全明白反向深度缓冲区这件事了。总之,要获取到屏幕的深度,我只需要去采样深度图,然后调用上面的接口,就能拿到深度值了,特别注意的是,如果你想拿NDC坐标的z来取深度,要留意平台差异,openGL平台是要 z*0.5+0.5转换到的。这种情况我猜你应该是在片元着色器的上下文,当然有条件的话还是建议直接拿ClipSpace的w分量,毕竟这玩意就是深度....
页:
[1]