Opengl编程指南第二章:状态管理、几何绘图
//http://blog.csdn.net/longhuihu/article/details/7701874
1、绘图基础
清除窗口
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
第一句代码设置”清除颜色“,第二句代码将当前颜色缓冲区重置为“清除颜色”。
图形硬件除了color buffer(颜色缓冲区、对应屏幕上的像素颜色),还有其他缓冲区,比如Depth,Stencil,Accumulation,设置这些缓冲区的清除值分别使用:glClearDepth(), glClearStencil(), glClearAccum();清除的命令也是glClear, 参数分别为: GL_DEPTH_BUFFER_BIT,GL_STENCIL_BUFFER_BIT,GL_ACCUM_BUFFER_BIT。
你可以,从效率出发也应该尽量,一次清除多个缓冲区,glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)。
指定颜色
在opengl中,绘制具体的几何图元,和指定颜色是相互独立的。你应该先设置好颜色,再绘制图元,除非这个颜色被设置为其他值,否则opengl会一直使用该颜色来绘制图元。
指定颜色使用函数 glColor3f(),glColor3fv()等。
2、点、线、多边形
点由一个包含3个浮点数的向量表示,又叫vertex(顶点)。opengl使用“齐次坐标“,因此在内部使用4个浮点数的向量表示,(x,y,z,w)。如果w!=0,相当于(x/w,y/w,z/w)。
百度百科"齐次坐标":
所谓齐次坐标就是将一个原本是n维的向量用一个n+1维向量来表示。例如,二维点(x,y)的齐次坐标表示为(hx,hy,h)。由此可以看出,一个向量的齐次表示是不唯一的,齐次坐标的h取不同的值都表示的是同一个点,比如齐次坐标(8,4,2)、(4,2,1)表示的都是二维点(4,2)。
许多图形应用涉及到几何变换,主要包括平移、旋转、缩放。以矩阵表达式来计算这些变换时,平移是矩阵相加,旋转和缩放则是矩阵相乘,综合起来可以表示为p' = m1*p + m2(m1旋转缩放矩阵, m2为平移矩阵, p为原向量 ,p'为变换后的向量)。引入齐次坐标的目的主要是合并矩阵运算中的乘法和加法,表示为p' = M*p的形式。即它提供了用矩阵运算把二维、三维甚至高维空间中的一个点集从一个坐标系变换到另一个坐标系的有效方法。
其次,它可以表示无穷远的点。n+1维的齐次坐标中如果h=0,实际上就表示了n维空间的一个无穷远点
线由两个vertex定义
多边形由一组依次相连闭合的线段组成,可以由一组有序的vertex定义。opengl要求多边形是”简单多边形“:组成多边形的边不相交;同时要求多边形是凸多边形:连接任意两个节点的线段全部处于多边形的内部。
如果你要绘制的多边形不满足这两个条件,总是能分割成满足条件的多边形的。
由于坐标是三维的,所以四个顶点的多边形并不能保证所有点都在同一个平面内;这样的话,一个简单四边形,经过旋转、缩放、投影之后得到的可能不在是一个简单四边形。因此,当多复杂多边形进行分割的时候,一般分割成三角形。
曲线可以用短线段来接近表示,曲面可以由大量的小多边形来接近表示。
3、绘制图元
任何几何图元都是有一组顶点来定义的,opengl通过函数glVertex*()来指定顶点。
绘制图元的代码如下所示:
glBegin(GL_POINTS)
glVertex*(v1)
glVertex*(v2)
...
glEnd()
glBegin(GL_POINTS)表示要绘制的图元是点,glEnd()表示图元的顶点数据结束。要绘制其他图元,把GL_POINTS换成GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, GL_POLYGON。
要想指定顶点的颜色,只要在glVertex*指点调用glColor*即可。
4、基本状态管理
glColor*指定颜色,这就是一种opengl状态。图元最终的渲染效果受到很多状态的影响:纹理、光照、雾等。默认情况下,很多状态都是关闭的,关闭和激活这些状态使用glDisable(GLenum capability)和glEnable(GLenum capability),通过glIsEnabled(GLenum capability)可以查询状态是否激活。
有些状态的值比(true/false)更复杂,通过专门的函数来设置,可以通过下面的函数查询。
void glGetBooleanv(GLenum pname, GLboolean *params);
void glGetIntegerv(GLenum pname, GLint *params);
void glGetFloatv(GLenum pname, GLfloat *params);
void glGetDoublev(GLenum pname, GLdouble *params);
void glGetPointerv(GLenum pname, GLvoid **params);
比如glColor3f设置颜色,glGetFloatv(GL_CURRENT_COLOR,param)可以查询。
5、图元样式
点:glPointSize(GLfloat size)设置点的大小,opengl实现对点的大小范围有限制,可以通过相关API查询。
线:glLineWidth(GLfloat width)设置线的宽度,其范围同样是有限制的。线还可以通过某种模式进行刻画,glEnable(GL_LINE_STIPPLE)打开刻画功能,glLineStipple(GLint factor, GLushort pattern)设定刻画模式,第二个参数是一个16位的short,当作一个位序列来用,1表示当前像素需要刻画,0表示略过;第一个参数是一个扩展因子,pattern的每一位被扩展factor倍。
多边形:多边形有两面:front和back,这俩面可以采用不同的模式来绘制。glPolygonMode(GLenum face, GLenum mode),face可以是GL_FRONT_AND_BACK, GL_FRONT;mode可以是GL_POINT, GL_LINE, or GL_FILL。
一般来说,如果多边形的顶点呈现逆时针方向,则多边形是面向front。“可定向流形”固体(反例是克莱因瓶和莫比乌斯带)都可以通过面向一致的多变形来构造。数学上,多变形的朝向可以由下面公式计算:a>0则front-face,否则back-face
多变形也可以通过一个32位*32位的pattern来刻画,首先调用glEnable(GL_POLYGON_STIPPLE),再调用glPolygonStipple(const GLubyte *mask)。
如果将一个非简单多边形划分成n个简单多边形进行绘制,此时需要隐藏某些多边形的某条边,glEdgeFlag*()命令使得以后续顶点为起点的边被隐藏。
法线:法线是垂直于表面的向量,对平面来说,所有点的法线方向一致,对曲面来说每个点的法线可能都不一样。opengl中,只能对每个顶点设置法线,就像设置颜色一样。对一个物体来说,法线决定了表面各处的空间方向,这对“光照”效果的渲染非常重要。设定法线使用函数glNormal*。
对面上的点来说,有两个向量垂直于面,一般来说法线是指向外部的那个向量。因此如果你想把“外部”和“内部”反转,只需要把法线(x,y,z)变成(-x,-y,-z)即可。
法线是用来表示方向的,其长度是无关紧要的,所以它最终会被规范化(normalized):长度为1。
6、顶点数组
使用glVertex*来指定顶点,绘制图元的方式非常的繁琐,需要大量的函数调用。顶点数组可以改变这种状况,使用顶点数组需要三个步骤:
激活顶点数组:glEnableClientState(GLenum array),参数array是要激活的那个数组,可能的参数值有GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_SECONDARY_COLOR_ARRAY, GL_INDEX_ARRAY, GL_NORMAL_ARRAY, GL_FOG_COORD_ARRAY, GL_TEXTURE_COORD_ARRAY, GL_EDGE_FLAG_ARRAY.
这个函数名称暗示着顶点数组其实存储在client端。glDisableClientState(GLenum array)可以关闭对应数组。
注意:顶点数组从含义上可理解为顶点相关数据的数组,包括坐标,颜色、法线等,上述参数指明了具体数组类型。
为数组赋值:每种数组有一个赋值函数,已vertex为例:
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--连续顶点数组之间的偏移量,如果为零,则意味着顶点数据是紧密排列的
其他数组赋值函数请参考原书或opengl文档
使用数组:glArrayElement(GLint ith)使用指定位置的顶点数组数据,它同时使用所有激活数组的对应位置数据:颜色、法线、顶点坐标;glDrawElements(GLenum mode, GLsizei count, GLenum type,const GLvoid *indices)使用一个索引数组来使用顶点数组绘制图元,mode用来指定图元,count是顶点数量,type是索引数组的元素类型,indice是索引数组的首地址;glDrawArrays(GLenum mode, GLint first, GLsizei count)从数组first位置开始,使用count个顶点绘制图元mode。
7、缓冲区对象buffer object
为了避免内存-显卡之间频繁的数据传输,可以使用buffer object。相比顶点数组,buffer object可以存储更多的数据类型。
创建BO:glGenBuffers(GLsizei n, GLuint *buffers)分配了n个BO ID,存储在buffer里面。glIsBuffer(GLuint buffer)可以查询某个ID是否是有效的BO ID;glDeleteBuffers可以删除BO,回收资源包括BO ID。
激活BO:glBindBuffer(GLenum target, GLuint buffer),buffer是BO ID,target是表示用途的,如 GL_ARRAY_BUFFER, GL_ELEMENT_ARRAY_BUFFER等。如果参数buffer为0,则表明不使用BO。
初始化BO:glBufferData(GLenum target, GLsizeiptr size, const GLvoid *data,GLenum usage)可以为BO分配空间,并初始化数据;usage是BO的用途,仅作为opengl优化性能的提示。
更新数据:glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size,const GLvoid *data)更新BO的部分数据;
GLvoid *glMapBuffer(GLenum target, GLenum access)将BO映射为一个本地内存地址,访问结束后需要调用glUnmapBuffer(GLenum target)来结束访问;glMapBufferRange提供更加精确的map功能。
BO之间拷贝数据:glCopyBufferSubData(GLenum readbuffer, GLenum writebuffer,GLintptr readoffset, GLintptr writeoffset,GLsizeiptr size)可以在BO之间直接拷贝数据。
使用顶点数组BO:分配绑定BO至GL_ARRAY_BUFFER,初始化数据,然后按上节使用顶点数组的流程,唯一的区别在于glVertexPointer,glColorPointer的最后一个参数是BO的偏移值。
注意:GL_ARRAY_BUFFER代表数据数组buffer,如果激活了该类型的BO,则所有原本从本地数据array取数据的操作会指向BO。
Vertex-Array对象:对复杂程序来说,可能需要在很多组数据array之间切换,glVertexPointer()这样的操作会非常频繁。Vertex-array对象将对顶点数据的绑定操作汇集起来,简化操作。详细使用方式请参考原书。
Opengl编程指南第二章:状态管理、几何绘图的更多相关文章
- OpenGL编程指南第九章:纹理映射
转自://http://blog.csdn.net/longhuihu/article/details/8477614 纹理(texture)是一块矩形数据序列,存储的数据为颜色.亮度.alpha值. ...
- OpenGL编程指南(第七版)
OpenGL编程指南(第七版) 转自:http://blog.csdn.net/w540982016044/article/details/21287645 在接触OpenGL中,配置显得相当麻烦,特 ...
- Knockout应用开发指南 第二章:监控属性(Observables)
原文:Knockout应用开发指南 第二章:监控属性(Observables) 关于Knockout的3个重要概念(Observables,DependentObservables,Observabl ...
- [书籍翻译] 《JavaScript并发编程》 第二章 JavaScript运行模型
本文是我翻译<JavaScript Concurrency>书籍的第二章 JavaScript运行模型,该书主要以Promises.Generator.Web workers等技术来讲解J ...
- 编译opengl编程指南第八版示例代码通过
最近在编译opengl编程指南第八版的示例代码,如下 #include <iostream> #include "vgl.h" #include "LoadS ...
- 3-8《Ruby元编程》第二章对象模型
<Ruby元编程> 第二章 对象模型 类定义揭秘inside class definitions: class关键字更像一个作用域操作符,核心作用是可以在里面随时定义方法. [].meth ...
- VS15 openGL 编程指南 配置库 triangle例子
最近去图书馆借了一本书<OpenGL编程指南(原书第八版)>,今天倒腾了一天才把第一个例子运行出来. 所以,给大家分享一下,希望能快速解决配置问题. 一.下载需要的库文件 首先,我们需要去 ...
- [转]OpenGL编程指南(第9版)环境搭建--使用VS2017
1.使用CMake Configure中选择VS2017 Win64 , Finish: 点击Generate. 2.进入build目录 打开GLFW.sln , 生成解决方案. 打开vermilio ...
- Spring学习指南-第二章-Spring框架基础(完)
第二章 Spring框架基础 面向接口编程的设计方法 在上一章中,我们看到了一个依赖于其他类的POJO类包含了对其依赖项的具体类的引用.例如,FixedDepositController 类包含 ...
随机推荐
- unity, EventType.MouseUp注意事项
如果鼠标移出了窗口范围,则即使鼠标抬起也不会收到EventType.MouseUp消息,所以只写 if(event==EventType.MouseUp){ 执行某操作 } 是错误的,会导致非常奇怪的 ...
- unity, GUI.Button texture is black
GUI.Button(rect,tex),结果显示出来tex是黑的,原来是因为我以前在别处调用了GUI.contentColor =Color.black. 参考:http://answers.uni ...
- Xilinx问题查找
1.登录https://www.xilinx.com/ 2.在All下拉菜单选择Support选项查找技术问题,All选项会查找全部关键词,但是大多数我们只需要技术相关的内容
- [svc]salt-grains
用途 1,匹配客户端 2,配置文件里使用 3,资产管理 定义grains方法1: 方法2:
- love2d教程30--文件系统
在游戏里少不了文件操作,在love2d里我们可以直接用lua自带的io函数,如果不熟悉可以先读一下我的lua文件读写. 相对lua,love2d提供了更多的函数, 方便我们操作文件.不过可能处于安全考 ...
- 机器学习:如何通过Python入门机器学习
我们都知道机器学习是一门综合性极强的研究课题,对数学知识要求很高.因此,对于非学术研究专业的程序员,如果希望能入门机器学习,最好的方向还是从实践触发. 我了解到Python的生态对入门机器学习很有帮助 ...
- Office Web App2013 在线查看PDF文件
经常会有客户问,在SharePoint中,如何在浏览器中查看与编辑文档,通常给出的解决方案是集成Office Web App. 而在实际应用过程中,客户通常会要求实现PDF文件在线查看,对于PDF文件 ...
- springMVC介绍
http://www.iteye.com/blogs/subjects/springMVC —————————————————————————————————————————————————————— ...
- tensorflow 保存训练模型ckpt 查看ckpt文件中的变量名和对应值
TensorFlow 模型保存与恢复 一个快速完整的教程,以保存和恢复Tensorflow模型. 在本教程中,我将会解释: TensorFlow模型是什么样的? 如何保存TensorFlow模型? 如 ...
- 【BZOJ】1691: [Usaco2007 Dec]挑剔的美食家(set+贪心)
http://www.lydsy.com/JudgeOnline/problem.php?id=1691 懒得打平衡树了.... 而且multiset是很快的... 排到了rank1 T_T 贪心就是 ...