深度测试 DEPTH_TEST
简单来说,深度测试就是比较绘制物体的深度。 在webgl中,可以通过简单的两句代码实现:
gl.enable(gl.DEPTH_TEST); // 开启深度测试
gl.depthFunc(gl.ALWAYS); // 设置深度测试函数如何进行比较
首先,我们先创建两个简单的三角形
很明显可以看出,虽然我们设置了红色三角形A的z轴为更接近屏幕的-0.1。但因为先绘制,所以仍然被后绘制的绿色三角形遮盖。
接下来我们打开深度测试试试看:
可以看到红色三角形这次显示在绿色三角形上面了。
值得注意的是我们并没有设置depthFunc,因为其默认值为gl.LESS。 depthFunc有以下参数(参考MDN):
gl.NEVER
(永不通过)gl.LESS
(如果传入值小于深度缓冲值,则通过)gl.EQUAL
(如果传入值等于深度缓冲区值,则通过)gl.LEQUAL
(如果传入值小于或等于深度缓冲区值,则通过)gl.GREATER
(如果传入值大于深度缓冲区值,则通过)gl.NOTEQUAL
(如果传入的值不等于深度缓冲区值,则通过)gl.GEQUAL
(如果传入值大于或等于深度缓冲区值,则通过)gl.ALWAYS
(总是通过)
我们来试试这些不同的参数,对显示效果有什么影响。
gl.NEVER
gl.depthFunc(gl.NEVER);
Nothing!没错,任何值都会被拒绝。
gl.EQUAL
gl.depthFunc(gl.EQUAL);
let triangleA = [
0, 0, -0.1,
0, 0.5, -0.1,
0.5, 0, -0.1,
];
let triangleB = [
-0.3, 0, 1,
-0.3, 0.5, 1,
0.2, 0, 1,
];
只有一个绿色三角形,这是什么意思呢?
实际上,在 WebGL 中,深度缓冲区(Depth Buffer)的默认值不是无穷大也不是零。深度缓冲区的值通常被规范化到 [0, 1] 的范围内,其中 0 表示最近的深度,1 表示最远的深度。这意味着默认情况下,深度缓冲区的初始值是 1.0,这代表最大深度,即最远离视点的位置。
我们将绿色三角形的z值设为了1,也就是等于了深度缓冲区的默认值,正好可以显示它。
gl.GREATER
let triangleA = [
0, 0, -0.1,
0, 0.5, -0.1,
0.5, 0, -0.1,
];
let triangleB = [
-0.3, 0, 0,
-0.3, 0.5, 0,
0.2, 0, 0,
];
gl.depthFunc(gl.LESS);
drawTrangle(triangleA, [1, 0, 0])
gl.depthFunc(gl.GREATER);
drawTrangle(triangleB, [0, 1, 0])
可以看到,这次我在每次绘制三角形的时候设置了不一样的depthFunc,得到了如上图的结果。
首先,默认缓冲区的值为1,设置LESS,我们绘制红色三角形。然后设置GREATER,绘制绿色三角形。为什么绿色三角形只有一个角呢。我们绘制红色三角形时,因为成功通过测试,红色三角形区域的深度值已经被设置为-0.1(其实按照映射应该是(-0.1+1)*0.5,但为了方便我还是按物体的坐标点说),其他空白区域仍然是1。之后我们设置了GREATER,只有比缓冲区大的值可以通过,在红色三角形与绿色的重叠区域,绿色三角形的深度为0,缓存区为-0.1,通过测试显示绿色。而在非重叠区域,绿色三角形的深度为0,缓冲区为1,无法通过测试,不显示。
gl.clearDepth()
到了这里就有同学会问了,深度缓冲区的默认值是1,我们有没有办法修改这个默认值呢,答案是有的:
gl.depthFunc(gl.LESS);
gl.clearDepth(0.5); // 与下一句clear一起用
gl.clear(gl.DEPTH_BUFFER_BIT);
let triangleA = [
0, 0, -0.5,
0, 0.5, -0.5,
0.5, 0, -0.5,
];
let triangleB = [
-0.3, 0, -0.1,
-0.3, 0.5, -0.1,
0.2, 0, 0.5,
];
drawTrangle(triangleA, [1, 0, 0])
drawTrangle(triangleB, [0, 1, 0])
我们这里使用了一个clearDepth的方法,给它的值为0.5(深度缓冲区中深度值映射为[0,1]),然后在clear(gl.DEPTH_BUFFER_BIT)的时候,会将深度缓冲区的值全部设为0.5。红色三角形的深度为-0.5,也是(-0.5+1)*0.5 = 0.25,比0.5小,通过测试。而绿色三角形,我们设置它是一个斜面。深度由-0.1到0.5,也就是0.45到0.75,只有一部分值小于0.5,自然它就被截断了。
到此为止,我们研究了LESS,NEVER,EQUAL,GREATER四种情况,相信大家也能举一反三的理解其他参数的含义了,在下就不再啰嗦,欢迎大家多多在代码中尝试每一种情况。
总结
总的来说,深度测试还是很简单很容易理解的,其也是非常常用的一个功能,以后会讲到模板测试,颜色混合等,将很多功能同时打开后,因为参数过多,绘制产生的结果也是千变万化。所以让我们由最简单的深度测试,打开webgl的神奇世界!