上節(jié)我們畫了 3 個(gè)紅色的點(diǎn)月而,點(diǎn)的顏色是寫死在 fragment shader 中柔袁。這節(jié)我們來畫 3 個(gè)不同顏色的點(diǎn)。
首先現(xiàn)在除了頂點(diǎn)的坐標(biāo)之外還要把每個(gè)頂點(diǎn)的顏色傳到 shader 中。前面說過有 2 種方法,一是可以定義 2 個(gè)數(shù)組冀自,2 個(gè) buffer object 分別來傳遞坐標(biāo)和顏色,二是可以把每個(gè)頂點(diǎn)的坐標(biāo)和顏色都放在 1 個(gè)數(shù)組中用 1 個(gè) buffer object 傳過去然后再分開解析秒啦。兩種方法各有利弊熬粗,首先分開傳肯定沒有一塊傳效率高,而一塊傳的弊端是當(dāng)你只想更新顏色而坐標(biāo)不變時(shí)也必須更新整個(gè)數(shù)組余境,這個(gè)要看具體情況驻呐。用 2 個(gè) buffer object 分開傳的情況留給大家自己練習(xí),我們來看看一塊傳的情況葛超。
// vertex shader
var VERTEX_SHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_Position = a_Position;\n' +
' gl_PointSize = 10.0;\n' +
' v_Color = a_Color;\n' +
'}\n';
// fragment shader
var FRAGMENT_SHADER_SOURCE =
'precision mediump float;\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
' gl_FragColor = v_Color;\n' +
'}\n';
- attribute vec4 a_Color
增加了一個(gè) attribute 變量 a_Color 來接收顏色
但顏色是在 fragment shader 中計(jì)算的暴氏,怎么把 vertex shader 中的顏色傳遞到 fragment shader 中呢延塑? 這就要用到 varying 變量绣张, 當(dāng)同一個(gè) varying 變量 (類型和名字都一樣)同時(shí)定義在 vertex shader 和 fragment shader 中時(shí), varying 變量的值會(huì)自動(dòng)從 vertex shader 中傳遞到 fragment shader 中关带。
- varying vec4 v_Color;
v_Color = a_Color;
我們定義了 v_Color 這個(gè) varying 變量侥涵,并賦值為 a_Color
來個(gè)直觀的圖,大家感受一下
attribute 和 varying 變量都必須定位為全局變量宋雏, main 是入口函數(shù)芜飘。
- precision mediump float
這是什么意思呢? precision 是精度修飾符磨总,mediump (medium precision) 中等精度嗦明, 意思是 fragment shader 中所有的 float 都用中等精度表示。
fragment shader 中默認(rèn)沒有為 float 指定精度蚪燕,必須手動(dòng)指定娶牌,主要是為了在有些情況下必須使用 highp (高精度) 或用 lowp (低精度) 來提高性能奔浅。
vertex shader 中數(shù)據(jù)默認(rèn)都是 highp 的,因?yàn)檫@適用于大多數(shù)情況诗良。
現(xiàn)在頂點(diǎn)中要增加顏色信息
var vertices = new Float32Array([
0.0, 0.5, 1.0, 0.0, 0.0, // (x,y) (r,g,b)
-0.5, -0.5, 0.0, 1.0, 0.0,
0.5, -0.5, 0.0, 0.0, 1.0
]);
每個(gè)頂點(diǎn)前 2 位表示位置汹桦,后 3 位表示顏色
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
// 每個(gè)元素的字節(jié)數(shù), 這里是 float 類型, 所以是 4 個(gè)字節(jié)
var BYTES_PER_ELEMENT = vertices.BYTES_PER_ELEMENT;
// 屬性變量和數(shù)據(jù)關(guān)聯(lián)起來并指定解析方法
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 5 * BYTES_PER_ELEMENT, 0);
// enable the assignment to attribute variable
gl.enableVertexAttribArray(a_Position);
gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 5 * BYTES_PER_ELEMENT, 2 * BYTES_PER_ELEMENT);
gl.enableVertexAttribArray(a_Color);
- vertices.BYTES_PER_ELEMEN
得到每個(gè)元素的字節(jié)數(shù), float 類型是 4 個(gè)字節(jié)
- gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 5 * BYTES_PER_ELEMENT, 0);
a_Position 我們傳了 2 個(gè)值鉴裹, 元素類型是 float
倒數(shù)第二個(gè)參數(shù)表示各個(gè)坐標(biāo)之間間隔的字節(jié)數(shù)舞骆,每個(gè)頂點(diǎn)的坐標(biāo)之間間隔 5 * 4 = 20 個(gè)字節(jié)
最后一個(gè)參數(shù)表示第一個(gè)頂點(diǎn)坐標(biāo)的起始位置,這里是 0
- gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, 5 * BYTES_PER_ELEMENT, 2 * BYTES_PER_ELEMENT);
a_Color 我們傳了 3 個(gè)值径荔, 元素類型是 float
倒數(shù)第二個(gè)參數(shù)表示各個(gè)顏色之間間隔的字節(jié)數(shù)督禽,每個(gè)頂點(diǎn)的顏色之間間隔 5 * 4 = 20 個(gè)字節(jié)
最后一個(gè)參數(shù)表示第一個(gè)頂點(diǎn)顏色的起始位置,這里是 2 * 4 = 8 個(gè)字節(jié)
頂點(diǎn)中除了位置总处、顏色還可以攜帶 norm (法向量)赂蠢、texture coord (紋理坐標(biāo)) 等,一般都是一塊傳過去后再分開解析辨泳。
最后 draw 不變還是畫 3 個(gè)頂點(diǎn)
gl.drawArrays(gl.POINTS, 0, 3);
練習(xí):
- 用 2 個(gè) buffer object 分別傳遞位置和顏色