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技术交流群学习交流。
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章