开启gl.DEPTH_TEST仅启用深度缓冲机制,遮挡效果还需配合gl.clear(GL_DEPTH_BUFFER_BIT)、合理gl.depthFunc、正确顶点Z值及深度写入控制,缺一不可。

开启 gl.DEPTH_TEST 本身不会自动“实现遮挡排序”,它只是启用深度缓冲机制;真正决定是否遮挡、谁遮谁,取决于绘制顺序、深度函数、清除操作和顶点 Z 值——漏掉任一环,模型就会穿模或错序。
为什么开了 gl.enable(gl.DEPTH_TEST) 还是不遮挡?
常见现象:两个重叠三角形,后画的总盖住先画的,不管 Z 值大小;或者整个场景全黑/全白,没有层次感。
根本原因不是没开深度测试,而是没配齐配套动作:
- 没调用
gl.clear(gl.DEPTH_BUFFER_BIT)—— 深度缓冲区残留旧值,新片元总被错误丢弃 - 没设置合理的深度比较函数(默认是
gl.LESS,但若你用的是反转 Z(如 WebGPU 风格),就得改用gl.GREATER) - 顶点着色器输出的
gl_Position.z超出[-1, 1]范围(比如未经透视除法或投影矩阵错误),导致深度值被裁剪或归一化异常 - 启用了
gl.BLEND但没关写深度(gl.depthMask(true)默认开着,但如果之前手动设成false就不会更新深度)
gl.depthFunc() 怎么选?别硬记 LESS/GREATER
关键看你的投影矩阵输出的 Z 是“近小远大”还是“近大远小”:
立即学习“前端免费学习笔记(深入)”;
- 标准透视投影(
perspective或frustum)输出Z ∈ [-1, 1],且近平面 Z = -1,远平面 Z = 1 → 用gl.LESS(默认) - 如果手写投影把 Z 反转了(例如
z' = 1.0 - z),让近处 Z 大、远处 Z 小 → 必须用gl.GREATER - 调试时可临时改成
gl.ALWAYS看是否所有片元都通过深度测试,确认是逻辑问题而非数据问题
绘制顺序还有影响吗?开了深度测试就随便画?
有影响,而且在特定情况下必须注意:
- 透明物体(alpha
- 不透明物体理论上可乱序,但若存在共享边、Z-Fighting(如地面和墙共面),建议仍按大致从前到后或从后到前绘制,并加
gl.polygonOffset()微调 - 多个 VAO/VBO 切换频繁时,避免在中间插一个没清深度的渲染通道,否则后续绘制会被前序残余深度干扰
一个最小可验证片段(WebGL 1)
gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LESS); // 显式设置,别依赖默认 gl.clearColor(0.2, 0.2, 0.2, 1.0); gl.clearDepth(1.0); // 清深度缓冲为最大值(远平面) gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); <p>// 绘制前确保 projection <em> view </em> model 已传入着色器 // 且顶点着色器中:gl_Position = u_projViewModel * a_position; // (其中 u_projViewModel 已包含正确的透视投影)
最容易被忽略的其实是 gl.clearDepth(1.0) 和每次帧开始的 gl.clear(... | gl.DEPTH_BUFFER_BIT) —— 深度缓冲不像颜色缓冲那样“一眼可见”,但它一旦脏了,遮挡关系就全崩了。



















