OpenGL学习06_顶点数组VertexArray

来源:互联网 发布:淘宝藏族舞蹈头饰 编辑:程序博客网 时间:2024/06/09 00:08

什么是顶点数组?

OpenGL提供了一些顶点数组函数,允许只用少数几个数组指定大量的与顶点相关的数据,并用少量函数调用(与顶点数组的数量相仿)访问这些数据。使用顶点数组函数,一个拥有20条边的多边形的20个顶点可以放在1个数组中,并且只通过1个函数进行调用。如果每个顶点还有一条法线向量,所有20条法线向量可以放在另一个数组中,也可以只通过1个函数进行调用。把数据放在顶点数组中可以提高应用程序的性能。使用顶点数组可以减少函数调用的次数,从而提高性能。另外,使用顶点数组还可以避免共享顶点的冗余处理

使用顶点数组对几何图形进行渲染需要3个步骤:

1) 激活(启用)最多可达8个数组,每个数组用于存储不同类型的数据:顶点坐标、表面法线、RGBA颜色、辅助颜色、颜色索引、雾坐标、纹理坐标以及多边形的边界标志。

[cpp] view plain copy
  1. void glEnableClientState(GLenum array)  
指定了需要启用的数组。array参数可以使用下面这些符号常量:
GL_VERTEX_ARRAY、GL_COLOR_ARRAY、GL_SECONDARY_COLOR_ARRAY、GL_INDEX_ARRAY、GL_NORMAL_ARRAY、GL_FOG_COORDINATE_ARRAY、GL_TEXTURE_COORD_ ARRAY和GL_EDGE_FLAG_ARRAY。
开启和关闭顶点数组的用法如下:
[cpp] view plain copy
  1. //启用顶点数组  
  2. glEnableClientState(GL_VERTEX_ARRAY);  
  3. //关闭顶点数组  
  4. glDisableClientState(GL_VERTEX_ARRAY);  

2) 把数据放入数组中。这些数组是通过它们的内存位置的地址(即指针)进行访问的。在客户-服务器模型中,这些数组存储在客户机的地址空间中,除非选择使用缓冲区对象,这时候,数组存储在服务器内存中。

可以通过一种简单的方法,用一条命令指定客户空间中的一个数组。共有8个不同的函数可以用来指定数组,每个函数用于指定一个不同类型的数组。另外,还有一个函数可以一次指定客户空间中的几个数组,它们均来源于一个混合数组。

[cpp] view plain copy
  1. void glVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);  

指定了需要访问的空间坐标数据。pointer是数组包含的第一个顶点的第一个坐标的内存地址。type指定了数组中每个坐标的数据类型(GL_SHORT、GL_INT、GL_FLOAT或GL_DOUBLE)。size是每个顶点的坐标数量,它必须是2、3或4。stride是连续顶点之间的字节偏移量。如果stride是0,数组中的顶点便是紧密相邻的。
为了访问其他几个数组,可以使用下面这些类似的函数:

[cpp] view plain copy
  1. void glColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);  
  2. void glSecondaryColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);  
  3. void glIndexPointer(GLenum type, GLsizei stride, const GLvoid *pointer);  
  4. void glNormalPointer(GLenum type, GLsizei stride, const GLvoid *pointer);  
  5. void glFogCoordPointer(GLenum type, GLsizei stride, const GLvoid *pointer);  
  6. void glTexCoordPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);  
  7. void glEdgeFlagPointer(GLsizei stride, const GLvoid *pointer);  

3) 用这些数据绘制几何图形。OpenGL通过指针从所有的被激活数组中获取数据。在客户端-服务器模型中,数据被传输到服务器的地址空间中。有3种方式可以完成这个任务:
• 访问单独的数组元素(随机存取)。
• 创建一个单独数组元素的列表(系统存取)。
• 线性地处理数组元素。

在顶点数组的内容被解引用(即提取指针所指向的数据)之前,数组一直保存在客户端,它们的内容很容易进行修改。在步骤3中,数组中的数据被提取,接着发送到服务器,然后发送到图形处理管线进行渲染。可以从单个数组元素(索引位置)提取数据,也可以从一个有序的数组元素列表(可能被限制为整个顶点数组数据的一个子集)中提取数据,或者从一个数组元素序列中提取数据。

解引用单个数组元素

[cpp] view plain copy
  1. void glArrayElement(GLint ith)  
获取当前所有已启用数组的一个顶点(第ith个)的数据。对于顶点坐标数组,对应的函数是glVertex[size][type]v(),其中size是[2, 3, 4]之一。type是[s, i, f, d]之一,分别表示GLshort、GLint、GLfloat和GLdouble。size和type都是由glVertexPointer()函数定义的。对于其他启用的数组,glArrayElement()分别调用glEdgeFlagv()、glTexCoord[size][type]v()、glColor[size][type]v()、glSecondaryColor3[type]v()、glInde[type]v()、glNormal3[type]v()和glFogCoord[type]v()。如果启用了顶点坐标数组,在其他几个数组(如果启用)相对应的函数(与数组值相对应,最多可达7个)被执行之后,glVertex*v()函数在最后执行。
glArrayElement()通常是在glBegin()和glEnd()之间调用。否则,glArrayElement()函数就会设置所有启用的数组的当前状态(顶点除外,因为它不存在当前状态)

解引用数组元素的一个列表

[cpp] view plain copy
  1. void glDrawElements(GLenum mode,GLsizei count,GLenum type,void *indices);  

mode(图元的类型)、count(元素的数量)、type(数据类型)和indices(顶点数据的数组位置)。glDrawRangeElements()引入了两个新参数:start和end,它们指定了indices可以接受的值的范围。indices数组中的值必须位于start和end之间才是合法的(包含start和end)。

调用glDrawArrays()函数的效果差不多相当于下面这段代码:
[cpp] view plain copy
  1. glBegin (mode);  
  2. for (i = 0; i < count; i++)  
  3.     glArrayElement(first + i);  
  4. glEnd();  
和glDrawElements()相似,glDrawArrays()也会对它的参数值执行错误检查,如果对应的数组被启用,它会导致当前的RGB颜色、辅助颜色、颜色索引、法线坐标、雾坐标、纹理坐标和边界标志处于不确定状态。

解引用一个数组元素序列

glArrayElements()、glDrawElements()和glDrawRangeElements()能够对数据数组进行随机存取,但是glDrawArrays()只能按顺序访问它们。

[cpp] view plain copy
  1. void glDrawArrays(GLenum mode, GLint first, GLsizei count);  
创建一个几何图元序列,使用每个被启用的数组中从first开始,到first + count-1结束的数组元素。mode指定了创建的图元类型,它的值和glBegin()函数所接受的参数值相同。例如:GL_POLYGON、GL_LINE_LOOP、GL_LINES和GL_POINTS等。
调用glDrawArrays()函数的效果差不多相当于下面这段代码:

[cpp] view plain copy
  1. glBegin (mode);  
  2. for (i = 0; i < count; i++)  
  3.     glArrayElement(first + i);  
  4. glEnd();  

和glDrawElements()相似,glDrawArrays()也会对它的参数值执行错误检查,如果对应的数组被启用,它会导致当前的RGB颜色、辅助颜色、颜色索引、法线坐标、雾坐标、纹理坐标和边界标志处于不确定状态。

一个小例子

[cpp] view plain copy
  1. //  
  2. //  main.cpp  
  3. //  OpenGL_05_VertexArray  
  4. //  
  5. //  Created by apple on 14/12/30.  
  6. //  Copyright (c) 2014年 cc. All rights reserved.  
  7. //  
  8.   
  9. #include <iostream>  
  10. #include <GLUT/GLUT.h>  
  11.   
  12. #define POINTER 1           //使用分别指定坐标和颜色顶点数组方式  
  13. #define INTERLEAVED 2       //使用混合指定坐标和颜色顶点数组方式  
  14.   
  15.   
  16. #define DRAWARRAY 1         //使用DrawArray方式  
  17. #define ARRAYELEMENT  2     //使用ArrayElement方式  
  18. #define DRAWELEMENTS 3      //使用DrawElement方式  
  19.   
  20. //当前设置的模式  
  21. int setupMethod = POINTER;  
  22. int derefMethod = DRAWARRAY;  
  23.   
  24. /** 
  25.  *  设置顶点坐标数组和顶点颜色数组(分别指定) 
  26.  */  
  27. void setupPointers() {  
  28.       
  29.     //顶点坐标数组  
  30.     static GLint vertices[] = {25, 25,  
  31.         100, 325,  
  32.         175, 25,  
  33.         175, 325,  
  34.         250, 25,  
  35.         325, 325  
  36.     };  
  37.       
  38.     //顶点颜色RBG数组  
  39.     static GLfloat colors[] = {1.0, 0.2, 0.2,  
  40.         0.2, 0.2, 1.0,  
  41.         0.8, 1.0, 0.2,  
  42.         0.75, 0.75, 0.75,  
  43.         0.35, 0.35, 0.35,  
  44.         0.5, 0.5, 0.5  
  45.     };  
  46.       
  47.     //启用顶点坐标数组  
  48.     glEnableClientState(GL_VERTEX_ARRAY);  
  49.     //启用顶点颜色数组  
  50.     glEnableClientState(GL_COLOR_ARRAY);  
  51.       
  52.     //指定顶点坐标数据  
  53.     glVertexPointer(2, GL_INT, 0, vertices);  
  54.     //指定顶点颜色数据  
  55.     glColorPointer(3, GL_FLOAT, 0, colors);  
  56.       
  57. }  
  58.   
  59. /** 
  60.  *  设置顶点坐标和顶点颜色数组(混合数组) 
  61.  */  
  62. void setupInterleave() {  
  63.       
  64.     /** 
  65.      *  intertwined[0~2]* n 为顶点坐标 
  66.      *  intertwined[3~5]* n 为顶点颜色 
  67.      */  
  68.     static GLfloat intertwined[] = {  
  69.         1.0, 0.2, 1.0, 100.0, 100.0, 0.0,  
  70.         1.0, 0.2, 0.2, 0.0, 200.0, 0.0,  
  71.         1.0, 1.0, 0.2, 100.0, 300.0, 0.0,  
  72.         0.2, 1.0, 0.2, 200.0, 300.0, 0.0,  
  73.         0.2, 1.0, 1.0, 300.0, 200.0, 0.0,  
  74.         0.2, 0.2, 1.0, 200.0, 100.0, 0.0  
  75.     };  
  76.       
  77.     //指定混合顶点数组  
  78.     glInterleavedArrays (GL_C3F_V3F, 0, intertwined);  
  79. }  
  80.   
  81. /** 
  82.  *  初始化操作 
  83.  */  
  84. void init() {  
  85.     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);  
  86.     //设置着色模式  
  87.     //GL_SMOOTH 制定的两点颜色进行插值,绘制之间的其他点  
  88.     //如果两点的颜色相同,使用两个参数效果相同  
  89.     //如果两点颜色不同,会出现过渡效果  
  90.     glShadeModel(GL_SMOOTH);  
  91.     //设置顶点数组,分别指定颜色和坐标  
  92.     setupPointers();  
  93. }  
  94.   
  95. /** 
  96.  *  展示绘制效果 
  97.  */  
  98. void display() {  
  99.       
  100.     //清理颜色缓冲区  
  101.     glClear(GL_COLOR_BUFFER_BIT);  
  102.       
  103.     if (derefMethod == DRAWARRAY) {  
  104.         //从顶点数组中的第一个顶点开始连续取6个顶点,绘制三角形  
  105.         glDrawArrays(GL_TRIANGLES, 0, 6);  
  106.     } else if (derefMethod == ARRAYELEMENT) {  
  107.         //取顶点坐标数组中的任意3个点进行绘制三角形  
  108.         glBegin(GL_TRIANGLES);  
  109.         glArrayElement(2);  
  110.         glArrayElement(3);  
  111.         glArrayElement(5);  
  112.         glEnd();  
  113.     } else if (derefMethod == DRAWELEMENTS) {  
  114.         //指定需要绘制的顶点的索引,绘制多边形  
  115.         GLuint indices[4] = {0, 1, 3, 4};  
  116.         glDrawElements(GL_POLYGON, 4, GL_UNSIGNED_INT, indices);  
  117.     }  
  118.       
  119.     glFlush ();  
  120.       
  121. }  
  122.   
  123. /** 
  124.  *  调整窗口尺寸 
  125.  * 
  126.  *  @param width  宽度 
  127.  *  @param height 高度 
  128.  */  
  129. void reshape(int width, int height) {  
  130.     //设置视口矩形区域,在默认情况下,视口被设置为占据打开窗口的整个像素矩形  
  131.     glViewport(0, 0, (GLsizei)width, (GLsizei)height);  
  132.     //对投影矩阵应用随后的矩阵操作  
  133.     glMatrixMode(GL_PROJECTION);  
  134.     //等于是将之前矩阵变换导致变化过的栈顶矩阵重新归位,置为单位矩阵!等于是之前的矩阵变换带来的影响到此为止了!  
  135.     glLoadIdentity();  
  136.     //指定2D裁剪坐标系,naer和far使用默认值-1和1  
  137.     gluOrtho2D(0.0, (GLdouble)width, 0.0, (GLdouble)height);  
  138. }  
  139.   
  140. /** 
  141.  *  键盘事件回调 
  142.  * 
  143.  *  @param key 键位 
  144.  *  @param x   x坐标 
  145.  *  @param y   y坐标 
  146.  */  
  147. void keyboard(unsigned char key, int x, int y) {  
  148.     switch (key) {  
  149.             //ESC  
  150.         case 27:  
  151.             exit(0);  
  152.             break;  
  153.     }  
  154. }  
  155.   
  156. /** 
  157.  *  鼠标事件回调 
  158.  * 
  159.  *  @param button 按钮类型 
  160.  *  @param state  点击状态 
  161.  *  @param x      x坐标 
  162.  *  @param y      y坐标 
  163.  */  
  164. void mouse (int button, int state, int x, int y) {  
  165.     switch (button) {  
  166.         //左键  
  167.         case GLUT_LEFT_BUTTON:  
  168.             if (state == GLUT_DOWN) {  
  169.                 //点击左键,(使用颜色和坐标分离的数组方式) 和 (使用混合数组的方式) 切换  
  170.                 if (setupMethod == POINTER) {  
  171.                     setupMethod = INTERLEAVED;  
  172.                     setupInterleave();  
  173.                 } else if (setupMethod == INTERLEAVED) {  
  174.                     setupMethod = POINTER;  
  175.                     setupPointers();  
  176.                 }  
  177.                 //重绘  
  178.                 glutPostRedisplay();  
  179.             }  
  180.             break;  
  181.         //右键  
  182.         case GLUT_RIGHT_BUTTON:  
  183.             if (state == GLUT_DOWN) {  
  184.                 if (derefMethod == DRAWARRAY) {  
  185.                     derefMethod = ARRAYELEMENT;  
  186.                 } else if (derefMethod == ARRAYELEMENT) {  
  187.                     derefMethod = DRAWELEMENTS;  
  188.                 } else if (derefMethod == DRAWELEMENTS) {  
  189.                     derefMethod = DRAWARRAY;  
  190.                 }  
  191.                 //重绘  
  192.                 glutPostRedisplay();  
  193.             }  
  194.             break;  
  195.         default:  
  196.             break;  
  197.     }  
  198. }  
  199.   
  200. int main(int argc, const char * argv[]) {  
  201.       
  202.     //初始化GLUT库  
  203.     glutInit(&argc, (char**)argv);  
  204.     //设置单缓冲,RGB像素格式的窗口  
  205.     glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);  
  206.     //设置窗口大小  
  207.     glutInitWindowSize(350, 350);  
  208.     //设置窗口坐标  
  209.     glutInitWindowPosition (100, 100);  
  210.     //创建窗口  
  211.     glutCreateWindow("VertexArray");  
  212.       
  213.     //初始化操作  
  214.     init();  
  215.       
  216.     //设置展示的回调方法  
  217.     glutDisplayFunc(display);  
  218.     glutReshapeFunc(reshape);  
  219.     glutKeyboardFunc(keyboard);  
  220.     glutMouseFunc(mouse);  
  221.   
  222.     //绘制线程开始循环  
  223.     glutMainLoop();  
  224.       
  225.     return 0;  
  226. }  


本文由CC原创总结,如需转载请注明出处:http://blog.csdn.net/oktears/article/details/42269263

0 0
原创粉丝点击