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

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

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

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

  1. 創(chuàng)建緩沖區(qū)對象gl.createBuffer()
  2. 綁定緩沖區(qū)對象gl.bindBuffer()
  3. 將數(shù)據(jù)寫入緩沖區(qū)對象gl.bufferData()
  4. 將緩沖區(qū)對象分配給一個attribute變量gl.vertexAttribPointer()
  5. 開始attribute變量gl.enableVertexAttribArray()
  • 繪制三角形的3個頂點
// 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ū)對象
  var vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return -1;
  }

  // 將緩沖區(qū)對象綁定到目標
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  // 向緩沖區(qū)對象中寫入數(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ū)對象分配給a_Position變量
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);

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

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

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

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

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

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

gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)

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

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

第三步变擒,開辟空間并向緩沖區(qū)中寫入數(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個參數(shù)vertices中的數(shù)據(jù)寫入綁定到第1個參數(shù)gl.ARRAY_BUFFER上的緩沖區(qū)對象锌唾。我們不能直接向緩沖區(qū)寫入數(shù)據(jù),而只能向"目標"寫入數(shù)據(jù)触徐,所以要向緩沖區(qū)寫數(shù)據(jù)咪鲜,必須先綁定。

其中撞鹉,參數(shù)usage表示程序?qū)⑷绾问褂么鎯υ诰彌_區(qū)對象中的數(shù)據(jù)疟丙。該參數(shù)將幫助WebGL優(yōu)化操作,但即便傳入了錯誤的值鸟雏,也不會終止程序(僅僅是降低程序的效率)

上面享郊,我們使用了Float32Array對象,而不是JS更常見的Array對象孝鹊。這是因為炊琉,JS中的數(shù)組Array是一種通用的類型,既可以存儲數(shù)字也可以存儲字符串又活,而并沒有對“大量元素都是同一種類型”優(yōu)化苔咪。為了解決這個問題,WebGL引入了類型化的數(shù)組柳骄,F(xiàn)loat32Array就是其中之一团赏。

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

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

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

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

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

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

size指定緩沖區(qū)中每個頂點的分量個數(shù)(1到4)复斥,若size比attribute變量需要的分量數(shù)小营密,缺失分量將按照與gl.vertexAttrib[1234]f()相同的規(guī)則補全。(比如:size為1目锭,那么第2评汰、3分量自動設為0纷捞,第4分量為1)

type為數(shù)據(jù)類型

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

stride指定相鄰兩個頂點間的字節(jié)數(shù)被去,默認為0

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

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

注意:雖然函數(shù)的名稱似乎表示該函數(shù)是用來處理“頂點數(shù)組”的主儡,但實際上它處理的對象是緩沖區(qū)。這是由于歷史原因(從OpenGL中繼承)造成的惨缆。

開啟attribute變量后糜值,就不能再用gl.vertexAttrib[1234]f()向它傳數(shù)據(jù)了,除非你顯示地關閉該attribute變量坯墨。實際上寂汇,你無法(也不應該)同時使用這兩個函數(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指定從哪個頂點開始繪制(整數(shù))

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

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

實際上臼膏,頂點著色器執(zhí)行了n(3)次,我們通過存儲在緩沖區(qū)中的頂點坐標數(shù)據(jù)被依次傳給attribute變量示损。

  • 連接三個頂點,填充三角形

基于上面頂點程序的改動有兩處:

1.在頂點著色器中嚷硫,去掉指定點的尺寸gl_PointSize = 10.0;,該語句只有在繪制單個點的時候才起作用检访。

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

  • WebGL可以繪制的基本圖形
image.png
  • 對應效果
image.png

WebGL有點上頭卖氨,暫時告一段落……

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市负懦,隨后出現(xiàn)的幾起案子筒捺,更是在濱河造成了極大的恐慌,老刑警劉巖纸厉,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件系吭,死亡現(xiàn)場離奇詭異,居然都是意外死亡颗品,警方通過查閱死者的電腦和手機肯尺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門沃缘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人则吟,你說我怎么就攤上這事槐臀。” “怎么了氓仲?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵水慨,是天一觀的道長。 經(jīng)常有香客問我寨昙,道長讥巡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任舔哪,我火速辦了婚禮欢顷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捉蚤。我一直安慰自己抬驴,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布缆巧。 她就那樣靜靜地躺著布持,像睡著了一般。 火紅的嫁衣襯著肌膚如雪陕悬。 梳的紋絲不亂的頭發(fā)上题暖,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音捉超,去河邊找鬼胧卤。 笑死,一個胖子當著我的面吹牛拼岳,可吹牛的內(nèi)容都是我干的枝誊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼惜纸,長吁一口氣:“原來是場噩夢啊……” “哼叶撒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耐版,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤祠够,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后粪牲,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哪审,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年虑瀑,在試婚紗的時候發(fā)現(xiàn)自己被綠了湿滓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片滴须。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖叽奥,靈堂內(nèi)的尸體忽然破棺而出扔水,到底是詐尸還是另有隱情,我是刑警寧澤朝氓,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布魔市,位于F島的核電站,受9級特大地震影響赵哲,放射性物質(zhì)發(fā)生泄漏待德。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一枫夺、第九天 我趴在偏房一處隱蔽的房頂上張望将宪。 院中可真熱鬧,春花似錦橡庞、人聲如沸较坛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丑勤。三九已至,卻和暖如春吧趣,著一層夾襖步出監(jiān)牢的瞬間法竞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工强挫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爪喘,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓纠拔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親泛豪。 傳聞我的和親對象是個殘疾皇子稠诲,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容