想学webgl?先来看看深度测试吧

220 阅读4分钟

深度测试 DEPTH_TEST

简单来说,深度测试就是比较绘制物体的深度。 在webgl中,可以通过简单的两句代码实现:

gl.enable(gl.DEPTH_TEST);   // 开启深度测试
gl.depthFunc(gl.ALWAYS);    // 设置深度测试函数如何进行比较

首先,我们先创建两个简单的三角形

很明显可以看出,虽然我们设置了红色三角形A的z轴为更接近屏幕的-0.1。但因为先绘制,所以仍然被后绘制的绿色三角形遮盖。

接下来我们打开深度测试试试看:

捕获.JPG 可以看到红色三角形这次显示在绿色三角形上面了。

值得注意的是我们并没有设置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);

捕获.JPG 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,
];

捕获.JPG 只有一个绿色三角形,这是什么意思呢?

实际上,在 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])

捕获.JPG 可以看到,这次我在每次绘制三角形的时候设置了不一样的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])

捕获.JPG 我们这里使用了一个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的神奇世界!