Shader中“深度”的理解和思考

发表于2018-08-16
评论0 4.7k浏览
深度其实就是该象素点在3d世界中距离摄象机的距离(绘制坐标),深度缓存中存储着每个象素点(绘制在屏幕上的)的深度值! 可能大家看到深度测试啊,深度图等,但是很难通过名字将他们的用途联想到一块,面对一些高级议题会涉及到它,所以这里就给大家介绍下对Shader中“深度”的思考与分析。

首先随手建立两个物体:

其中一个cube里面包含一个圆体,为何会呈现上面的样子呢,引擎是这么去做的:
1.由于我设置的队列是透明队列,所以引擎保证绘制顺序是从远到近。当然对当前这个例子来说,不论是从远到近还是从近到远,绘制结果都是一样的。那么我们假定先画cube,再画圆体。

2.注意,1中所谓的画,并不是真的直接在屏幕上直接画出来,而是在考虑接下来的步骤的时候的处理顺序。

3.首先顶点着色器执行完毕,然后开始进行深度测试和背面剔除。背面剔除就是如果这个面试朝后的,那么摄像机就看不到,所以不用画。我们主要看下深度测试。所谓深度测试,就是将当前的深度值和深度缓冲中的深度值进行比较,以确定是否要剔除还是保留当前的绘制片段。你可以简单理解成,最靠近摄像机的才会被绘制。但是这种抽象的理解不利于你去理解一些特殊的效果(后面会提到),所以还是要明确下具体的步骤:

绘制cube的时候,深度缓冲中的是底部的Plane,毫无疑问,cube是更靠近摄像机的,所以深度缓冲更新为cube的深度。

绘制圆体的时候,深度缓冲中的是cube的深度,那么圆体的上部分没有被遮住,所以绘制,下面的被遮住了,所以不绘制。此时,屏幕中有一部分的深度缓冲被更新成圆体的深度。

这样整个过程就结束了。然后看下shader中涉及深度的指令:ZTest 和 ZWrite.

ZTest就是指定如何进行深度测试,比如你可以指定不论如何 永远绘制,那么这个物体将永远是不剔除的,当然有可能还是会被挡住,这就是因为所谓的永远不剔除只是在过程上不去剔除它,但绘制的时候,如果后面绘制的物体覆盖住了它,它还是会被挡住(可能描述的不够清楚,但我是为了说明不要从字面的意思去理解这个指令,而要理解它对绘制过程的影响,这样对后面的效果才会明白如何做到的)。

ZWrite就是表示是否写入深度缓冲,比如刚才,我们屏幕上的深度缓冲的更新,就是因为ZWrite是默认开启的。

理论总是比较枯燥和不知所谓,还是配合例子一起看吧。

首先,我们把Ztest调节成Greater,就变成了这样:

这个就是让被挡住的反而绘制出来。那么这个是啥用处,比如这个效果:
其实就是让遮挡的部位换一种着色方法。那么我们也可以马上利用ZTest实现类似的效果:

被挡住的部分我着色器用绿色,不挡住的部分着色器用蓝色。唯一要注意的是,被挡住的部分ZWrite要关闭。因为假设你开启了ZWrite,那么你想一下我们上面的步骤,当绘制绿色部分的时候,假设深度值被写入了,那么蓝色在比较深度的时候,就会被画出来,那么被挡住的绿色就被蓝色覆盖了。

再看一个很多人碰到的情况,就是半透明的时候,物体内部显示出来,例如:

这是因为半透明物体在绘制的时候,会根据当前的值和背景alpha混合,并不是我覆盖你就不绘制你,而是我根据当前的颜色和被我覆盖的进行剔除。那么这个怎么办呢,也很简单,就是在前面增加一个Pass{colormask0}这样就可以了。

效果如下:

这是因为第一个pass干扰了绘制过程,让深度缓冲中已存在当前的深度值,这样就会去剔除内部了。

如果以上的东西你都能理解,说明你已经明白了深度的概念和意义,就可以开始利用他们实现一些非常有意思的效果了。
来自:https://blog.csdn.net/yxriyin/article/details/50533513

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引