webgl 5.畫3個點

前面我們都只傳遞了一個頂點到 vertex shader 中,現在來看看怎么一次傳遞多個頂點進去

draw three points.png

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';

下面來定義 3 個頂點

var vertices = new Float32Array([
    0.0, 0.5,
    -0.5, -0.5,
    0.5, -0.5
]);

這里用了 Float32Array

為了高效的處理數據,必須使用 Typed Array, 支持以下類型

Int8Array     1個字節
Uint8Array    1個字節
Int16Array    2個字節
Uint16Array   2個字節
Int32Array    4個字節
Uint32Array   4個字節
Float32Array  4個字節
Float64Array  8個字節

為了一次傳遞多個頂點到 vertex shader 中,需要用到 Buffer Object, 看看下圖

Buffer Object.png

Buffer Object 其實就是 GPU 中開辟的一塊內存,用來存儲頂點信息

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');

    // 屬性變量和數據關聯起來并指定解析方法
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    // enable the assignment to attribute variable
    gl.enableVertexAttribArray(a_Position);
}
  • gl.createBuffer()

create 一個 buffer object

  • gl.bindBuffer(target, buffer)

將 buffer 綁定到 target 上
target 有 2 種取值: gl.ARRAY_BUFFER 標識 vertex object 里面存的是頂點
gl.ELEMENT_ARRAY_BUFFER 標識 vertex object 里面存的是頂點的索引值

  • gl.bufferData(target, data, usage)

將數據 data 拷貝到綁定到 target 的 buffer object 中。
這里才真在 GPU 中分配內存并從主存拷貝數據,gl.createBuffer() 可以理解為創建了一個指針,這里才知道要分配多少內存。
usage: 提示數據將被怎么使用。可取 gl.STATIC_DRAW 表示數據會被寫一次然后多次使用, gl.STREAM_DRAW 表示數據會被寫一次然后使用幾次, gl.DYNAMIC_DRAW 表示數據會被多次寫入。 這個主要是提高性能用的,僅僅是給 GPU 一個建議,設置錯了也沒事。

  • gl.vertexAttribPointer(location, size, type, normalized, stride, offset)

將 attribute 變量和 buffer object 關聯起來,并指定怎么解析數據。
location: 要關聯的 attribute 地址
size:表示每個頂點你為 attribute 傳遞了幾個 components,因為每個頂點我們只傳了 (x, y) 2 個值,所以這里 size 為 2 ,z 和 w 會取默認值。 顯然 size 的值只能是 1-4。
type: 指定數據類型
normalized : Either true or false to indicate whether nonfloating data should be normalized to [0, 1] or [–1, 1] 。
stride 各個頂點屬性之間的間隔, 單位是字節
offset 第一個頂點屬性的起始位置, 單位是字節

數據類型可以取以下值:
gl.UNSIGNED_BYTE 對應 Uint8Array
gl.SHORT 對應 Int16Array
gl.UNSIGNED_SHORT 對應 Uint16Array
gl.INT 對應 Int32Array
gl.UNSIGNED_INT 對應 Uint32Array
gl.FLOAT 對應 Float32Array

之前說過一個頂點里面可以包括頂點的 position (坐標)、color(顏色)、norm(法向量) 、texture coord(紋理坐標) 等信息。通過 size, type, stride, offset 我們就能循環從 vertex buffer 中提取中各個數據并傳給對應的 attribute 變量。

  • gl.drawArrays(gl.POINTS, 0, 3)

從第 0 個頂點開始,循環處理 3 個頂點
每個頂點都會調用一遍 vertex shader

練習:

  1. 試試 gl.drawArrays(gl.POINTS, 0, 1), gl.drawArrays(gl.POINTS, 2, 1),gl.drawArrays(gl.POINTS, 2, 2)

思考:

  1. 我想讓每個頂點有不同的顏色怎么做?顯然除了位置還要把每個頂點的顏色傳進去,而傳遞顏色信息有 2 種方法,一是我可以再定義一個 buffer object 用來傳遞顏色,二是我把頂點的位置和顏色混在一塊一起傳過去然后再解析, 請看下節

查看源碼

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容