OpenGL ES 3.0(四)圖元、VBO、VAO

圖元

OpenGL ES 3.0 可供繪製的圖元類型有:
1) Triangles,三角形
2) Lines,線
3) Point sprites,點

三角形

繪製三角形時,可供選擇的繪製方式有:GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN 三種,效果如下:

三角形的三種繪製方式

即:

1) GL_TRIANGLES,共有 n/3 個三角形會被繪製,繪製的方式是:(v0, v1, v2)、(v3, v4, v5) ……

2) GL_TRIANGLE_STRIP,共有 n-2 個三角形會被繪製,繪製的方式是:(v0, v1, v2)、(v2, v1, v3)、(v2, v3, v4)……

3) GL_TRIANGLE_FAN,共有 n-2 個三角形會被繪製,繪製的方式是:(v0, v1, v2)、(v0, v2, v3)、(v0, v3, v4)……

支持 GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP 三種,效果如下:

線的三種繪製方式

可以使用 glLineWidth 指定線的寬度。

多用於遊戲,未研究,略

圖元繪製

除了使用 glDrawArrays 繪製之外,還可以使用 glDrawElements。glDrawArrays 的缺點是頂點不共享,比如:

正方體

如果要用 glDrawArrays 繪製這樣一個立方體,則由於頂點不共享,因此每個面都需要 4 個頂點存儲數據,一共有六個面,需要 24 個頂點數據。

而使用 glDrawElements,則可以定義頂點索引,指定每次繪製一個三角形時,所用到的頂點,比如繪製一個正方形:

const static GLfloat VERTICES[] = {
        -0.5f, 0.5f, 0.0f,  // 頂點 0
        -0.5f, -0.5f, 0.0f, // 頂點 1
        0.5f, -0.5f, 0.0f,  // 頂點 2
        0.5f, 0.5f, 0.0f,   // 頂點 3
};

const static GLfloat COLORS[]{
        0.0f, 1.0f, 0.0f, 1.0f,
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 1.0f, 1.0f
};

const static GLushort INDICES[] = {
        0, 1, 2, // 使用頂點 0、1、2 繪製第一個三角形
        0, 2, 3  // 使用頂點 0、2、3 繪製第二個三角形
};

值得注意的是,圖元繪製的方式有兩種,上述頂點數據和顏色數據分開的屬於第一種,還可以把頂點和顏色數據放在同一個數據裏:

const static GLfloat VERTICES[] = {
        -0.5f, 0.5f, 0.0f,      // 頂點 0
        0.0f, 1.0f, 0.0f, 1.0f,   // 顏色 0
        -0.5f, -0.5f, 0.0f,     // 頂點 1
        1.0f, 0.0f, 0.0f, 1.0f,   // 顏色 1
        0.5f, -0.5f, 0.0f,      // 頂點 2
        0.0f, 0.0f, 1.0f, 1.0f,   // 顏色 2
        0.5f, 0.5f, 0.0f,       // 頂點 3
        1.0f, 0.0f, 1.0f, 1.0f    // 顏色 3
};

只需要在設置頂點、顏色數據的時候指定 stride 和 offset 即可:

const static GLint VERTEX_POS_SIZE = 3;
const static GLint VERTEX_COLOR_SIZE = 4;
const static GLsizei VERTEX_STRIDE = sizeof(GLfloat) * (VERTEX_POS_SIZE + VERTEX_COLOR_SIZE);

glVertexAttribPointer(ATTRIB_POSITION, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE,
                      VERTEX_STRIDE, VERTICES);
glVertexAttribPointer(ATTRIB_COLOR, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE,
                      VERTEX_STRIDE, VERTICES[3]); // 3 爲第一個顏色數據在數組中的位置

Vertex Buffer Object

存儲在應用程序中的頂點數據,在每次調用 glDrawArrays、glDrawElements 的時候,必須從 CPU 內存複製到 graphics 內存中,複製的操作顯得十分繁瑣且降低了程序的運行效率。Vertex Buffer Object(VBO) 可以很好地解決這個問題,它能在繪製圖元之前緩衝頂點或索引數據,避免每次繪製圖元時都要重新發送數據。

使用示例(繼續上面的例子):

1) 生成 VBO 緩存數據

// 生成 3 個 VBO
glGenBuffers(3, mVboIds);
// GL_ARRAY_BUFFER、GL_ELEMENT_ARRAY_BUFFER 是可選的兩個 buffer 目標
glBindBuffer(GL_ARRAY_BUFFER, mVboIds[0]);
// 緩存頂點數據
glBufferData(GL_ARRAY_BUFFER, sizeof(VERTICES), VERTICES, GL_STATIC_DRAW);

// 緩存顏色數據
glBindBuffer(GL_ARRAY_BUFFER, mVboIds[1]);
glBufferData(GL_ARRAY_BUFFER, sizeof(COLORS), COLORS, GL_STATIC_DRAW);

// 緩存索引數據
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVboIds[2]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(INDICES), INDICES, GL_STATIC_DRAW);

2) 使用 VBO 繪製圖元

glBindBuffer(GL_ARRAY_BUFFER, mVboIds[0]);
glEnableVertexAttribArray(ATTRIB_POSITION);
glVertexAttribPointer(ATTRIB_POSITION, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE,
                      sizeof(GLfloat) * VERTEX_POS_SIZE, 0);

glBindBuffer(GL_ARRAY_BUFFER, mVboIds[1]);
glEnableVertexAttribArray(ATTRIB_COLOR);
glVertexAttribPointer(ATTRIB_COLOR, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE,
                      sizeof(GLfloat) * VERTEX_COLOR_SIZE, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVboIds[2]);

glDrawElements(GL_TRIANGLES, INDEX_NUMBER, GL_UNSIGNED_SHORT, 0);

glDisableVertexAttribArray(ATTRIB_POSITION);
glDisableVertexAttribArray(ATTRIB_COLOR);

glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

Vertex Array Objects

VAO 是 OpenGL ES 3.0 引入的新特性,可以使圖元的繪製更高效。VBO 用於緩存頂點、顏色、索引等數據,VAO 則可以認爲是用於緩存 VBO 的容器:

glGenVertexArrays(1, &mVaoId);
glBindVertexArray(mVaoId);

glBindBuffer(GL_ARRAY_BUFFER, mVboIds[0]);
glEnableVertexAttribArray(ATTRIB_POSITION);
glVertexAttribPointer(ATTRIB_POSITION, VERTEX_POS_SIZE, GL_FLOAT, GL_FALSE,
                      sizeof(GLfloat) * VERTEX_POS_SIZE, 0);

glBindBuffer(GL_ARRAY_BUFFER, mVboIds[1]);
glEnableVertexAttribArray(ATTRIB_COLOR);
glVertexAttribPointer(ATTRIB_COLOR, VERTEX_COLOR_SIZE, GL_FLOAT, GL_FALSE,
                      sizeof(GLfloat) * VERTEX_COLOR_SIZE, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVboIds[2]);

glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

繪製圖元時,代碼就會變得非常簡單:

glBindVertexArray(mVaoId);
glDrawElements(GL_TRIANGLES, INDEX_NUMBER, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);

源碼已上傳到 GitHub

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章