状态量管理和绘制几何物体---3
来源:互联网 发布:淘宝中药央视 编辑:程序博客网 时间:2024/04/29 08:13
法线向量:
顾名思义, 就是垂直与表面方向的向量。对与平面, 一个法线向量就可以标识出平面上所有点的法向。 对与曲面, 每一个点的法向是不同。因此OPENGL提供函数允许为每个多边形或者每个顶点指定法线的。程序员可以用glNormal3×来为指定的顶点赋以当前法线。 例如: glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
然后调用glVertex×() 函数为指定的顶点赋以当前法线。要为每一个物体寻找法线需要完成一些计算----求导,才能利用法线技术达到特定的效果。法线技术一般用在光照技术里面--根据光线与法线向量之间的位置来确定该顶点接收多少光照。
一些注意细节:
1.在一个表面给定处有两个方向相反的向量垂直于此表面。习惯上:法线是指向模型表面外侧的向量。
2. 法线向量仅仅只表示方向,其长度多少不重要。 但是在光照计算执行之前, 必须将其变换为长度1. 可以用x, y, z 都除以(x^2 + y^2 + z^2)^(1/2). 如果模型执行了旋转和平移, 不会改变法线长度,但是执行了不规则的变换, 则应该在变换之后让OPENGL 自动地将其法线向量归一化。 可以调用glEnable(GL_NORMALIZE)。如果支持单位长度法线, 并且只进行了均匀缩放, 就可以通过一个来自模型视图变换矩阵的常量因子, 使用glEnable(GL_RESCALE_NORMAL) 来缩放法线, 将其变换为一个单位长度。上述两种都需要额外的计算,致使程序的性能降低。
顶点数组:
当我们绘制一个20个顶点的多边形,我们要调用22个函数。两个是glBegin() , glEnd(), 其他的就是glVertex*(). 如果还要在顶点加上附加信息, 如前面的边界标志, 颜色, 顶点法线。那么函数调用的就更加频繁了。降低了性能。
还有相邻多边形之间所共有的顶点的冗余处理问题。 如一个立方体。 有6个面,8个共有顶点。如果向上面一样,就相当于为每个顶点指定了三次,总共处理了3×8个顶点。
基于上述问题:
opengl提供了顶点数组函数 :可以把20个顶点放入一个数组, 从而使用一个函数对其调用,如果每一个顶点也有一个颜色, 则可以将其所有的20个表面法线放入另外一个数组, 并且也可以用一个函数对其调用。
那么该如何做呢:
1. 最多可以激活6个数组, 它们中的每一个用于保存不同类型的数据: 顶点坐标, RGBA颜色、颜色索引, 表面法线、纹理坐标、多边形边界标志。
2.将数据放入一个数组或者几个数组中。 在cs模式下, 数据被保存在客户的地址空间中。
3. 使用数据来绘制几何体。 通过解除指针的参考,OPENGL从所有被激活的数组中获得数据。在cs模式下, 数据被传到服务器的地址空间中: 有3中解除指针参考的方法:
a、 存取单个数组元素(随机地四处转发)
b、 创建一个由单个数组元素组成的列表(顺序的四处转发)
c、 处理顺序的数组元素。
对上述第一步: 使用:glEnableClientState (GLenum array); 参数可以当然也有6种:
GL_VERTEX_ARRAY -----顶点坐标
GL_NORMAL_ARRAY -----法线向量
GL_COLOR_ARRAY ------顶点颜色
GL_INDEX_ARRAY -------颜色索引
GL_TEXTURE_COORD_ARRAY -----纹理坐标
GL_EDGE_FLAG_ARRAY -----边界标志。
那么相应的关闭激活的函数: glDisableClientState (GLenum array);
第二步: 有6个不同的函数可以用于指定数组. 例如指定顶点坐标的:void glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
size :每个顶点坐标数目,必须为2, 3,4中的一个。
type:数组中每个坐标的数据类型:GL_SHORT, GL_INT, GL_FLOAT. GL_DOUBLE.
stride : 连续顶点之间的字节偏移。
pointer : 数组中第一个顶点的第一坐标的内存地址。
其他三个参数都好理解,就是stride这个参数不好理解, 是吧?那举个例子:
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 }; glColorPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), &intertwined[0]); glVertexPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), &intertwined[3]);
前三个是一个颜色坐标值, 后三个是顶点坐标值,然后这样交替。
其他5个类似的函数:
void glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
void glIndexPointer (GLenum type, GLsizei stride, const GLvoid *pointer); 尺寸为1
void glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer); 尺寸为3
void glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
void glEdgeFlagPointer (GLsizei stride, const GLvoid *pointer); 尺寸为1
第三步:解除参考和渲染。
1.解除一个数组元素的参考:
利用glArrayElement(GLint ith); 如下代码:
GLfloat intertwined[] = { 1.0, 0.2, 1.0, 10.0, 10.0, 0.0, 1.0, 0.2, 0.2, 0.0, 20.0, 0.0, 1.0, 1.0, 0.2, 10.0, 30.0, 0.0, 0.2, 1.0, 0.2, 20.0, 30.0, 0.0 }; glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glColorPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), &intertwined[0]); glVertexPointer(3, GL_FLOAT, 6 * sizeof(GLfloat), &intertwined[3]); glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glArrayElement(0); // 第 0个顶点 glArrayElement(2); glArrayElement(3); glEnd(); glFlush();
注意在完成图元之前,不要在glBegin 和 glEnd 之间改变任何可能被存取的数组的内容。
2. 解除数组元素的列表:
利用函数: glDrawElements,
上面glBegin 到最底下的代码可以也可这样实现:
GLushort indices[] = { 0, 2, 3 }; glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, indices); glFlush();
第一个参数指定创建什么类型的图元, 第二个参数指定数组的个数,第三个参数指定这个数组的数据类型, 最后一个是数组的指针。
上面的两个函数“四处转发” 数据数组的时, 函数 glDrawArrays() 则直接在数据数组中进行。
void glDrawArrays (GLenum mode, GLint first, GLsizei count);
该函数使用每一个激活数组的起始于first, 结束与first + count -1 的数组元素, 来构造一系列的几何图元。mode 和glBegin一样。
交叉数组, 它一次实现了上面的第一步和第二步, 函数为:
glInterleavedArrays (GLenum format, GLsizei stride, const GLvoid *pointer); 具体使用可以google。
属性组:
OPENGL 把相关的状态变量归纳在一个属性组中。
例如: GL_LINE_BIT 属性包括了五个状态变量: 线宽、 GL_LINE_STIPPLE激活状态、线段的点画线模式、线段的点画线计数器和GL_LINE_SMOOTH激活状态。
使用glPushAttrib() 和 glPopAttrib(), 可以立刻保存 和恢复所有的这 5个状态变量。。
在opengl1.1中, 有两个不同的属性堆栈:原始的矩阵堆栈, 客户属性堆栈。 客户属性堆栈可以用函数 glPushClientAttrib() 和 glPopClientAttrib() 。。因为一些值被保存在硬件当中,所以如果自己编写函数来保存,存取的开销比较大。
大约总共有20个属性组和2个客户组。因为属性都保存在堆栈上, 若向一个满栈中压入数据和从空栈中弹出数据,会发生错误。我们可以用
void glGetIntegerv (GLenum pname, GLint *params);
传递: GL_MAX_ATTRIB_STACK_DEPTH 和GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 获得堆栈深度。
- 状态量管理和绘制几何物体---3
- 状态量管理和绘制几何物体---1
- 状态量管理和绘制几何物体--2
- OpenGL学习二:状态管理和绘制几何物体
- OpenGL状态管理和绘制几何物体之顶点数组
- OpenGL学习日记1状态管理和绘制几何物体
- OpenGL学习(二) 状态管理和绘制几何物体
- opengl编程指南笔记(三)第二章 状态管理和绘制几何物体
- opengl学习笔记——状态管理和绘制几何物体
- OpenGL编程指南之阅读笔记 第二章 状态管理和绘制几何物体
- OpenGL 学习笔记(3)绘制几何物体
- OpenGL 学习笔记(3)绘制几何物体
- OpenGL 学习笔记绘制几何物体
- OpenGL绘制几何物体(特性)
- opengl红宝书第二章 状态管理与几何物体 所得记录
- 状态管理和绘制几何体(一)
- DOM-元素节点几何量和滚动几何量
- Direct3D开启光照和使用材质绘制物体
- php 开发调试阶段记录日志
- 电子竞技游戏市场概论
- Objective-C_实例变量可见度和⽅法
- C陷阱与缺陷读书笔记
- android布局技巧之屏幕适配
- 状态量管理和绘制几何物体---3
- 模板①:背包问题(0-1背包&完全背包&多重背包)
- #pragma 预处理指令详解
- Max Path Sum
- AWS的另类发展:与慧科教育联手,攻入北航在职硕士培训专业
- OC第二天
- hdu - 1506 - Largest Rectangle in a Histogram(dp / 单调栈)
- 蓝鲸的2道360题目作业
- NDK开发,没有你想象的那么难