1. 程式人生 > >OpenGL--頂點陣列與緩衝區中使用頂點陣列

OpenGL--頂點陣列與緩衝區中使用頂點陣列

理論基礎

  1. 頂點陣列:就是把一些頂點資料儲存到陣列中儲存,這些資料包括:頂點座標,表面法線,RGBA顏色,輔助顏色,顏色索引,霧座標,紋理座標以及多邊形的邊界標誌。這樣就可以只通過一個函式呼叫來完成繪製,大大減少了函式的呼叫次數,同時還可以避免共享頂點的冗餘處理,提高了程式效能。
  2. 緩衝區物件:由於OpenGL是一個CS的結構,有時從客服端傳輸資料到服務端可能會比較緩慢,所以增加了一個緩衝區物件,可以直接顯示的指定把哪些資料儲存到圖形伺服器中。

例項程式碼

  • 使用頂點陣列繪製一個三角形
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__ #include <glut/glut.h> #else #define FREEGLUT_STATIC #endif static GLint vertices[] = {25, 25, 100, 325, 175, 25, 175, 325, 250, 25, 325, 325}; static GLfloat colors[] = {1.0, 0.2, 0.2, 0.2, 0.2, 1.0, 0.8, 1.0, 0.2, 0.75, 0.75, 0.75, 0.35, 0.35, 0.35, 0.5
, 0.5, 0.5}; void display(void) { glClear (GL_COLOR_BUFFER_BIT); //第三步:解引用和渲染 glBegin (GL_TRIANGLES); /*glArrayElement(int v):獲取所有開啟頂點陣列的第v個數據, 作為他們對應的設定資料,執行順序是先執行的其它型別的頂 點陣列,最後才執行頂點座標資料glVertex*v() */ glArrayElement (2); glArrayElement (3); glArrayElement (5); glEnd (); // //上面等價於下面這種形式
// glBegin(GL_TRIANGLES); // glColor3fv(colors + (2 * 3)); // glVertex2iv(vertices + (2 * 2)); // glColor3fv(colors + (3 * 3)); // glVertex2iv(vertices + (3 * 2)); // glColor3fv(colors + (5 * 3)); // glVertex2iv(vertices + (5 * 2)); // glEnd(); glFlush (); } void setupPointers() { //第一步:啟用要使用的頂點陣列 glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_COLOR_ARRAY); //第二步:指定陣列的資料 glVertexPointer (2, GL_INT, 0, vertices); glColorPointer (3, GL_FLOAT, 0, colors); } void init() { glClearColor (0.0, 0.0, 0.0, 0.0); glShadeModel (GL_SMOOTH); setupPointers (); } void reshape (int w, int h) { glViewport (0, 0, (GLsizei) w, (GLsizei) h); /*頂點位置座標,經過變換矩陣的變換,得到的座標,才會真的拿去繪製, 所以這裡的矩陣變換不能省。*/ glMatrixMode (GL_PROJECTION); glLoadIdentity (); gluOrtho2D (0.0, (GLdouble) w, 0.0, (GLdouble) h); } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); glutInitWindowSize (350, 350); glutInitWindowPosition (100, 100); glutCreateWindow ("varray"); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; }

這裡寫圖片描述

註釋:這裡使用的glArrayElement這種頂點陣列解引用和渲染的形式,這也是最基本的方式。在它之上還有一些效率更高的介面,如:glDrawElements(),glMultiDrawElements(),glDrawRangeElements()和glDrawArrays()等。

  • 使用緩衝區物件繪製正方體框
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#endif

#define VERTICES 0
#define INDECES 1
#define NUM_DUFFERS 2
GLuint buffers[NUM_DUFFERS];

static GLfloat vertices[] = {-1.0f, -1.0f, -5.0f, //前面的正方形
    1.0f, -1.0f,-5.0f,
    1.0f, 1.0f, -5.0f,
    -1.0f, 1.0f, -5.0f,
    -1.0f, -1.0f, -10.0f,//背面的正方形
    1.0f, -1.0f, -10.0f,
    1.0f, 1.0f, -10.0f,
    -1.0f, 1.0f, -10.0f};

static GLubyte indices[] = {0, 1, 2, 3, //前面
    0, 3, 7, 4, //左面
    5, 6, 2, 1, //右面
    7, 6, 5, 4, //後面
    3, 2, 6, 7, //上面
    1, 0, 4, 5 //地面
};

void init()
{
    glClearColor (0.0, 0.0, 0.0, 0.0);
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glShadeModel (GL_FLAT);
    glewInit();//glGenBuffers是glew庫的介面,要初始化它才能認識

    //生成緩衝區標示符
    glGenBuffers(NUM_DUFFERS, buffers);
    //繫結頂點緩衝區物件,並設定頂點陣列
    glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES]);//繫結
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);//初始化資料,即將資料拷貝到伺服器記憶體
    glVertexPointer(3, GL_FLOAT, 0, 0);
}

void reshape (int w, int h)
{
    if(h == 0)
        h = 1;

    glViewport(0, 0, w, h);

    GLfloat fAspect = (GLfloat)w / (GLfloat)h;

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    /*透視投影,引數:角度,寬高比,近平面,遠平面*/
    gluPerspective(35.0f, fAspect, 1.0f, 100.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void display(void)
{
    glClear (GL_COLOR_BUFFER_BIT);
    glColor3f(0.0f, 0.0f, 1.0f);

    glPushMatrix();
    glEnableClientState(GL_VERTEX_ARRAY);//啟用頂點陣列
    //繫結索引緩衝區物件,並進行渲染
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[INDECES]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glDrawElements(GL_QUADS, 24, GL_UNSIGNED_BYTE, 0);
    glDisableClientState(GL_VERTEX_ARRAY);//關閉頂點陣列
    glPopMatrix();

    glutSwapBuffers();    
}


int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize (350, 350);
    glutInitWindowPosition (100, 100);
    glutCreateWindow ("VBO");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutMainLoop();
    return 0;  
}

這裡寫圖片描述
註釋:

  • glDrawElements(mode, count, type, indices)
    是用索引的形式繪製,這樣比直接頂點資料渲染效率要高,而這裡的索引,直觀點講就是頂點資料陣列對應的下標而已。它相當於如下程式碼:
    glBegin(mode);
    for(i = 0; i < count; i++)
    glArrayElement(indices[i]);
    glEnd();