webgl渲染优化——深度缓冲区、多边形缓冲机制


前言

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);  

目的达成,可以重新编辑了。

总结

  • 深度缓冲区

  • 多边形缓冲机制

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值