前面我們都只傳遞了一個(gè)頂點(diǎn)到 vertex shader 中贡珊,現(xiàn)在來(lái)看看怎么一次傳遞多個(gè)頂點(diǎn)進(jìn)去
shader 不變
// vertex shader
var VERTEX_SHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = 10.0;\n' +
'}\n';
// fragment shader
var FRAGMENT_SHADER_SOURCE =
'void main() {\n' +
' gl_FragColor = vec4(1.0,0.0,0.0,1.0);\n' +
'}\n';
下面來(lái)定義 3 個(gè)頂點(diǎn)
var vertices = new Float32Array([
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5
]);
這里用了 Float32Array
為了高效的處理數(shù)據(jù)握恳,必須使用 Typed Array, 支持以下類型
Int8Array 1個(gè)字節(jié)
Uint8Array 1個(gè)字節(jié)
Int16Array 2個(gè)字節(jié)
Uint16Array 2個(gè)字節(jié)
Int32Array 4個(gè)字節(jié)
Uint32Array 4個(gè)字節(jié)
Float32Array 4個(gè)字節(jié)
Float64Array 8個(gè)字節(jié)
為了一次傳遞多個(gè)頂點(diǎn)到 vertex shader 中肌幽,需要用到 Buffer Object, 看看下圖
Buffer Object 其實(shí)就是 GPU 中開辟的一塊內(nèi)存喇辽,用來(lái)存儲(chǔ)頂點(diǎn)信息
function initVertexBuffers(gl, vertices) {
var vertexBuffer = gl.createBuffer();
if (!vertexBuffer) {
console.log('Failed to create buffer object');
return -1;
}
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// write data to the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
// 屬性變量和數(shù)據(jù)關(guān)聯(lián)起來(lái)并指定解析方法
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
// enable the assignment to attribute variable
gl.enableVertexAttribArray(a_Position);
}
- gl.createBuffer()
create 一個(gè) buffer object
- gl.bindBuffer(target, buffer)
將 buffer 綁定到 target 上
target 有 2 種取值: gl.ARRAY_BUFFER 標(biāo)識(shí) vertex object 里面存的是頂點(diǎn)
gl.ELEMENT_ARRAY_BUFFER 標(biāo)識(shí) vertex object 里面存的是頂點(diǎn)的索引值
- gl.bufferData(target, data, usage)
將數(shù)據(jù) data 拷貝到綁定到 target 的 buffer object 中牡昆。
這里才真在 GPU 中分配內(nèi)存并從主存拷貝數(shù)據(jù)周霉,gl.createBuffer() 可以理解為創(chuàng)建了一個(gè)指針掂器,這里才知道要分配多少內(nèi)存。
usage: 提示數(shù)據(jù)將被怎么使用俱箱」停可取 gl.STATIC_DRAW 表示數(shù)據(jù)會(huì)被寫一次然后多次使用, gl.STREAM_DRAW 表示數(shù)據(jù)會(huì)被寫一次然后使用幾次, gl.DYNAMIC_DRAW 表示數(shù)據(jù)會(huì)被多次寫入狞谱。 這個(gè)主要是提高性能用的乃摹,僅僅是給 GPU 一個(gè)建議,設(shè)置錯(cuò)了也沒事跟衅。
- gl.vertexAttribPointer(location, size, type, normalized, stride, offset)
將 attribute 變量和 buffer object 關(guān)聯(lián)起來(lái)孵睬,并指定怎么解析數(shù)據(jù)。
location: 要關(guān)聯(lián)的 attribute 地址
size:表示每個(gè)頂點(diǎn)你為 attribute 傳遞了幾個(gè) components伶跷,因?yàn)槊總€(gè)頂點(diǎn)我們只傳了 (x, y) 2 個(gè)值掰读,所以這里 size 為 2 ,z 和 w 會(huì)取默認(rèn)值叭莫。 顯然 size 的值只能是 1-4磷支。
type: 指定數(shù)據(jù)類型
normalized : Either true or false to indicate whether nonfloating data should be normalized to [0, 1] or [–1, 1] 。
stride 各個(gè)頂點(diǎn)屬性之間的間隔食寡, 單位是字節(jié)
offset 第一個(gè)頂點(diǎn)屬性的起始位置雾狈, 單位是字節(jié)
數(shù)據(jù)類型可以取以下值:
gl.UNSIGNED_BYTE 對(duì)應(yīng) Uint8Array
gl.SHORT 對(duì)應(yīng) Int16Array
gl.UNSIGNED_SHORT 對(duì)應(yīng) Uint16Array
gl.INT 對(duì)應(yīng) Int32Array
gl.UNSIGNED_INT 對(duì)應(yīng) Uint32Array
gl.FLOAT 對(duì)應(yīng) Float32Array
之前說(shuō)過(guò)一個(gè)頂點(diǎn)里面可以包括頂點(diǎn)的 position (坐標(biāo))、color(顏色)抵皱、norm(法向量) 善榛、texture coord(紋理坐標(biāo)) 等信息辩蛋。通過(guò) size, type, stride, offset 我們就能循環(huán)從 vertex buffer 中提取中各個(gè)數(shù)據(jù)并傳給對(duì)應(yīng)的 attribute 變量。
- gl.drawArrays(gl.POINTS, 0, 3)
從第 0 個(gè)頂點(diǎn)開始移盆,循環(huán)處理 3 個(gè)頂點(diǎn)
每個(gè)頂點(diǎn)都會(huì)調(diào)用一遍 vertex shader
練習(xí):
- 試試 gl.drawArrays(gl.POINTS, 0, 1)悼院, gl.drawArrays(gl.POINTS, 2, 1),gl.drawArrays(gl.POINTS, 2, 2)
思考:
- 我想讓每個(gè)頂點(diǎn)有不同的顏色怎么做咒循?顯然除了位置還要把每個(gè)頂點(diǎn)的顏色傳進(jìn)去据途,而傳遞顏色信息有 2 種方法,一是我可以再定義一個(gè) buffer object 用來(lái)傳遞顏色叙甸,二是我把頂點(diǎn)的位置和顏色混在一塊一起傳過(guò)去然后再解析颖医, 請(qǐng)看下節(jié)