Games101笔记|Z-Buffer(深度缓冲)
2 可见性与遮挡
2.1 画家算法
原理
先对远处的物体进行光栅化,后逐步对近处的物体进行光删化操作。(画近处的物体时会覆盖掉之前画的远处的一些物体)这样就可以正确地处理遮挡的问题了。
涉及到一个问题
这里涉及到一个问题:当某些物体在深度上存在互相遮挡的情况,此时没有办法定义顺序关系,这样就无法使用画家算法,因为不知道应该按照什么样的顺序画,或者不管先画什么都是错的。如下图所示:
2.2 问题解决方法:深度缓存/缓冲 z-buffer
思想:在生成最终图像的同时,也会生成一个“只存像素所看到的几何物体最浅的深度信息”的图像。然后利用深度缓存来维护遮挡信息。
-
每一个像素内存储最浅深度值,即 z 值。
-
需要额外的深度值缓冲区
- 帧缓冲区(frame buffer)存储颜色值
- 深度缓冲区(z缓冲区)存储深度
之前的讲述是摄像机永远看向z轴的负方向,因此所有的 z 都是负的。以为这 z 值越大距离反而越近,z 值越小,离摄像机的距离越远。
为了简化计算,将之前看到的 z 换一个概念。我们现在认为,摄像机到物体之间的距离,也就是深度信息,这个值永远都是正的。越小的值表示越近,值越大表示距离越远。
深度缓存算法思想:
- 一开始将所有像素记录的深度缓存距离都初始化为无限远,即初始化为无限大的值。
- 在光栅化的过程中,找到任意一个三角形所覆盖的任意一个像素。
- 如果新的三角形要画在这个像素内,对于这个像素来说,如果新的 z 值比之前所存储的深度信息还要小,那么就将像素点的颜色值和深度信息值都进行更新。否则,什么都不做。
注意这里并未进行排序,只是在不断求最小值而已。复杂度为O(n)。
该算法有一个很重要的特点:和绘制顺序是没有关系的,只要正确求得最小的深度信息,最后绘制出来的图像就是对的。(前提条件,不出现在同一个像素点上出现相同的深度信息的情况。)
总结:
这是一个非常非常重要的算法,几乎广泛应用在所有的硬件中。每一个像素维护一个深度测试,就可以得到正确的遮挡算法。
之前有提到过 MSAA 的方法,对于这里面的采样点进行深度缓冲的话。意味着也不一定是对每一个像素进行 z-buffer, 也有可能是对采样点~
z-buffer 一定处理不了透明物体的深度,这个需要特殊处理。
绘制透明物体
缓冲区其实就是一张和最终输出图像分辨率一样大的图,每个像素存储了不同的数据。
1)深度缓冲区 z-buffer:每个像素记录了离相机最近的片元的深度。
2)颜色缓冲区 Frame buffer:也叫帧缓冲区,每个像素记录了当前该位置对应的颜色。
1、场景中存在半透明物体的正确渲染
由于通过透明物体是可以看到被其遮挡的物体的,因此对于深度缓存中的深度值就不能直接替换更新,深度值应该是离相机最近的不透明物对应的片元的深度值,否则就会出现透明物体挡住不透明物体的渲染错误。 因此在渲染半透明物体时,需要关闭深度写入,但要保留深度测试。(深度测试的目的在于判断:是否因为遮挡而舍弃当前片元,如果该透明片元在不透明物体后,它被遮挡了,深度值比较大,当然应该被丢弃。当它在不透明物体前,它就不会被丢弃,但是又不会将当前的深度值写入,还是会以不透明物体的深度信息为准。)
同时对于颜色也不可以和以前一样替换更新,而是要做透明度混合,即用帧缓存中已有的颜色和透明片元的透明色混合出一个新的颜色。
场景总存在透明物体时的渲染步骤:
-
先渲染不透明物体,后渲染透明物体
-
对透明物体进行排序,然后从远到进的顺序依次渲染。(因为只有这样才能正确地叠上,并混合出正确的颜色)
-
并开启它们的深度测试,但关闭深度写入。
但此时还存在两个问题:
1)仍然无法解决透明物体相互交叠的问题。
2)透明物体内部如果自身互相交叠也会存在问题。无法判断片元的先后顺序。
2、半透明物体间相互交叠的问题
3、半透明物体的自身交叠问题及双面渲染
关闭背面剔除,将双面渲染的工作分成两个pass,渲染两次:
- 第一个pass只渲染背面
- 第二个pass只渲染正面
保证背面总是在正面被渲染之前渲染,从而可以保证正确的深度渲染关系
- 原文作者:Binean
- 原文链接:https://bzhou830.github.io/post/20200222Games101_04/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。