文章目录
- 前言
- 深度缓冲区
- 多边形缓冲机制
- 总结
前言
webgl在渲染三维场景时,按照Z坐标的值决定前后关系,但是在默认状态下它并未开启深度检测,而是将后绘制的物体放在前面;当两个物体Z坐标相差无几时,会产生深度冲突,两个物体颜色互相影响,使得表面看上去斑斑驳驳,需要开启多边形缓冲来避免此类问题。
深度缓冲区
我们知道webgl着色器中的内置变量gl_Position是按照左手坐标系。也就是说Z轴指向屏幕内侧,z坐标大的像素将会被绘制在后方,遮挡z坐标比它大的像素(暂不考虑乘以MVP矩阵)。但是,这是在开启深度检测的前提下,如果没有开启这一设置,后绘制的会遮挡先前绘制的
。
这样子使用:
/** @type {HTMLCanvasElement} */
//------------------------------------------------------创建画布
// 获取canvas元素对象
let canvas = document.getElementById('canvas');
// 获取webgl绘图上下文
const gl = canvas.getContext('webgl');
if (!gl) {
throw new Error('WebGL not supported');
}
gl.viewport(0, 0, canvas.width, canvas.height)
// 设置背景色
gl.clearColor(0.0, 0.0, 0.0, 1.0)
// 清空缓冲区
gl.clear(gl.COLOR_BUFFER_BIT)
const vertex = `
attribute vec4 aPosition;
attribute vec4 aColor;
varying vec4 v_Color;
void main() {
gl_Position = aPosition;
gl_PointSize = 10.0;
v_Color = aColor;
}
`
const fragment = `
precision highp float;
varying vec4 v_Color;
void main(){
gl_FragColor = v_Color;
}
`
// 创建program
const program = initShader(gl, vertex, fragment)
// 获取attribute变量的数据存储位置
const aPosition = gl.getAttribLocation(program, 'aPosition');
const aColor = gl.getAttribLocation(program, 'aColor');
// 获取uniform变量的数据存储位置
// 创建缓冲区对象
const buffer = gl.createBuffer();
// 绑定缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
// 传入的数据
const vertices = new Float32Array([
// Z 为 0.0的蓝色三角形
-0.3, 0.6, 0.0, 0.4, 0.4, 1.0,
-0.8, -0.6, 0.0, 0.4, 0.4, 1.0,
0.2, -0.6, 0.0, 1.0, 0.4, 0.4,
// Z 为 -0.5的黄色三角形
0.0, 1.0, -0.5, 1.0, 1.0, 0.4,
-0.5, -1.0, -0.5, 1.0, 1.0, 0.4,
0.5, -1.0, -0.5, 1.0, 0.4, 0.4,
// Z 为 0.5 的绿色三角形
0.3, 0.8, 0.5, 0.4, 1.0, 0.4,
-0.2, -0.8, 0.5, 0.4, 1.0, 0.4,
0.8, -0.8, 0.5, 1.0, 0.4, 0.4,
])
const BYTES = vertices.BYTES_PER_ELEMENT;
// 开辟空间并写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
// 缓冲区对象分配给attribute变量
gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 6 * BYTES, 0)
gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, 6 * BYTES, 3 * BYTES)
// 开启attribue变量
gl.enableVertexAttribArray(aPosition)
gl.enableVertexAttribArray(aColor)
// 开始绘制
gl.drawArrays(gl.TRIANGLES, 0, 18)
在上述代码中,向vertices依次传入缓冲区数据,实际效果如下:
webgl默认按照缓冲区中的顺序绘制图形,后绘制的图形覆盖先绘制的图形,因为这样做很高效。但是当传入顺序与z坐标大小不一致,或者视点不断移动更改视角时,将无法保证绘制顺序。
- 开启深度检测
- 1.开启隐藏面消除功能:gl.enable(gl.DEPTH_TEST)
- 2.在执行绘制函数之前,清除深度缓冲区:gl.clear(gl.DEPTH_BUFFER_BIT),gl.clear支持使用 | 添加多个参数。
// 设置背景色
gl.clearColor(0.0, 0.0, 0.0, 1.0)
// 开启深度检测
gl.enable(gl.DEPTH_TEST);
// 清空颜色缓冲区和深度缓冲区
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT )
如下黄色就到了最前面
为了方便观察蓝色三角形与绿色三角形的关系,将黄色三角形尺寸调整的小一些:
const vertices = new Float32Array([
// Z 为 0.0的蓝色三角形
-0.3, 0.6, 0.0, 0.4, 0.4, 1.0,
-0.8, -0.6, 0.0, 0.4, 0.4, 1.0,
0.2, -0.6, 0.0, 1.0, 0.4, 0.4,
// Z 为 -0.5的黄色三角形
0.0, 0.2, -0.5, 1.0, 1.0, 0.4,
-0.5, -0.2, -0.5, 1.0, 1.0, 0.4,
0.5, -0.2, -0.5, 1.0, 0.4, 0.4,
// Z 为 0.5 的绿色三角形
0.3, 0.8, 0.5, 0.4, 1.0, 0.4,
-0.2, -0.8, 0.5, 0.4, 1.0, 0.4,
0.8, -0.8, 0.5, 1.0, 0.4, 0.4,
])
效果如下,与预计中一样,Z坐标:Z黄 < Z蓝 < Z绿。前后顺序:黄 > 蓝 > 绿。
多边形缓冲机制
当两个表面过于接近,深度缓冲区有限的精度已经不能区分先后关系,当场景中有多个运动着的物体时,很难保证它们的深度值不会在某刻相同,这种情况会导致两个物体颜色互相影响,使得表面看上去斑斑驳驳。
webgl提供一种名为 多边形偏移 的机制来解决这个问题。该机制将自动在 Z 值加上一个偏移量,偏移量的值由物体表面相对于观察者视线的角度来确定。
- 1.开启多边形偏移:gl.enable(gl.POLYGON_OFFSET_FILL)
- 2.设置偏移参数:gl.polygonOffset(1.0, 1.0)
gl.enable(gl.POLYGON_OFFSET_FILL);
gl.polygonOffset(1.0, 1.0);
总结
-
深度缓冲区
-
多边形缓冲机制