WebGL 中的 gl.drawArrays()与gl.drawElements() 你真的懂吗?
哈哈,今天群友又问了一个很有意思的问题,问gl.drawElements()如何使用,如何制定绘制的范围,哈哈,很基础的问题,但也难住了很多人,你也可以思考一下如何去实现,Three.js源码拆分几何体地时候就会用到这些api技巧,但是我之前并没有深入去学习,OK,带着问题我们开始吧。
先来看一下 gl.drawArrays()的ts声明:
drawArrays(mode: number, first: number, count: number): void;
这个理解起来就比较简单了,就是常说的顶底绘制,这个常用比较简单。
需要注意的是:
下面重点来了哈,先看一下gl.drawElements()的ts声明:
drawElements(mode: number, count: number, type: number, offset: number): void;
这个一看,也没什么难的吗,肯定是根据count和offset去设置范围,当然是这样,也肯定是这样,那我提一个问题,count和offset之间又有什么关系呢。好,接下来,让我结合代码去分析这个问题。首先来看一下构建顶点数据的代码:
this.vertexData= [
3.0,3.0,3.0,
3.0,-3.0,3.0,
-3.0,3.0,3.0,
-3.0,3.0,3.0,
3.0,-3.0,3.0,
-3.0,-3.0,3.0,
3.0,3.0,3.0,
3.0,-3.0,-3.0,
3.0,3.0,-3.0
];
this.vcount = this.vertexData.length / 3; //得到顶点数量
this.vertexBuffer = gl.createBuffer(); //创建顶点坐标数据缓冲
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer); //绑定顶点坐标数据缓冲
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.vertexData), gl.STREAM_DRAW); //将顶点坐标数据送入缓冲
按照 gl.drawArrays()的套路,我们就可以直接这样绘制这三个三角形:
gl.drawArrays(gl.TRIANGLES, 0, this.vcount);
好,接下来,我们先思考个问题,我只想绘制第二个三角形怎么办,应该这样给点参数,这样写的意思是我们从第3个顶点后开始绘制,然后绘制三个顶点,也就是索引3-5的顶点绘制,就是第二个三角形。
gl.drawArrays(gl.TRIANGLES, 3, 3);
接下来,我们来看一下,如何利用gl.drawElements()绘制三个三角形,然后并可以指定绘制某个三角形。先来看一下,如何构建顶点数据和索引数据的代码:
this.vertexData = [
3.0, 3.0, 3.0,
3.0, -3.0, 3.0,
-3.0, 3.0, 3.0,
-3.0, -3.0, 3.0,
6.0, 3.0, 3.0
];
this.vcount = this.vertexData.length / 3;
this.vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.vertexData), gl.STREAM_DRAW);
this.indexData = new Uint16Array([
0, 1, 2,
2, 1, 3,
0, 1, 4
]);
this.indexCount = this.indexData.length;
this.indexOffset = 0;
this.indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indexData, gl.STREAM_DRAW);
哎,顶点数据好像少了,没有重复的顶点了。这也是索引绘制的优点,能够减少重复点,而且节约空间,索引是整数,顶点是浮点数。回到正题,我们正常绘制应该怎么写,也是网上大部分中文教程的做法,我们来看一下,第二个参数count是索引数量,第四个offset是0,然后万事大吉。
gl.drawElements(gl.TRIANGLES,this.indexCount, gl.UNSIGNED_SHORT, this.indexOffset);
别忘了,我们探索的重点是如何利用gl.drawElements()的绘制指定的部分,假设我们还是需要绘制第二个三角形,我们该如何做呢,我直接写出正确的写法,然后在解释。
gl.drawElements(gl.TRIANGLES,3, gl.UNSIGNED_SHORT, 6);
下面说给没看明白的同学,我们可以这样理解,在indexData这块索引数据上,我需要用到三个索引,从indexData的6字节偏移后开始,gl.UNSIGNED_SHORT是两个字节的类型,6/2=3,也就是indexData的索引3到索引5的数据进行绘制,也就绘制除了第二个三角形。
到这里其实,大家应该了解了这两种api参数的意义和用法,我感觉自己写的有些问题,我也不一定真懂,哈哈,大家多指教,欢迎加我的3D技术交流群学习交流。
上一篇: cat全链路监控_全链路监控选型