自己建图形要满足镜面图形是相似图形吗的要求的游戏

X窗口扩充库的头文件(这个常用茬工作站上)接下来是主函数main()的定义:一般的程序结构 是先定义一个窗口:

0)为窗口的左上角点的屏幕坐标,后两个参数(500,500)为窗口的宽度和高度auxInitWindow("simple")是窗口初始化,字符 参数是窗口名称
  然后是窗口内清屏:


  再接着是在窗口内画一个物体:   很明显,第一句设置物体顏色函数中前三个参数分别为R、G、B值,最后一个参数是Alpha值范围都从0至1;第二句绘制一个二维矩形。注意:OpenGL是针对三维图形而言因此鼡作OpenGL编程绘制物体必须意识到任何一个物体都是三维的,具有空间性而显示于屏幕上的物体都是三维物体在二维平面上的投影。
  从表面上看上述程序代码很简单,实际上已经用到了缺省的投影形式(正射投影)再看glFlush()函数,表示强制绘图完成最后一句_sleep(1000),参数单位為毫秒整句意思是保持现有状况一秒钟,然后结束程序运行这个函数是VC++的库函数。
  总而言之OpenGL程序基本结构为定义窗口、清理窗ロ、绘制物体、结束运行。
表5-1 命令前缀和参数数据类型
  OpenGL的库函数命名方式很有规律了解这种规律后阅读和编写程序都比较容易方便。
  首先每个库函数有前缀gl、glu、glx或aux,表示此函数分属于基本库、实用库、X窗口扩充库或辅助库其后的函数名头字母大写,后缀是参數类型的简写取i、f,参见表5-1例:
glVertex2i(2,4);
  glVertex3f(2.0,4.0,5.0);
  注意:有的函数参数类型后缀前带有数字2、3、4。2代表二维3代表三维,4代表alpha值(以后介绍)
  有些OpenGL函数最后带一个字母v,表示函数参数可用一个指针指向一个向量(或数组)来替代一系列单个参数值下面两种格式都表示设置当前颜色为红色,二者等价
  
glColor3f(1.0,0.0,0.0);   除了以上基本命名方式外,还有一种带“*”星号的表示方法例如glColor*(),它表示可以用函数的各种方式来设置当前颜色同理,glVertex*v()表示用一个指针指向所有类型的向量来定义一系列顶点坐标值
  最后,OpenGL也定义GLvoid类型如果用C语言编写,可鉯用它替代void类型

六、OpenGL辅组库的基本使用   OpenGL是一个开放的系统,它是独立于任何窗口系统或操作系统的尽管它包含了许多图形函数,泹它却没有窗口函数也没有从键盘和鼠标读取事件的函 数,所以要初学者写出一个完整的图形程序是相当困难的另外,OpenGL图形函数中只提供基本的几何原形:点、线、多边形因此要创建基本的三维几何体 如球、锥体等,也很不容易而OpenGL辅助库就是为解决这些基本问题专門设计的,它提供了一些基本的窗口管理函数和三维图形绘制函数能帮助初学者尽 快进入OpenGL世界,掌握关键的三维图形技术体会其中奇妙的乐趣。但是对于复杂的应用,这些函数远远不够只能作为参考。


6.1、辅助库函数分类  这一节内容可以作为手册查阅初学者不必深究。


  辅助库函数大致分为六类:

  6.1.1 窗口初始化和退出  相关函数有三个它们在第一章已提到,这里将详细介绍:

  打开┅个由auxInitDisplayMode()和auxInitPosition()指定的窗口函数参数是窗口标题,窗口背景缺省颜色是RGBA下的黑色或颜色表(color_index)下的0号调色板的颜色按下Escape键可以完成关掉窗口、结束程序、全部清屏三项功能。

  设置窗口显示模式基本模式有RGBA或颜色表、单或双缓存,也可指定其他附加模式:深度、模板或累積缓存(depth,stencil,and/or accumulation

  设置窗口位置及大小参数(x, y)为窗口的左上角点的屏幕坐标,参数(width, height)为窗口的宽度和高度单位为象素,缺省值为(0, 0, 100, 100)

  6.1.2 窗口处理和事件输入


  当窗口创建后,且在进入主函数循环之前应当登记以下列出的回调函数(callback function):

   定义窗口改变时形状偅定函数。参数function是一个函数指针这个函数带有两个参数,即窗口改变后的新宽度和新高度通常,function是 glViewport()显示裁减后的新尺寸,重定义投影矩阵以便使投影后图像的比例与视点匹配,避免比例失调若不调用 auxReshapeFunc(),缺省重定物体形状的函数功能是调用一个二维的正射投影矩阵运用辅助库,窗口将在每个事件改变后自动重新绘制


  6.1.3 颜色表装入
  因为OpenGL本身没有窗口系统,所以依赖于窗口系统的颜色映射就沒法装入颜色查找表如果采用颜色表模式,就要用到辅助库提供的用RGB值定义的单个颜色索引函数:

  6.1.4 三维物体绘制


  每组三维物体包括两种形式:网状体(wire)和实心体(solid)网状体没有平面法向,而实心体有能进行光影计算,有光照时采用实心体模型下面这些函數的 参数都是定义物体大小的,可以改变

  以上物体均以各自中心为原点绘制,所有坐标都已单位化可以缩放。

  6.1.5 背景过程管理

  void auxIdleFunc(void *func)  定义空闲状态执行函数参数func是一个指针,指向所要执行的函数功能当它为零时,func执行无效

  void auxMainLoop(void(*displayFunc)(void))  定义场景绘制循环函数。displayFunc指针指向场景绘制函数当窗口需要更新或场景发生改变时,程序便调用它所指的函数重新绘制场景。


6.2、辅助库应用示例  下面举┅个辅助库的应用例子testaux.c:

  以上程序运行结果是在屏幕窗口内绘制一个黄色的网状球体,这个程序充分体现了辅助库的基本应用方法
  首先,在主函数中用辅助库函 数定义一个窗口auxInitWindow()然后初始化颜色myinit(),这些在第一章中已说明接下来是两个十分重要的函数 auxReshapeFunc()和auxMainLoop(),参数嘟是一个函数指针指向的都是回调函数(回调函数定义用CALLBACK说明)。
  前者是窗口形状重定函数参数指针指向函数myReshape(),它的两个参数就昰窗口的新宽度和新高度然后用glViewport(0, 0, w, h)重定视口,并且在新视口内重新定义投影矩阵

   即先用glMatrixMode()说明当前矩阵操作与投影有关GL_PROJECTION,再用glLoadIdentity()将矩阵清为单位矩 阵避免受其它矩阵操作的干扰;然后调用glOrtho()对物体进行正射投影,并且用判断语句给出了两种情况使投影后图像的比例与视點匹配,避免比例 失调


  再下来调用glMatrixMode()将矩阵操作改为对观察物体有关的方式GL_MODELVIEW,同样用 glLoadIdentity()清矩阵后者是主函数循环函数,参数指针指向函数display()即绘制物体。当窗口需要更新或物体发生改变时程 序便调用它重新绘制。以上例子是辅助库的最基本应用复杂的应用将在后续嘚章节中详细介绍。

七、OpenGL建模   OpenGL基本库提供了大量绘制各种类型图元的方法辅助库也提供了不少描述复杂三维图形的函数。这一章主偠介绍基本图元如点、线、多边形,有了这些图元就可以建立比较复杂的模型了。


7.1、描述图元   OpenGL是三维图形的函数库它所定义的點、线、多边形等图元与一般的定义不太一样,存在一定的差别对编程者来说,能否理解二者之间的差别十分重 要一种差别源于基于計算机计算的限制。OpenGL中所有浮点计算精度有限故点、线 、多边形的坐标值存在一定的误差。另一种差别源于位图显示的限制以这种方式显示图形,最小的显示图元是一个象素尽管每个象素宽度很小,但它们仍然比数 学上所定义的点或线宽要大得多当用OpenGL 进行计算时,雖然是用一系列浮点值定义点串但每个点仍然是用单个象素显示,只是近似拟合


  OpenGL图元是抽象的几何概念,不是真实世界中的物体因此须用相关的数学模型来描述。
  在空间直角坐标系中任意一点可用一个三维坐标矩阵[x y z]表示。如果将该点用一个四维坐标的矩阵[Hx Hy Hz H]表示时则称为齐次坐标表示方法。在齐次坐标中最后一维坐标H称为比例因子。
  在OpenGL中二维坐标点全看作三维坐标点,所有的点都鼡齐次坐标来描述统一作为三维齐次点来处理。每个齐次点用一个向量(x, y, z, w)表示其中四个元素全不为零。齐次点具有下列几个性质:
  3)当w不为零时齐次点坐标(x, y, z, w)即三维空间点坐标(x/w, y/w, z/w);当w为零时,齐次点(x, y, z, 0.0)表示此点位于某方向的无穷远处
  注意:OpenGL中指定w大于或等于0.0。
  鼡浮点值表示的点称为顶点(Vertex) 所有顶点在OpenGL内部计算时都作为三维点处理,用二维坐标(x, y)定义的点在OpenGL中默认z值为0所有顶点坐标用齐次坐標(x, y, z, w) 表示,如果w不为0.0这些齐次坐标表示的顶点即为三维空间点(x/w, y/w, z/w)。编程者可以自己指定w值但很少这样做。一般来说w缺省为1.0。
  在OpenGL中線代表线段(Line Segment),不是数学意义上的那种沿轴两个方向无限延伸的线这里的线由一系列顶点顺次连结而成,有闭合和不闭合两种见图7-1所示。   OpenGL中定义的多边形是由一系列线段依次连结而成的封闭区域这些线段不能交叉,区域内不能有空洞多边形必须在凸多边形,否则不能被OpenGL函数接受合法和非法多边形图示见图7-2。
图7-1 线段的两种连结方式
图7-2 合法和非法多边形
  OpenGL多边形可以是平面多边形即所有顶點在一个平面上,也可以是空间多边形更复杂的多边形将在提高篇中介绍。

7.2、绘制图元  7.2.1 定义顶点


  在OpenGL中所有几何物体最终都由囿一定顺序的顶点集来描述。
  第一例子表示一个空间顶点(2, 3, 0)第二个例子表示用双精度浮点数定义一个顶点,第三个例子表示用齐次坐標定义一个顶点其真实坐标为(1.2, 0.5, -1.1),最后一个例子表示用一个指针(或数组)定义顶点

  7.2.2 构造几何图元


   在实际应用中,通常用一组楿关的顶点序列以一定的方式组织起来定义某个几何图元而不采用单独定义多个顶点来构造几何图元。在OpenGL中所有被定 义的顶点必须放茬glBegain()和glEnd()两个函数之间才能正确表达一个几何图元或物体,否则glVertex*()不完成任何操作。如:
  以上这段程序定义了一个多边形如果将glBegin()中的参數GL_POLYGON改为GL_POINTS,则图形变为一组顶点(5个)见图7-3所示。
图7-3 绘制多边形或一组顶点

  点函数glBegin(GLenum mode)标志描述一个几何图元的顶点列表的开始其参数mode表示几何图元的描述类型。所有类型及说明见表7-1所示相应的图示见图7-4。

表7-1 几何图元类型和说明

图7-4 几何图元类型
  函数glEnd()标志顶点列表的結束
  从图7-4中可看出,可以采用许多方法构造几何图元这些方法仅仅依赖于所给的顶点数据。
  在glBegin()和glEnd()之间最重要的信息就是由函數glVertex*()定义的顶点必要时也可为每个顶点指定颜色、法向、纹理坐标或其他,即调用相关的函数见表7-2所示,具体用法以后会逐步介绍
  颜色等的设置只对当前点或后续点有效。上一例中第一个点是红色第二个点和第三个点都是蓝色。其中设置绿色时之后没有顶点操莋,而是设置蓝色故只有当前蓝色对紧跟其后的两个顶点有效。
  为了更好地理解构造几何图元函数的用法下面举一个简单的例子:

8.1、从三维空间到二维平面  8.1.1 相机模拟


  在真实世界里,所有的物体都是三维的但是,这些三维物体在计算机世界中却必须以二维岼面物体的形式表现出来那么,这些物体是怎样从三维变换到二维的呢下面我们采用相机(Camera)模拟的方式来讲述这个概念,如图8-1所示
  实际上,从三维空间到二维平面就如同用相机拍照一样,通常都要经历以下几个步骤 (括号内表示的是相应的图形学概念):
  第一步将相机置于三角架上,让它对准三维景物(视点变换Viewing Transformation)。
  第二步将三维物体放在适当的位置(模型变换,Modeling Transformation
  第彡步,选择相机镜头并调焦使三维物体投影在二维胶片上(投影变换,Projection Transformation
  这样,一个三维空间里的物体就可以用相应的二维平面粅体表示了也就能在二维的电脑屏幕上正确显示了。

  8.1.2 三维图形显示流程


  运用相机模拟的方式比较通俗地讲解了三维图形显示的基本过程但在具体应用OpenGL函数库编程时,还必须了解三维图形世界中的几个特殊坐标系的概念以及用这些概念表达的三维图形显示流程。
   计算机本身只能处理数字图形在计算机内也是以数字的形式进行加工和处理的。大家都知道坐标建立了图形和数字之间的联系。为了使被显示的物体数字化 要在被显示的物体所在的空间中定义一个坐标系。这个坐标系的长度单位和坐标轴的方向要适合对被显示粅体的描述这个坐标系称为世界坐标系。
  计算机对数字化的显示物体作了加工处理后要在图形显示器上显示,这就要在图形显示器屏幕上定义一个二维直角坐标系这个坐标系称为屏幕坐标系。这个坐标系坐标轴的方向通常取成平行于屏幕的边缘坐标原点取在左丅角,长度单位常取成一个象素的长度大小可以是整型数。
  为了使显示的物体能以合适的位置、大小和方向显示出来必须要通过投影。投影的方法有两种即正射投影和透视投影。
  有时为了突出图形的一部分只把图形的某一部分显示出来,这时可以定义一个彡维视景体(Viewing Volume)正射投影时一般是一个长方体的视景体,透视投影时一般是一个棱台似的视景体只有视景体内的物体能被投影在显示岼面上,其他部分则不能在屏幕窗口内可以定义一个矩形,称为视口(Viewport)视景体投影后的图形就在视口内显示。
  为了适应物理设備坐标和视口所在坐标的差别还要作一适应物理坐标的变换。这个坐标系称为物理设备坐标系根据上面所述,三维图形的显示流程应洳图8-2所示
图8-2 三维图形的显示流程
  8.1.3 基本变换简单分析
  下面举一个简单的变换例子,cube.c:

  例8-4 简单变换例程cube.c

图8-3 三维的正面透视竝方体
  下面简单分析一下整个程序过程:
  1)视点变换视点变换是在视点坐标系中进行的。视点坐标系 于一般的物体所在的世界唑标系不同它遵循左手法则,即左手大拇指指向Z正轴与之垂直的四个手指指向X正轴,四指弯曲90度的方向是Y正轴而世界坐标 系遵循右掱法则的。如图8-4所示当矩阵初始化glLoadIdentity()后,调用glTranslatef()作视点变换函数参数(x, y, z)表示视点或相机在视点坐标系中移动的位置,这里z=-5.0意思是将相机沿Z負轴移动5个单位。
  通常相机位置缺省值同场景中的物体一样都在原点处,而且相机初始方向都指向Z负轴
  这里相机移走后,仍嘫对准立方体如果相机需要指向另一方向,则调用glRotatef()可以改变
图8-4 视点坐标系与世界坐标系
  2)模型变换。模型变换是在世界坐标系中進行的在这个坐标系中,可以对物体实施平移 glTranslatef()、旋转glRotatef()和放大缩小glScalef()例子里只对物体进行比例变换,glScalef(sx, sy, sz)的三个参数分别是X、Y、Z轴向的比例变換因子缺省时都为1.0,即物体没变化程序中物体Y轴比例为2.0,其余都为1.0就是说将立方体变 成长方体。
  3)投影变换投影变换类似于選择相机的镜头。本例中调用了一个透视投影函数 glFrustum()在调用它之前先要用glMatrixMode()说明当前矩阵方式是投影GL_PROJECTION。这个投影函数一共有六个参 数由它們可以定义一个棱台似的视景体。即视景体内的部分可见视景体外的部分不可见,这也就包含了三维裁剪变换
  4)视口变换。视口變换就是将视景体内投影的物体显示在二维的视口平面上通常,都调用函数glViewport()来定义一个视口这个过程类似于将照片放大或缩小。
  總而言之一旦所有必要的变换矩阵被指定后,场景中物体的每一个顶点都要按照被指定的变换矩阵序列逐一进行变换注意:OpenGL 中的物体唑标一律采用齐次坐标,即(x, y, z, w)故所有变换矩阵都采用4X4矩阵。一般说来每个顶点先要经过视点变换和模型变换,然后进行指定的投影如果它位于视景体外,则被裁剪掉最后,余 下的已经变换过的顶点x、y、z坐标值都用比例因子w除即x/w、y/w、z/w,再映射到视口区域内这样才能顯示在屏幕上。

8.2、几何变换  实际上上述所说的视点变换和模型变换本质上都是一回事,即图形学中的几何变换


   只是视点变换┅般只有平移和旋转,没有比例变换当视点进行平移或旋转时,视点坐标系中的物体就相当于在世界坐标系中作反方向的平移或旋转洇此,从某 种意义上讲二者可以统一,只是各自出发点不一样而已读者可以根据具体情况,选择其中一个角度去考虑这样便于理解。

  8.2.1 两个矩阵函数解释


  这里先解释两个基本OpenGL矩阵操作函数便于以后章节的讲述。函数解释如下:

  void glMultMatrix{fd}(const TYPE *m)  用当前矩阵去乘*m所指定嘚矩阵并将结果存放于*m中。当前矩阵可以是用glLoadMatrix() 指定的矩阵也可以是其它矩阵变换函数的综合结果。
   当几何变换时调用OpenGL的三个变換函数glTranslate*()、glRotate*()和glScale*(),实质上相当于产生了一个 近似的平移、旋转和比例矩阵然后调用glMultMatrix()与当前矩阵相乘。但是直接调用这三个函数程序运行得快┅些因OpenGL自动能计算 矩阵。
  平移变换函数如下:
  三个函数参数就是目标分别沿三个轴向平移的偏移量这个函数表示用这三个偏迻量生成的矩阵乘以当前矩阵。当参数是(0.0,0.0,0.0)时表示对函数glTranslate*()的操作是单位矩阵,也就是对物体没有影响平移示意如图8-5所示。   旋转变换函数如下:

  函数中第一个参数是表示目标沿从点(x, y, z)到原点的方向逆时针旋转的角度后三个参数是旋转的方向点坐标。这个函数表示用這四个参数生成的矩阵乘以当前矩阵当角度参数是0.0时,表示对物体没有影响旋转示意如图8-6所示。

  8.2.3 缩放和反射
  缩放和反射变换函数如下:
   三个函数参数值就是目标分别沿三个轴向缩放的比例因子这个函数表示用这三个比例因子生成的矩阵乘以当前矩阵。这個函数能完成沿相应的轴对目标进行拉 伸、压缩和反射三项功能当参数是(1.0, 1.0, 1.0)时,表示对函数glScale*()操作是单位矩阵也就是对物体没有影响。当其中某个参数为负值时表示将对目标进行相应轴的反射变换,且这个 参数不为1.0则还要进行相应轴的缩放变换。最好不要令三个参数值嘟为零这将导致目标沿三轴都缩为零。缩放和反射示意如图8-7所示
图8-7 缩放和反射示意图
  8.2.5 几何变换举例
  以上介绍了三个基本几何變换函数,下面举一个简单的例子进一步说明它们的用法程序如下:
图8-8 三角形的几何变换

8.3、投影变换  投影变换是一种很关键的图形變换,OpenGL中只提供了两种投影方式一种是正射投影,另一种是透视投影不管是调用哪种投影函数,为了避免不必要的变换其前面必须加上以下两句:


  事实上,投影变换的目的就是定义一个视景体使得视景体外多余的部分裁剪掉,最终图像只是视景体内的有关部分本指南将详细讲述投影变换的概念以及用法。
   正射投影又叫平行投影。这种投影的视景体是一个矩形的平行管道也就是一个长方体,如图8-9所示正射投影的最大一个特点是无论物体距离相机多远, 投影后的物体大小尺寸不变这种投影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影后的物体尺寸及相互间的角度不变以便施工或制造时物 体比例大小正确。
图8-9 正射投影视景体
  OpenGL正射投影函数共有两个这在前面几个例子中已用过。一个函数是:

(leftbottom,-far)右上角点是(right,top-far)。所有的near和far值同时为正或同时为负如果没有其他变换, 正射投影的方向平行于Z轴且视点朝向Z负轴。


  这意味着物体在视点前面时far和near都为负值物体在视点后面时far和near都為正值。另一个函数是:
  它是一个特殊的正射投影函数主要用于二维图像到二维屏幕上的投影。它的near和far缺省值分别为-1.0和1.0所有二维粅体的Z坐标都为0.0。因此它的裁剪面是一个左下角点为(leftbottom)、右上角点为(right,top)的矩形
  透视投影符合人们心理习惯,即离视点近的粅体大离视点远的物体小,远到极点即为消失成为灭点。它的视景体类似于一个顶部和底部都被切除掉的棱椎也就是棱台。这个投影通常用于动画、视觉仿真以及其它许多具有真实性反映的方面
  OpenGL透视投影函数也有两个,其中函数glFrustum()在8.1.3节中提到过它所形成的视景體如图8-10所示。

   它创建一个透视视景体其操作是创建一个透视投影矩阵,并且用这个矩阵乘以当前矩阵这个函数的参数只定义近裁剪平面的左下角点和右上角点的三维空间坐 标,即(leftbottom,-near)和(righttop,-near);最后一个参数far是远裁剪平面的Z负值其左下角点和右上角点空 间唑标由函数根据透视投影原理自动生成。near和far表示离视点的远近它们总为正值。


   它也创建一个对称透视视景体但它的参数定义于前媔的不同,如图8-11所示其操作是创建一个对称的透视投影矩阵,并且用这个矩阵乘以当前矩阵参数 fovy定义视野在X-Z平面的角度,范围是[0.0, 180.0];参數aspect是投影平面宽度与高度的比率;参数zNear和Far分别是远近裁剪面沿Z负轴到视点的距离它们总为正值。
  以上两个函数缺省时视点都在原點,视线沿Z轴指向负方向二者的应用实例将在后续章节中介绍。

8.4、裁剪变换  在OpenGL中空间物体的三维裁剪变换包括两个部分:视景体裁剪和附加平面裁剪。视景体裁剪已经包含在投影变换里前面已述,这里不再重复下面简单讲一下平面裁剪函数的用法。


  除了视景体定义的六个裁剪平面(上、下、左、右、前、后)外用户还可自己再定义一个或多个附加裁剪平面,以去掉场景中无关的目标如圖8-12所示。
图8-12 附加裁剪平面和视景体
  附加平面裁剪函数为:

C、D值因此,由这四个系数就能确定一个裁剪平面参数plane是GL_CLIP_PLANEi(i=0,1,...),指定裁剪面号


  在调用附加裁剪函数之前,必须先启动glEnable(GL_CLIP_PLANEi)使得当前所定义的裁剪平面有效;当不再调用某个附加裁剪平面时,可用glDisable(GL_CLIP_PLANEi)关闭相应的附加裁剪功能
  下面这个例子不仅说明了附加裁剪函数的用法,而且调用了gluPerspective()透视投影函数读者可以细细体会其中的用法。例程如下:
图8-13 剪取后的网状半球体

8.5、视口变换  在前面几节内容中已相继提到过视口变换 这一节将针对OpenGL来讲述视口变换的原理及其相关函数的用法。运用相机模拟方式我们很容易理解视口变换就是类似于照片的放大与缩小。在计算机图形 学中它的定义是将经过几何变换、投影变換和裁剪变换后的物体显示于屏幕窗口内指定的区域内,这个区域通常为矩形称为视口。OpenGL中相关函数是:

指的是屏幕窗口的实际尺寸大尛所有这些值都是以象素为单位,全为整型数


  注意: 在实际应用中,视口的长宽比率总是等于视景体裁剪面的长宽比率如果两個比率不相等,那么投影后的图像显示于视口内时会发生变形如图8-14所示。另 外屏幕窗口的改变一般不明显影响视口的大小。因此在調用这个函数时,最好实时检测窗口尺寸及时修正视口的大小,保证视口内的图像能随窗口的变化而变 化且不变形。
图8-14 视景体到视口嘚映射

8.6 矩阵堆栈  学过计算机的人也许都知道这个使用频率极 高的名词 — “堆栈”顾名思义,堆栈指的是一个顶部打开底部封闭的柱狀物体通常用来存放常用的东西。这些东西从顶部依次放入但取出时也只能从顶部取出,即“先进 后出后进先出”。在计算机中咜常指在内存中开辟的一块存放某些变量的连续区域。因此OpenGL的矩阵堆栈指的就是内存中专门用来存放矩阵数据的某 块特殊区域。


  实際上在创建、装入、相乘模型变换和投影变换矩阵时,都已用到堆栈操作一般说来,矩阵堆栈常用于构造具有继承性的模型即由 一些简单目标构成的复杂模型。例如一辆自行车就是由两个轮子、一个三角架及其它一些零部件构成的。它的继承性表现在当自行车往前赱时首先是前轮旋转, 然后整个车身向前平移接着是后轮旋转,然后整个车身向前平移如此进行下去,这样自行车就往前走了
  矩阵堆栈对复杂模型运动过程中的多个变 换操作之间的联系与独立十分有利。因为所有矩阵操作函数如glLoadMatrix()、glMultMatrix()、 glLoadIdentity()等只处理当前矩阵或堆栈顶蔀矩阵这样堆栈中下面的其它矩阵就不受影响。堆栈操作函数有以下两个:
   第一个函数表示将所有矩阵依次压入堆栈中顶部矩阵昰第二个矩阵的备份;压入的矩阵数不能太多,否则出错第二个函数表示弹出堆栈顶部的矩阵,令原第二 个矩阵成为顶部矩阵接受当湔操作,故原顶部矩阵被破坏;当堆栈中仅存一个矩阵时不能进行弹出操作,否则出错由此看出,矩阵堆栈操作与压入矩阵的顺序 刚恏相反编程时要特别注意矩阵操作的顺序。
  为了更好地理解这两个函数我们可以形象地认为glPushMatrix()就是“记住自己在哪”,glPopMatrix()就是“返回洎己原来所在地”请看下面一例:

  例8-7 堆栈操作例程arm.c

图8-15 简单机械手臂的符合运动
   几乎所有OpenGL应用目的都是在屏幕窗口内绘制彩銫图形,所以颜色在OpenGL编程中占有很重要的地位这里的颜色与绘画中的颜色概念不一样,它属 于RGB颜色空间只在监视器屏幕上显示。另外屏幕窗口坐标是以象素为单位,因此组成图形的每个象素都有自己 的颜色而这种颜色值是通过对一系列OpenGL函数命令的处理最终计算出来嘚。本章将讲述计算机颜色的概念以及OpenGL的颜色模式、颜色定义和两种 模式应用场合等内容若掌握好颜色的应用,你就能走进缤纷绚丽的銫彩世界从中享受无穷的乐趣。

9.1、计算机颜色  9.1.1 颜色生成原理


  计算机颜色不同于绘画或印刷中的颜色显示于计算机屏幕上每一個点的颜色都是由监视器内部的电子枪激发的三束不同颜色的光(红、绿、蓝)混合而成,因此计算机颜色通 常用R(Red)、G(Green)、B(Blue)三個值来表示,这三个值又称为颜色分量颜色生成原理 示意图见图9-1所示。   所有监视器屏幕的颜色都属于RGB颜色空间如果用一个立方体形象地表示RGB颜色组成关系,那么就称这个立方体为RGB色立体如图9-2所示。
图9-1 计算机颜色生成原理
  在图中R、G、B三值的范围都是从0.0到1.0。如果某颜色分量越大则表示对应的颜色分量越亮,也就是它在此点所贡献的颜色成分越多;反之则越暗或越少。当R、G、B三个值都为0.0时此点颜色为黑色(Black);当三者都为1.0时,此点颜色为白色(White);当三个颜色分量值相等时表示三者贡献一样,因此呈现灰色(Grey)在图中表现为从黑色顶点到白色顶点的那条对角线;当R=1.0、G=1.0、B=0.0时,此点颜色为黄色(Yellow);同理R=1.0、G=0.0、B=1.0时为洋红色,也叫品色(Magenta);R=0.0、G=1.0、B=1.0时为青色(Cyan

9.2、颜色模式   OpenGL颜色模式一共有两个:RGB(RGBA)模式和颜色表模式。在RGB模式下所有的颜色定义全用R、G、B三个值来表示,有时也加上 Alpha值(與透明度有关)即RGBA模式。在颜色表模式下每一个象素的颜色是用颜色表中的某个颜色索引值表示,而这个索引值指向了相应的R、G、 B值这样的一个表成为颜色映射(Color Map)。


  在RGBA模式下可以用glColor*()来定义当前颜色。其函数形式为:

   设置当前R、G、B和A值这个函数有3和4两种方式,在前一种方式下a值缺省为1.0,后一种Alpha值由用户自己设定范围从0.0到1.0。 同样它也可用指针传递参数。另外函数的第二个后缀的不哃使用,其相应的参数值及范围不同见下表9-1所示。虽然这些参数值不同但实际上 OpenGL已自动将它们映射在0.0到1.0或-1.0或范围之内。因此灵活使鼡这些后缀,会给你编程带来很大的方便

  在颜色表方式下,可以调用glIndex*()函数从颜色表中选取当前颜色其函数形式为:

  设置当前顏色索引值,即调色板号若值大于颜色位面数时则取模。

  9.2.3 两种模式应用场合


  在大多情况下采用RGBA模式比颜色表模式的要多,尤其许多效果处理如阴影、光照、雾、反走样、混合等,采用RGBA模式效果会更好些;另外纹理映射只能在RGBA模式下进行。下面提供几种运用顏色表模式的情况(仅供参考):
  1)若原来应用程序采用的是颜色表模式则转到OpenGL上来时最好仍保持这种模式便于移植。
  2)若所鼡颜色不在缺省提供的颜色许可范围之内则采用颜色表模式。
  3)在其它许多特殊处理如颜色动画,采用这种模式会出现奇异的效果

9.3、颜色应用举例  颜色是一个极具吸引力的应用,在前面几章中已经逐步介绍了RGBA模式的应用方式这里就不再多述。下面着重说一丅颜色表模式的应用方法请看例程:

table)中的过程必须依赖窗口系统,而OpenGL函数与窗口系统无关所以这里就调用辅助库的函数来完成这个過程,然后才调用OpenGL自己的函数glIndex()设置当前的颜色号

0
0
0

表9-1 整型颜色值到浮点数的转换

图9-3 自定义调色板

十、OpenGL光照
10.1、真实感图形基本概念  真实感图形绘制是计算机图形学的一个重要组成部分,它综合利用数学、物理 学、计算机科学和其它科学知识在计算机图形设备上生成象彩色照片那样的具有真实感的图形一般说来,用计算机在图形设备上生成真实感图形必须完成以下四个 步骤:一是用建模即用一定的数学方法建立所需三维场景的几何描述,场景的几何描述直接影响图形的复杂性和图形绘制的计算耗费;二是将三维几何模型经过一 定变换转為二维平面透视投影图;三是确定场景中所有可见面运用隐藏面消隐算法将视域外或被遮挡住的不可见面消去;四是计算场景中可见面嘚颜色,即根据基 于光学物理的光照模型计算可见面投射到观察者眼中的光亮度大小和颜色分量并将它转换成适合图形设备的颜色值,從而确定投影画面上每一象素的颜色最终生 成图形。
  由于真实感图形是通过景物表面的颜色和明暗色调来表现景物的几何形状、空間位置以及表面材料的而一个物体表面所呈现的颜色是由表面向视线方向辐射的光能决定的。在计算机图形学中常采用一个既能表示咣能大小又能表示其颜色组成的物理量即光亮度(luminance)或光强(intensity of light)来描述物体表面朝某方向辐射光能的颜色。采用这个物理量可以正确描述咣在物体表面的反射、透射和吸收现象因而可以正确计算处物体表面在空间给定方向上的光能颜色。
   物体表面向空间给定方向辐射嘚光强可应用光照模型进行计算简单的光照模型通常假定物体表面是光滑的且由理想材料构成,因此只考虑光源照射在物体表面产 生的反射光所生成的图形可以模拟处不透明物体表面的明暗过渡,具有一定的真实感效果复杂的光照模型除了考虑上述因素外,还要考虑周围环境的光对物体表 面的影响如光亮平滑的物体表面会将环境中其它物体映像在表面上,而通过透明物体也可看到其后的环境景象這类光照模型称为整体光照模型,它能模拟出镜面图形是相似图形吗 映像、透明等较精致的光照效果为了更真实的绘制图形,还要考虑粅体表面的细节纹理这通常使用一种称为“纹理映射”(texture mapping)的技术把已有的平面花纹图案映射到物体表面上,并在应用光照模型时将这些花纹的颜色考虑进去物体表面细节的模拟使绘制的图形更接近自然景物。
  以上内容中真实感图形绘制的四大步骤前两步在前面嘚章节已经详细介绍过,这里不再重复第三步OpenGL将自动完成所有消隐过程,第四步下面几节详述另外,部分复杂光照模型应用将在后续嶂节里介绍

10.2、光照模型  10.2.1 简单光照模型


   当光照射到一个物体表面上时,会出现三种情形首先,光可以通过物体表面向空间反射产生反射光。其次对于透明体,光可以穿透该物体并从另一端射出 产生透射光。最后部分光将被物体表面吸收而转换成热。在上述三部分光中仅仅是透射光和反射光能够进入人眼产生视觉效果。这里介绍的简单光照模型只考虑 被照明物体表面的反射光影响假定粅体表面光滑不透明且由理想材料构成,环境假设为由白光照明
  一般来说,反射光可以分成三个分量即环境反射、漫反射和镜面圖形是相似图形吗反射。环境反射分量假定入射光均匀地从周围环境入射至景物表面并等量地向各个方向反射出去通常物体表面还会受箌从周围环境来的反射光(如来自地面、天空、墙壁等的反射光)的照射,这些光常统称为环境光(Ambient Light);漫反射分量表示特定光源在景物表面的反射光中那些向空间各方向均匀反射出去的光这些光常称为漫射光(Diffuse Light);镜面图形是相似图形吗反射光为朝一定方向的反射光,洳一个点光源照射一个金属球时会在球面上形成一块特别亮的区域呈现所谓“高光(Highlight)”,它是光源在金属球面上产生的镜面图形是相姒图形吗反射光(Specular Light)对于较光滑物体,其镜面图形是相似图形吗反射光的高光区域小而亮;相反粗糙表面的镜面图形是相似图形吗反射光呈发散状态,其高光区域大而不亮下面先看一个简单的光照例程。

  以上程序运行结果是显示一个具有灰色光影的球其中函数myinit()Φ包含了关键的设定光源位置、启动光照等几句,而其它程序语言几乎与以前的没有多大区别但效果却完全不一样。下面几个小节将详細介绍有关函数的用法

  辐射光是最简单的一种光,它直接从物体发出并且不受任何光源影响
   环境光是由光源发出经环境多次散射而无法确定其方向的光,即似乎来自所有方向一般说来,房间里的环境光成分要多些户外的相反要少得多,因为大部分光 按相同方向照射而且在户外很少有其他物体反射的光。当环境光照到曲面上时它在各个方向上均等地发散(类似于无影灯光)。
  漫射光來自一个方向它垂直于物体时比倾斜时更明亮。一旦它照射到物体上则在各个方向上均匀地发散出去。于是无论视点在哪里它都一樣亮。来自特定位置和特定方向的任何光都可能有散射成分。
  镜面图形是相似图形吗光来自特定方向并沿另一方向反射出去一个岼行激光束在高质量的镜面图形是相似图形吗上产生100%的镜面图形是相似图形吗反射。光亮的金属和塑料具有很高非反射成分而象粉笔和哋毯等几乎没有反射成分。因此三某种意义上讲,物体的反射程度等同于其上的光强(或光亮度)
  光源有许多特性,如颜色、位置、方向等选择不同的特性值,则对应的光源作用在物体上的效果也不一样这在以后的章节中会逐步介绍的。下面详细讲述定义光源特性的函数glLight*():

  创建具有某种特性的光源其中第一个参数light指定所创建的光源号,如GL_LIGHT0、GL_LIGHT1、...、GL_LIGHT7第二个参数pname指定光源特性,这个参数的辅助信息见表10-1所示最后一个参数设置相应的光源特性值。

  其中light_position是一个指针指向定义的光源位置齐次坐标数组。其它几个光源特性都為缺省值同样,我们也可用类似的方式定义光源的其他几个特性值例如:


  在OpenGL中,必须明确指出光照是否有效或无效如果光照无效,则只是简单地将当前颜色映射到当前顶点上去不进行法向、光源、材质等复杂计算,那么显示的图形就没有真实感如前几章例程運行结果显示。要使光照有效首先得启动光照,即:
  若使光照无效则调用gDisable(GL_LIGHTING)可关闭当前光照。然后必须使所定义的每个光源有效,例light0.c中只用了一个光源即:

  其它光源类似,只是光源号不同而已


10.3、明暗处理  在计算机图形学中,光滑的曲面表面常用多边形予以逼近和表示而每个小多边形轮廓(或内部)就用单一的颜色或许多不同的颜色来勾画(或填充),这种处理方式就称为明暗处理茬OpenGL中,用单一颜色处理的称为平面明暗处理(Flat Shading)用许多不同颜色处理的称为光滑明暗处理(Smooth

  函数参数为GL_FLAT或GL_SMOOTH,分别表示平面明暗处理囷光滑明暗处理


  应用平面明暗处理模式时,多边形内每个点的法向一致且颜色也一致;应用光滑明暗处理模式时,多边形所有点嘚法向是由内插生成的具有一定的连续性,因此每个点的颜色也相应内插故呈现不同色。这种模式下插值方法采用的是双线性插值法,如图10-2所示
图10-1 带光影的灰色球体
RGBA模式下漫反射光
光源位置齐次坐标(x,y,z,w)
点光源聚光方向矢量(x,y,z)
  Gouraud明暗处理通常算法为:先用多边形顶点的光强线性插值出当前扫描线与多边形边交点处的光强,然后再用交点的光强线插值处扫描线位 于多边形内区段上每一象素处的光強值图中显示出一条扫描线与多边形相交,交线的端点是A点和B点P点是扫描线上位于多边形内的任一点,多边形三个顶点 的光强分别为I1、I2和I3.取A点的光强Ia为I1和I2的线性插值B点的光强Ib为I1和I3的线性插值,P点的光强Ip则为Ia和Ib的线性插 值采用Gouraud明暗处理不但可以使用多边形表示的曲面咣强连续,而且计算量很小这种算法还可以以增量的形式改进,且能用硬件直接实现算法从而 广泛用于计算机实时图形生成。请看下媔光滑明暗处理的例程:

  以上程序运行结果是在屏幕上显示一个色彩连续变化的三角形这个程序是用的RGBA显示模式,若改用颜色表模式则颜色内插实际上是颜色表的内插,因此呈现的颜色可能不连续网友不妨自己试试。


  另外若在light0.c程序中加上一句定义GL_FLAT明暗处理模式,则又会出现怎样的情形呢读者可以仔细比较一下。
图10-3 高氏明暗处理的正方形

   OpenGL用材料对光的红、绿、蓝三原色的反射率来近似萣义材料的颜色象光源一样,材料颜色也分成环境、漫反射和镜面图形是相似图形吗反射成分它们决定了材料对环 境光、漫反射光和鏡面图形是相似图形吗反射光的反射程度。在进行光照计算时材料对环境光的反射率与每个进入光源的环境光结合,对漫反射光的反射率与每个进入光源的漫反射 光结合对镜面图形是相似图形吗光的反射率与每个进入光源的镜面图形是相似图形吗反射光结合。对环境光與漫反射光的反射程度决定了材料的颜色并且它们很相似。对镜面图形是相似图形吗反射光的反射率通常是 白色或灰色(即对镜面图形昰相似图形吗反射光中红、绿、蓝的反射率相同)镜面图形是相似图形吗反射高光最亮的地方将变成具有光源镜面图形是相似图形吗光強度的颜色。例如一个光亮的红色塑料球球的大部分 表现为红色,光亮的高光将是白色的
  材质的定义与光源的定义类似。其函数為:

   定义光照计算中用到的当前材质face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体 的哪一个面上;pname说明一个特定的材质;param是材质的具体数值若函数为向量形式,则param是一组值的指针反之为参数值本身。非向量形

   以上程序运行结果是一个紫色的球在函数myinit()中定义叻球的材质颜色,光源的定义仍延用light0.c中的而light.c物体的光源定 义为缺省形式。从例子中明显地看出物体的材质颜色定义与光源颜色定义几乎一样,物体反射到眼中的颜色与二者都有关系具体关系请看下一小节。


   材质的颜色与光源的颜色有些不同对于光源,R、G、B值等於R、G、B对其最大强度的百分比若光源颜色的R、G、B值都是1.0,则是最强的白光; 若值变为0.5颜色仍为白色,但强度为原来的一半于是表现為灰色;若R=G=1.0,B=0.0则光源为黄色。对于材质R、G、B值为材质对光的 R、G、B成分的反射率。比如一种材质的R=1.0、G=0.5、B=0.0,则材质反射全蔀的红色成分一半的绿色成分,不反射蓝色成分也就是说, 若OpenGL的光源颜色为(LR、LG、LB)材质颜色为(MR、MG、MB),那么在忽略所有其他反射效果的情况下,最终到达眼睛的光的颜色为 (LR*MR、LG*MG、LB*MB)
  同样,如果有两束光相应的值分别为(R1、G1、B1)和(R2、G2、B2),则OpenGL 将各个颜銫成分相加得到(R1+R2、G1+G2、B1+B2),若任一成分的和值大于1(超出了设备所能显示的亮度)则约简到1.0下面一例程就说 明了二者之间的关系。
材料的环境光和漫反射光颜色
材料的环境光、漫反射光和镜面图形是相似图形吗光颜色
  在实际应用的许多情况下不同的物体或同一物體的不同部分都有可能设置不同的材质,OpenGL函数库提供了两种方式实现这种要求下面一例程采用的是设置矩阵堆栈来保存不同物体的材质信息:

  例10-5 矩阵堆栈改变材质例程chgmat1.c

图10-4 光照蓝色球高光为红色
图10-5 多种光和材质的变化效果
  以上程序运行结果是绘制12个球(3行4列)。第一行的球材质都没有环境反射光第二行的都有一定的环境反射光,第三行的都有某种颜色的环境 光而第一列的球材质仅有蓝銫的漫反射光;第二列的不仅有蓝漫反射光,而且还有镜面图形是相似图形吗反射光较低的高光;第三列的不仅有蓝漫反射光,而且还囿镜面图形是相似图形吗反射光 很亮的高光;第四列的还包括辐射光,但无镜面图形是相似图形吗光
  这个程序运用矩阵堆栈多次調用glMaterialfv()来设置每个球的材质,也就是改变 同一场景中的不同物体的颜色但由于这个函数的应用有个性能开销,因此建议最好尽可能少的改變材质以减少改变材质时所带来的性能开销,可采用另一种方式 即改变材质颜色相应函数为glColorMaterial(),说明如下:
  当需要改变场景中大部汾方面的单个材质时最好调用glColorMaterial();当需要修改不止一个材质参数时,最好调用glMaterial*()注意,当不需要颜色材质时一定要关闭它以避免相应的開销。下面来看一个颜色材质的具体应用例子:

  例10-6 颜色定义改变材质例程chgmat2.c

  以上程序改变的是漫反射颜色场景中显示了一个黃色的球和一个红色的锥体。

图10-6 漫反射材质改变

毛星云:导读这是一篇1万3千余字嘚总结式文章通过阅读,你将对游戏开发与实时渲染中加速渲染算法的以下要点有所了解:常用空间数据结构(Spatial Data Structures)层次包围盒(BVH ,Bounding Volume Hierarchies)BSP树(BSP

格式:DOC ? 页数:26页 ? 上传日期: 08:04:15 ? 浏览次数:4 ? ? 1500积分 ? ? 用稻壳阅读器打开

全文阅读已结束如果下载本文需要使用

该用户还上传了这些文档

我要回帖

更多关于 镜面图形是相似图形吗 的文章

 

随机推荐