顶点数组以及解引用单个数组
2015-08-27 13:11
225 查看
法线向量
物体的法线向量定义了他的表面在空间中的方向。具体地说定义了他相对于光源的方向。OpenGL使用法线向量确定了这个物体各个顶点所接受的光照。在定义物体的几何形状时,同时也定义了他的法线向量。可以使用glNormal*()函数,把当前法线向量设置为这个函数所标示的值,以后调用glVertex*()时,就会把当前法线向量分配给所指定的顶点。每个顶点尝尝具有不同的法线,所以需要交替调用这个函数。
由于法线向量只表示方向,因此长度无关紧要。法线可以指定为任意长度,但是在执行光照计算之前,需要向量单位化。如果模型只涉及旋转和移动,法线向量就可以保证规范化。如果进行了不规则的变换,在变换之后OpenGL会自动对法线向量进行规范化。为了启用这个功能调用
顶点数组
OpenGL需要大量的函数调用才能完成对几何图元的渲染,以及共享顶点的冗余处理问题。使用顶点数组,允许只用少数几个数组指定大量与顶点相关的数据,并用少量函数调用访问这些数据,把数据放在顶点数组可以提高应用程序的性能。
使用顶点数组对几何图元进行渲染需要三个步骤:
1. 激活最多可达8个数组,每个数组用于存储不同类型的数据:顶点坐标,表面法线,RGBA颜色,辅助颜色,颜色索引,雾坐标,纹理坐标以及多边形边界坐标。
2. 把数据放入数组中。这些数组是通过它们的内存地址(指针)进行访问的。在客户机服务器模型中,这些数组存储在客户机的地址空间中,除非使用缓冲区对象,这时候数据存储在服务器内存中。
3. 用这些数据绘制几何图形。OpenGL通过指针从所有的被激活数组中获取数据。在客户机-服务器模型中,数据被传输到服务器地址空间中。有三种方式完成这个任务:
1. 访问单独数组元素
2. 创建一个单独数组元素的列表
3. 线性的处理数组元素
启用数组:
调用
例如需要使用光照,可能需要为每个顶点定义一条法线向量,这种情况下使用顶点数组时候,需要同时激活表面法线数组以及顶点坐标数组
如果在某个时刻需要关闭光照,需要调用glDisable()函数来关闭光照状态,在关闭光照状态之后,还需要停止更改表面法线状态的值,因为这种做法完全浪费
调用
指定数组数据:
用一条命令指定客户空间中的一个数组。共有8个函数可以用来指定数组,每个函数用于指定一个不同类型的数组。以glVertexpointer为例
指定了需要访问的空间坐标数据。Size是每个顶点的坐标数量,必须是2,3,4.stride是连续顶点之间的字节偏移量,如果为0,数组中顶点便是紧密相连。type指定了数组中每个坐标的数据类型。Pointer是数组包含的第一个顶点的第一个坐标的内存地址。
使用顶点数组表示RGBA颜色和顶点坐标。RGB浮点值以及与它们对应的整型坐标值被加载到
跨距
Gl*Pointer()函数的stride参数告诉OpenGL如何访问指针数组中的数据。他的值应该是两个连续的指针元素之间的字节数量。如果顶点的RGB值和顶点坐标存储在同一个数组中,如下所示
如果只想引用数组中的颜色值或者顶点坐标则需要跳跃读取
如果stride为0,数组中数据是一致的只包含颜色值,或者顶点坐标等。
3解引用和渲染
在顶点数组内容被解引用之前,数组一直保存在客户端,他们的内容很容易进行修改。在这一步骤中,数组中数据被提取,接着发送到服务器,然后发送到图形处理管线进行渲染。可以从单个数组元素提取数据,也可以从一个有序的数组元素列表中提取。
解引用单个数组
获取当前所有已启用数组的的第ith个顶点的数据
对于顶点坐标数组,对应的函数是
等价于解引用函数的那三行代码,由于glArrayElement()对于每个顶点只调用一次,因此他可能会减少函数的调用数量,从而提高程序总体性能。在绘图期间不要修改数组元素内容。
物体的法线向量定义了他的表面在空间中的方向。具体地说定义了他相对于光源的方向。OpenGL使用法线向量确定了这个物体各个顶点所接受的光照。在定义物体的几何形状时,同时也定义了他的法线向量。可以使用glNormal*()函数,把当前法线向量设置为这个函数所标示的值,以后调用glVertex*()时,就会把当前法线向量分配给所指定的顶点。每个顶点尝尝具有不同的法线,所以需要交替调用这个函数。
glBegin(GL_POLYGON); glNormal3fv(n0); glVertex3fv(v0); glNormal3fv(n1); glVertex3fv(v1); glNormal3fv(n2); glVertex3fv(v2); glNormal3fv(n3); glVertex3fv(v3); glEnd();
由于法线向量只表示方向,因此长度无关紧要。法线可以指定为任意长度,但是在执行光照计算之前,需要向量单位化。如果模型只涉及旋转和移动,法线向量就可以保证规范化。如果进行了不规则的变换,在变换之后OpenGL会自动对法线向量进行规范化。为了启用这个功能调用
glEnable(GL_NORMALIZE);如果提供了单位长度的法线,并且只进行均匀缩放,就可以使用
glEnable(GL_RESCALE_NORMAL),用一个常量因子对法线缩放,恢复单位长度。
顶点数组
OpenGL需要大量的函数调用才能完成对几何图元的渲染,以及共享顶点的冗余处理问题。使用顶点数组,允许只用少数几个数组指定大量与顶点相关的数据,并用少量函数调用访问这些数据,把数据放在顶点数组可以提高应用程序的性能。
使用顶点数组对几何图元进行渲染需要三个步骤:
1. 激活最多可达8个数组,每个数组用于存储不同类型的数据:顶点坐标,表面法线,RGBA颜色,辅助颜色,颜色索引,雾坐标,纹理坐标以及多边形边界坐标。
2. 把数据放入数组中。这些数组是通过它们的内存地址(指针)进行访问的。在客户机服务器模型中,这些数组存储在客户机的地址空间中,除非使用缓冲区对象,这时候数据存储在服务器内存中。
3. 用这些数据绘制几何图形。OpenGL通过指针从所有的被激活数组中获取数据。在客户机-服务器模型中,数据被传输到服务器地址空间中。有三种方式完成这个任务:
1. 访问单独数组元素
2. 创建一个单独数组元素的列表
3. 线性的处理数组元素
启用数组:
调用
glEnableClientState()函数,激活选择的数组,在实践中同时可激活数组只有6个,有些数组不能同时激活,例如显示模式可以支持RGBA或颜色索引,但是不能同时支持这两种。
Void glEnableClientState(GLenum array)array参数是一个符号常量。
例如需要使用光照,可能需要为每个顶点定义一条法线向量,这种情况下使用顶点数组时候,需要同时激活表面法线数组以及顶点坐标数组
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
如果在某个时刻需要关闭光照,需要调用glDisable()函数来关闭光照状态,在关闭光照状态之后,还需要停止更改表面法线状态的值,因为这种做法完全浪费
调用
gldisableClientState(GL_NORMAL_ARRAY);
指定数组数据:
用一条命令指定客户空间中的一个数组。共有8个函数可以用来指定数组,每个函数用于指定一个不同类型的数组。以glVertexpointer为例
void glVertexPointer(GLint size,GLenum type,GLsize stride,const Glvoid* pointer);
指定了需要访问的空间坐标数据。Size是每个顶点的坐标数量,必须是2,3,4.stride是连续顶点之间的字节偏移量,如果为0,数组中顶点便是紧密相连。type指定了数组中每个坐标的数据类型。Pointer是数组包含的第一个顶点的第一个坐标的内存地址。
使用顶点数组表示RGBA颜色和顶点坐标。RGB浮点值以及与它们对应的整型坐标值被加载到
GL_COLOR_ARRAY和
GL_VERTEX_ARRAY数组中。
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 }; glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3,GL_FLOAT,0,colors); glVertexPointer(2,GL_INT,0,vertices);
跨距
Gl*Pointer()函数的stride参数告诉OpenGL如何访问指针数组中的数据。他的值应该是两个连续的指针元素之间的字节数量。如果顶点的RGB值和顶点坐标存储在同一个数组中,如下所示
static GLfloat intertwined[]= { 1.0,0.2,1.0,100.0,100.0,0.0, 1.0,0.2,0.2,0.0,200.0,0.0, 1.0,1.0,0.2,100.0,300.0,0.0, 0.2,1.0,0.2,200.0,300.0,0.0, 0.2,1.0,1.0,300.0,200.0,0.0, 0.2,0.2,1.0,200.0,100.0,0.0 };
如果只想引用数组中的颜色值或者顶点坐标则需要跳跃读取
glColorPointer(3,GL_FLOAT,6*sizeof(GLfloat),&intertwined[0]); glVertexPointer(3,GL_FLOAT,6*sizeof(GLfloat),&intertwined[3]);
如果stride为0,数组中数据是一致的只包含颜色值,或者顶点坐标等。
3解引用和渲染
在顶点数组内容被解引用之前,数组一直保存在客户端,他们的内容很容易进行修改。在这一步骤中,数组中数据被提取,接着发送到服务器,然后发送到图形处理管线进行渲染。可以从单个数组元素提取数据,也可以从一个有序的数组元素列表中提取。
解引用单个数组
Void glArrayElement(Glint ith);
获取当前所有已启用数组的的第ith个顶点的数据
对于顶点坐标数组,对应的函数是
glVertex[size][type]v(),其中size和type由
glvertexPointer()函数定义的。其它启用的数组类似。
glArrayElement通常在
glBegin()和
glEnd()之间调用,下面程序使用取自启用的顶点数组的第3,4,6个顶点绘制一个三角形。
void Init() { glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_FLAT); } void myDisplay() { 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, 1.0,1.0,1.0, 1.0,1.0,1.0, 0.35,0.35,0.35, 1.0,1.0,1.0 }; glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3,GL_FLOAT,0,colors); glVertexPointer(2,GL_INT,0,vertices); glBegin(GL_TRIANGLES); glArrayElement(2); glArrayElement(3); glArrayElement(5); glEnd(); glFlush(); glColor3fv(colors +(2*3)); glVertex2iv(vertices +(2*2)); } 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 _tmain(int argc, _TCHAR* argv[]) { glutInit(&argc,(char**)argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100,100); glutInitWindowSize(400,400); glutCreateWindow("绘制三角形"); Init(); glutDisplayFunc(&myDisplay); glutReshapeFunc(reshape); glutMainLoop(); return 0; } 运行结果生成一个白色的三角形 glColor3fv(colors +(2*3)); glVertex2iv(vertices +(2*2)); glColor3fv(colors +(3*3)); glVertex2iv(vertices +(3*2)); glColor3fv(colors +(5*3)); glVertex2iv(vertices+(5*2));
等价于解引用函数的那三行代码,由于glArrayElement()对于每个顶点只调用一次,因此他可能会减少函数的调用数量,从而提高程序总体性能。在绘图期间不要修改数组元素内容。
相关文章推荐
- Scala 深入浅出实战经典 第66讲:Scala并发编程实战初体验
- elk+redis 搭建nginx日志分析平台
- mybatis中实体属性和数据库中的字段不对应相冲突的解决办法
- centos cluster 切换
- POJ 3189--Steady Cow Assignment【二分图多重匹配 && 最大流求解 && 枚举 && 经典】
- SVN服务器搭建02---SVN服务器软件搭建(Ubuntu14.04)
- http 协议上传文件multipart form-data boundary 说明--转载
- 代码优化概要
- 快速掌握 Android Studio 中 Gradle 的使用方法
- iOS开发-我的iOS工程结构
- java 通过LDAP 验证、添加、修改、删除
- java 通过LDAP 验证、添加、修改、删除
- 关于JSP里面的表单提交
- 在 Linux 下使用 RAID(四):创建 RAID 5(条带化与分布式奇偶校验)
- 在 Linux 下使用 RAID(四):创建 RAID 5(条带化与分布式奇偶校验)
- LeetCode Excel Sheet Column Title
- 代码编写命名规范
- 自解代理模式
- 王健林台湾大学演讲实录
- LDAP的特定错误