深度测试
三块重叠的四边形按「近 → 中 → 远」的顺序绘制。深度测试打开时近的压住远的; 关掉之后,遮挡关系立刻退化成绘制顺序。
说明
十八个顶点一次画完,三块四边形在同一个绘制调用里。顶点顺序是蓝、绿、红, 但 z 值分别是 -0.7、0、0.6;裁剪空间里 z 越小离相机越近,蓝在最前。 深度测试打开时,后面画的绿与红在重叠处被蓝挡住; 关闭后,红作为最后一个画的三角形覆盖一切。
「关闭深度测试」把 depthCompare 从 less-equal 换成
always。这不是删掉深度缓冲,而是让每次比较都通过,
效果等同于不测深度。
| 项目 | 取值 | 说明 |
|---|---|---|
| 顶点数量 | 18 | 三块四边形各六个 |
| 图元 | triangle-list | 一次绘制画完 |
| z 值 | -0.7 / 0 / 0.6 | 裁剪空间里越小越靠近相机 |
| 深度比较 | less-equal | 关闭时改为 always |
| 深度写入 | true | 两种状态都保持写入 |
| 绘制顺序 | 蓝 → 绿 → 红 | 固定不变 |
参数写在模型上
const model = new Model(device, {
topology: 'triangle-list',
vertexCount: 18,
parameters: {
depthCompare: 'less-equal',
depthWriteEnabled: true
},
attributes: { positions: posBuffer, colors: colBuffer },
bufferLayout: [
{ name: 'positions', stepMode: 'vertex', format: 'float32x3' },
{ name: 'colors', stepMode: 'vertex', format: 'float32x3' }
],
vs: vsSource,
fs: fsSource
});
深度状态属于管线。运行期调用 model.setParameters({...})
会标记管线需要重建,下一帧自动换上新管线,不需要手工销毁旧对象。
深度值从哪来
顶点着色器输出的 gl_Position.z 是裁剪空间坐标,
除以 w 得到归一化设备坐标,再线性映射到 0–1 的窗口深度。
本示例的 w 恒为 1,所以 z 直接决定远近:-0.7 映射到 0.15,
0.6 映射到 0.8,前者离相机更近。
透视投影下这个映射是非线性的,靠近相机的区间精度高、远处精度低。 这也是远处两个面贴得很近时会出现闪烁的原因。
深度测试与混合的区别
| 深度测试 | 混合 | |
|---|---|---|
| 解决的问题 | 哪个片元离相机更近 | 同一像素上多层颜色如何叠加 |
| 结果 | 保留或丢弃整个片元 | 按权重合成颜色 |
| 透明物体 | 需要先画不透明再画透明 | 透明层靠它合成 |
GIS 里的对应场景
建筑体块、地形与标注重叠时,深度测试决定谁被遮住。 半透明面罩、云层、热力面则要在深度测试之外补上混合与绘制顺序, 否则边缘会出现硬切。
默认画布带深度缓冲,离屏目标要自己加。
自己建的帧缓冲如果没有 depthStencilAttachment,
深度参数不会报错,但所有片元都通过比较,画面按绘制顺序叠在一起。