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技術交流羣學習交流。
在這裏插入圖片描述

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