02-WebGL緩沖區(qū)對(duì)象

WebGL提供了一種很方便的機(jī)制,即緩沖區(qū)對(duì)象(buffer object),它可以一次性地向著色器傳入多個(gè)頂點(diǎn)的數(shù)據(jù)。

緩沖區(qū)對(duì)象是WebGL系統(tǒng)中的一塊內(nèi)存區(qū)域,我們可以一次性地向緩沖區(qū)對(duì)象中填充大量的頂點(diǎn)數(shù)據(jù),然后將這些數(shù)據(jù)保存在其中,供頂點(diǎn)著色器使用。

使用緩沖區(qū)對(duì)象向頂點(diǎn)著色器傳入多個(gè)頂點(diǎn)的數(shù)據(jù),需要遵循以下5個(gè)步驟:

  1. 創(chuàng)建緩沖區(qū)對(duì)象gl.createBuffer()
  2. 綁定緩沖區(qū)對(duì)象gl.bindBuffer()
  3. 將數(shù)據(jù)寫(xiě)入緩沖區(qū)對(duì)象gl.bufferData()
  4. 將緩沖區(qū)對(duì)象分配給一個(gè)attribute變量gl.vertexAttribPointer()
  5. 開(kāi)始attribute變量gl.enableVertexAttribArray()
  • 繪制三角形的3個(gè)頂點(diǎn)
// Vertex shader program
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '  gl_PointSize = 10.0;\n' +
  '}\n';

// Fragment shader program
var FSHADER_SOURCE =
  'void main() {\n' +
  '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
  '}\n';

function main() {
  // Retrieve <canvas> element
  var canvas = document.getElementById('webgl');

  // Get the rendering context for WebGL
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }

  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }

  // Write the positions of vertices to a vertex shader
  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log('Failed to set the positions of the vertices');
    return;
  }

  // Specify the color for clearing <canvas>
  gl.clearColor(0, 0, 0, 1);

  // Clear <canvas>
  gl.clear(gl.COLOR_BUFFER_BIT);

  // Draw three points
  gl.drawArrays(gl.POINTS, 0, n);
}

function initVertexBuffers(gl) {
  var vertices = new Float32Array([
    0.0, 0.5,   -0.5, -0.5,   0.5, -0.5
  ]);
  var n = 3; // The number of vertices

  // 創(chuàng)建緩沖區(qū)對(duì)象
  var vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return -1;
  }

  // 將緩沖區(qū)對(duì)象綁定到目標(biāo)
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  // 向緩沖區(qū)對(duì)象中寫(xiě)入數(shù)據(jù)
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
  // 將緩沖區(qū)對(duì)象分配給a_Position變量
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

  // 連接a_Position變量與分配給它的緩沖區(qū)對(duì)象
  gl.enableVertexAttribArray(a_Position);

  return n;
}
  1. 創(chuàng)建緩沖區(qū)對(duì)象gl.createBuffer()

執(zhí)行該方法的結(jié)果就是,WebGL系統(tǒng)中多了一個(gè)新創(chuàng)建出來(lái)的緩沖區(qū)對(duì)象。返回值為null表示創(chuàng)建失敗。

相應(yīng)地,gl.deleteBuffer(buffer)函數(shù)可以用來(lái)刪除被gl.createBuffer()創(chuàng)建出來(lái)的緩沖區(qū)對(duì)象

  1. 綁定緩沖區(qū)gl.bindBuffer(target,buffer)

創(chuàng)建緩沖區(qū)的第二步就是將緩沖區(qū)對(duì)象綁定到WebGL系統(tǒng)中已經(jīng)存在的“目標(biāo)”上。這個(gè)“目標(biāo)”表示緩沖區(qū)對(duì)象的用途。允許使用buffer表示的緩沖區(qū)對(duì)象綁定到target表示的目標(biāo)上。

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)

其中,gl.ARRAY_BUFFER表示緩沖區(qū)對(duì)象中包含了頂點(diǎn)的數(shù)據(jù)

  1. 向緩沖區(qū)對(duì)象中寫(xiě)入數(shù)據(jù)gl.bufferData(target,data,usage)

第三步,開(kāi)辟空間并向緩沖區(qū)中寫(xiě)入數(shù)據(jù)。

var vertices = new Float32Array([
    0.0,0.5,-0.5,-0.5,0.5,0.5
])
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

該方法的效果是,將第2個(gè)參數(shù)vertices中的數(shù)據(jù)寫(xiě)入綁定到第1個(gè)參數(shù)gl.ARRAY_BUFFER上的緩沖區(qū)對(duì)象。我們不能直接向緩沖區(qū)寫(xiě)入數(shù)據(jù),而只能向"目標(biāo)"寫(xiě)入數(shù)據(jù),所以要向緩沖區(qū)寫(xiě)數(shù)據(jù),必須先綁定。

其中,參數(shù)usage表示程序?qū)⑷绾问褂么鎯?chǔ)在緩沖區(qū)對(duì)象中的數(shù)據(jù)。該參數(shù)將幫助WebGL優(yōu)化操作,但即便傳入了錯(cuò)誤的值,也不會(huì)終止程序(僅僅是降低程序的效率)

上面,我們使用了Float32Array對(duì)象,而不是JS更常見(jiàn)的Array對(duì)象。這是因?yàn)?,JS中的數(shù)組Array是一種通用的類(lèi)型,既可以存儲(chǔ)數(shù)字也可以存儲(chǔ)字符串,而并沒(méi)有對(duì)“大量元素都是同一種類(lèi)型”優(yōu)化。為了解決這個(gè)問(wèn)題,WebGL引入了類(lèi)型化的數(shù)組,F(xiàn)loat32Array就是其中之一。

  • WebGL使用的各種類(lèi)型化數(shù)組
數(shù)組類(lèi)型 每個(gè)元素所點(diǎn)字節(jié)數(shù) 描述(C語(yǔ)言中的數(shù)據(jù)類(lèi)型)
Int8Array 1 8位整型(singed char)
UInt8Array 1 8位無(wú)符號(hào)整型(unsinged char)
Int16Array 2 16位整型(singed short)
UInt16Array 2 16位無(wú)符號(hào)整型(unsinged short)
Int32Array 4 32位整型(singed int)
UInt32Array 4 32位無(wú)符號(hào)整型(unsinged int)
Float32Array 4 單精度32位浮點(diǎn)數(shù)(float)
Float64Array 8 雙精度64位浮點(diǎn)數(shù)(double)

注意: 與普通的Array數(shù)組不同,類(lèi)型化數(shù)組不支持push()和pop()方法;創(chuàng)建類(lèi)型化數(shù)組的唯一方法就是使用new運(yùn)算符,不能使用[]運(yùn)算符。

  • 類(lèi)型化數(shù)組的方法、屬性和常量
方法、屬性和常量 描述
get(index) 獲取第index個(gè)元素值
set(index,value) 設(shè)置第index個(gè)元素的值為value
set(array,offset) 從第offset個(gè)元素開(kāi)始將數(shù)組array中的值填充進(jìn)去
length 數(shù)組的長(zhǎng)度
BYTES_PER_ELEMENT 數(shù)組中每個(gè)元素所占的字節(jié)數(shù)
  1. 將緩沖區(qū)對(duì)象分配給attribute變量gl.vertexAttribPointer(location,size,type,normalized,stride,offset)

將綁定到gl.ARRAY_BUFFER的緩沖區(qū)對(duì)象分配給由location指定的attribute變量。

  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

參數(shù)location指定待分配attribute變量的存儲(chǔ)位置;

size指定緩沖區(qū)中每個(gè)頂點(diǎn)的分量個(gè)數(shù)(1到4),若size比attribute變量需要的分量數(shù)小,缺失分量將按照與gl.vertexAttrib[1234]f()相同的規(guī)則補(bǔ)全。(比如:size為1,那么第2、3分量自動(dòng)設(shè)為0,第4分量為1)

type為數(shù)據(jù)類(lèi)型

normalize傳入true或false,表明是否將非浮點(diǎn)型的數(shù)據(jù)歸一化到[0,1]或[1,1]區(qū)間

stride指定相鄰兩個(gè)頂點(diǎn)間的字節(jié)數(shù),默認(rèn)為0

offset指定緩沖區(qū)對(duì)象中的偏移量

  1. 開(kāi)啟attribute變量gl.enableVertexAttribArray()
gl.enableVertexAttribArray(a_Position)

注意:雖然函數(shù)的名稱(chēng)似乎表示該函數(shù)是用來(lái)處理“頂點(diǎn)數(shù)組”的,但實(shí)際上它處理的對(duì)象是緩沖區(qū)。這是由于歷史原因(從OpenGL中繼承)造成的。

開(kāi)啟attribute變量后,就不能再用gl.vertexAttrib[1234]f()向它傳數(shù)據(jù)了,除非你顯示地關(guān)閉該attribute變量。實(shí)際上,你無(wú)法(也不應(yīng)該)同時(shí)使用這兩個(gè)函數(shù)。

gl.drawArrays(mode,first,count)

mode指定繪制的方式,可接收:gl.POINTS、gl.LINES、gl.LINES_STRIP、gl.LINE_LOOP、gl.TRIANGLES、gl.TRIANGLE_STRIP、gl.TRINGLE_FAN

first指定從哪個(gè)頂點(diǎn)開(kāi)始繪制(整數(shù))

count 指定繪制需要用到多少個(gè)頂點(diǎn)(整數(shù))

gl.drawArrays(gl.POINTS,0,n) //n為3

實(shí)際上,頂點(diǎn)著色器執(zhí)行了n(3)次,我們通過(guò)存儲(chǔ)在緩沖區(qū)中的頂點(diǎn)坐標(biāo)數(shù)據(jù)被依次傳給attribute變量。

  • 連接三個(gè)頂點(diǎn),填充三角形

基于上面頂點(diǎn)程序的改動(dòng)有兩處:

1.在頂點(diǎn)著色器中,去掉指定點(diǎn)的尺寸gl_PointSize = 10.0;,該語(yǔ)句只有在繪制單個(gè)點(diǎn)的時(shí)候才起作用。

2.gl.drawArrays()方法的第1個(gè)參數(shù)從gl.POINTS被改為了gl.TRINGLES,就相當(dāng)于告訴WebGL,從緩沖區(qū)中的第1個(gè)頂點(diǎn)開(kāi)始,使頂點(diǎn)著色器執(zhí)行3次(n為3),用這3個(gè)點(diǎn)繪制出一個(gè)三角形。

  • WebGL可以繪制的基本圖形
image.png
  • 對(duì)應(yīng)效果
image.png

WebGL有點(diǎn)上頭,暫時(shí)告一段落……

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容