欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WebGL 中的 gl.drawArrays()与gl.drawElements() 你真的懂吗?

程序员文章站 2022-03-10 16:57:26
...

  哈哈,今天群友又问了一个很有意思的问题,问gl.drawElements()如何使用,如何制定绘制的范围,哈哈,很基础的问题,但也难住了很多人,你也可以思考一下如何去实现,Three.js源码拆分几何体地时候就会用到这些api技巧,但是我之前并没有深入去学习,OK,带着问题我们开始吧。
  先来看一下 gl.drawArrays()的ts声明:

drawArrays(mode: number, first: number, count: number): void;

  这个理解起来就比较简单了,就是常说的顶底绘制,这个常用比较简单。
WebGL 中的 gl.drawArrays()与gl.drawElements() 你真的懂吗?
  需要注意的是:
WebGL 中的 gl.drawArrays()与gl.drawElements() 你真的懂吗?
  下面重点来了哈,先看一下gl.drawElements()的ts声明:

drawElements(mode: number, count: number, type: number, offset: number): void;

WebGL 中的 gl.drawArrays()与gl.drawElements() 你真的懂吗?
  这个一看,也没什么难的吗,肯定是根据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技术交流群学习交流。
WebGL 中的 gl.drawArrays()与gl.drawElements() 你真的懂吗?

相关标签: WebGL