1.画家算法
画家在画油画时,会从远景开始画起,然后逐渐画近景覆盖远景,比如下图:
参考画家算法,在屏幕空间中画一个正方体就需要如下的绘制步骤:
首先绘制最远的那个面(后面),然后再画左面和下面,之后再画上面和右面,最后画正面。就可以得到这样一个正方体。先画背面最后画正面可以理解,那么四个侧面的顺序是如何决定的?目前我们只是暂时用这种画法,没有什么特殊的决定方法。但是若更改一下顺序,先画上面和左面,再画右面和底面,就会导致右面有一条线无法被覆盖,立方体的上面就会多出一条线。所以按照画家算法需要对三角形的深度进行排序,时间复杂度为
(
O
(
n
l
o
g
n
)
)
(O(nlogn))
(O(nlogn)),排序过后按照深度信息由深至浅绘制。
**存在的问题:**互相遮挡的情况,画家算法无法解决这种场景,如下图所示。
深度缓冲(Z - Buffer)
声明放在最前面: 由于相机放在坐标原点指向-z轴(屏幕朝内),那么一个物体的z的坐标越小,这个物体离我们就越远;反之,z的坐标值越大,离我们就越近。但是这里我们计算物体所处的深度时不这么取值,因为深度只能是一个大于0的数,所以我们取z的绝对的作为一个物体的深度。
Z-Buffer的思想
对每个像素进行深度值比较,实际上并不需要排序,一个个比较过去,记录最小的深度值,时间复杂度
(
O
(
n
)
)
(O(n))
(O(n))
需要一个额外的缓冲来记录每一个像素的深度值(|z|)
- 帧缓冲(frame buffer)存储每一个像素的颜色的值(color values)
- 深度缓冲(z - buffer)存储每一个像素的深度值
Z-Buffer实例
如上所示,需要两个缓冲,一个缓冲存储最终的渲染效果,而另外一个Z-Buffer是用来存储每个像素的深度值信息。在深度图像上,一个像素的深度值越大,那么该点就会越白,如果深度值越小,该点就会越黑,因为当取色范围为0-1时,
c
o
l
o
r
=
0
color = 0
color=0为黑色,
c
o
l
o
r
=
1
color = 1
color=1为白色,深度越小,对应的颜色值就越小,反应到图像上就是越黑,反之越白。我们以一个像素点为例,如图中左上角的顶点,在绘制图像时先在该像素点上存储了一个地板的颜色,然后在绘制立方体时,发现立方体的深度值比地板的深度值要小,那么就在这个像素点上存储立方体的颜色来覆盖地板。
深度缓冲算法(Z - Buffer Algorithm)
伪代码:
Initialize depth buffer to ∞
During rasterization:
for(each triangle T)
{
for(each sample(x,y,z) in T)
{
if(z<zbuffer[x,y])
{
framebuffer[x,y]=rgb;
zbuffer[x,y]=z;
}
}
}
解释:
- 先把所有像素的深度值都初始化为无限大
- 对于三角形上的每一个像素点,如果这个像素点的深度值小于深度缓冲中的深度值,在该像素点绘制三角形的rgb颜色,然后更新深度缓冲的深度值为当前绘制的三角形的在该点的深度值;否则就什么都不做。
用图更直观说明:
图中R代表无限大,数字代表深度大小。5比R小,则重新写入,加入第二个三角形,跟R和5相比,比5大要被原来的三角形遮挡,比5小的会遮挡原来的三角形这两个三角形插入到了一起,互相遮挡一部分。
为了实现Z-Buffer , 图形学中通常采用的做法是:在渲染最后成品图的同时,也会同时生成另外一个深度图像,这个深度图像只存储了任何一个像素他所看到的几何物体中最浅的深度信息。