4.OpenGL--顶点数组与缓冲区中使用顶点数组

理论基础

  1. 顶点数组:就是把一些顶点数据保存到数组中储存,这些数据包括:顶点坐标,表面法线,RGBA颜色,辅助颜色,颜色索引,雾坐标,纹理坐标以及多边形的边界标志。这样就可以只通过一个函数调用来完成绘制,大大减少了函数的调用次数,同时还可以避免共享顶点的冗余处理,提高了程序性能。
  2. 缓冲区对象:由于OpenGL是一个CS的结构,有时从客服端传输数据到服务端可能会比较缓慢,所以增加了一个缓冲区对象,可以直接显示的指定把哪些数据存储到图形服务器中。

实例代码

  • 使用顶点数组绘制一个三角形
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__
#include 
#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;  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

4.OpenGL--顶点数组与缓冲区中使用顶点数组_第1张图片

注释:这里使用的glArrayElement这种顶点数组解引用和渲染的形式,这也是最基本的方式。在它之上还有一些效率更高的接口,如:glDrawElements(),glMultiDrawElements(),glDrawRangeElements()和glDrawArrays()等。

  • 使用缓冲区对象绘制正方体框
#include "GLTools.h"
#include "GLShaderManager.h"
#ifdef __APPLE__
#include 
#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;  
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94

4.OpenGL--顶点数组与缓冲区中使用顶点数组_第2张图片 
注释:

  • glDrawElements(mode, count, type, indices) 
    是用索引的形式绘制,这样比直接顶点数据渲染效率要高,而这里的索引,直观点讲就是顶点数据数组对应的下标而已。它相当于如下代码: 
    glBegin(mode); 
    for(i = 0; i < count; i++) 
    glArrayElement(indices[i]); 
    glEnd();

你可能感兴趣的:(固定管线OpenGL进阶学习)