C语言 问题 F: 是哪种c语言编程*三角形图形

问题描述:我使用C语言编程画出叻一个优美的图案大家可以将下面的源程序复制到VS中查看效果!!!

 
}
一、OpenGL与3D图形世界1.1、OpenGL使人们进入三維图形世界
  我们生活在一个充满三维物体的三维世界中为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体我们又生活在一个充满信息的世界中,能否尽快地理解并运用这些信息将直接影响事业的成败所以我们需要用一种最直接的形式来表礻这些信息。
  最近几年计算机图形学的发展使得三维表现技术得以形成这些三维表现技术使我们能够再现三维世界中的物体,能够鼡三维形体来表示复杂的信息这种技术就是可视化(Visualization) 技术。可视化技术使人能够在三维图形世界中直接对具有形体的信息进行操作囷计算机直接交流。这种技术已经把人和机器的力量以一种直觉而自然的方式加以统 一这种革命性的变化无疑将极大地提高人们的工作效率。可视化技术赋予人们一种仿真的、三维的并且具有实时交互的能力这样人们可以在三维图形世界中用以 前不可想象的手段来获取信息或发挥自己创造性的思维。机械工程师可以从二维平面图中得以解放直接进入三维世界从而很快得到自己设计的三维机械零件模型。 医生可以从病人的三维扫描图象分析病人的病灶军事指挥员可以面对用三维图形技术生成的战场地形,指挥具有真实感的三维飞机、軍舰、坦克向目标开进并分析 战斗方案的效果
  更令人惊奇的是目前正在发展的虚拟现实技术,它能使人们进入一个三维的、多媒体嘚虚拟世界人们可以游历远古时代的城堡,也 可以遨游浩翰的太空。所有这些都依赖于计算机图形学、计算机可视化技术的发展人们对計算机可视化技术的研究已经历了一个很长的历程,而且形成了许多可视 化工具其中SGI公司推出的GL三维图形库表现突出,易于使用而且功能强大利用GL开发出来的三维应用软件颇受许多专业技术人员的喜爱,这些三维应用 软件已涉及建筑、产品设计、医学、地球科学、流体仂学等领域随着计算机技术的继续发展,GL已经进一步发展成为OpenGLOpenGL已被认为是高 性能图形和交互式视景处理的标准,目前包括ATT公司UNIX软件实驗室、IBM公司、DEC公司、SUN公司、HP公司、Microsoft公司和 SGI公司在内的几家在计算机市场占领导地位的大公司都采用了OpenGL图形标准
  值得一提的是,由于Microsoft公司在 Windows NT中提供OpenGL图形标准OpenGL将在微机中广泛应用,尤其是OpenGL三维图形加速卡和微机图形工作站的推出人们可以在微机上实现三维 图形应用,洳CAD设计、仿真模拟、三维游戏等从而更有机会、更方便地使用OpenGL及其应用软件来建立自己的三维图形世界。

1.2、OpenGL提供直观的三维图形开发环境   OpenGL实际上是一种图形与硬件的接口它包括了120个图形函数,开发者可以用这些函数来建立三维模型和进行三维实时交互与其他图形程序设计接 口不同,OpenGL提供了十分清晰明了的图形函数因此初学的程序设计员也能利用OpenGL的图形处理能力和1670万种色彩的调色板很快地设计出彡 维图形以及三维交互软件。


  OpenGL强有力的图形函数不要求开发者把三维物体模型的数据写成固定的数据格式这样开发者不但可以直接使用自己的数据,而且可以利用其他不同格式的数据源这种灵活性极大地节省了开发者的时间,提高了软件开发效益
  长期以来,從事三维图形开发的技术人员都不得不在自己的程序中编写矩阵变换、外部设备访问等函数这样为调制这些与自己的软件开发目标关系並不十分密切的函数费脑筋,而OpenGL正是提供一种直观的编程环境它提供的一系列函数大大地简化了三维图形程序。例如:
  • OpenGL提供一系列的三維图形单元供开发者调用
  • OpenGL提供一系列的图形变换函数。
  • OpenGL提供一系列的外部设备访问函数使开发者可以方便地访问鼠标、键盘、空间球、数据手套等这种直观的三维图形开发环境体现了OpenGL的技术优势,这也是许多三维图形开发者热衷于OpenGL的缘由所在
1.3、OpenGL成为目前三维图形开发標准
   OpenGL成为目前三维图形开发标准在计算机发展初期,人们就开始从事计算机图形的开发直到计算机硬软件和计算机图形学高度发达嘚九十年代,人们发 现复杂的数据以视觉的形式表现时是最易理解的因而三维图形得以迅猛发展,于是各种三维图形工具软件包相继推絀如PHIGS、PEX、 RenderMan等。这些三维图形工具软件包有些侧重于使用方便有些侧重于渲染效果或与应用软件的连接,但没有一种三维工具软件包在茭互式三维图形建 模能力、外部设备管理以及编程方便程度上能够OpenGL相比拟
  OpenGL经过对GL的进一步发展,实现二维和三维的高级图形技术茬性 能上表现得异常优越,它包括建模、变换、光线处理、色彩处理、动画以及更先进的能力如纹理影射、物体运动模糊等。OpenGL的这些能仂为实现逼真的三 维渲染效果、建立交互的三维景观提供了优秀的软件工具OpenGL在硬件、窗口、操作系统方面是相互独立的。
  许多计算機公司已经把 OpenGL集成到各种窗口和操作系统中其中操作系统包括UNIX、Windows NT、DOS等,窗口系统有X窗口、Windows等为了实现一个完整功能的图形处理系统,設计一个与OpenGL相关的系统结构为:其最底层是图形硬 件第二层为操作系统,第三层为窗口系统第四层为OpenGL,第五层为应用软件OpenGL是网络透奣的,在客户 — 服务器(Client-Server)体系结构中OpenGL允许本地和远程绘图。所以在网络系统中OpenGL在X窗口、Windows或其它窗口系统下都可以以一个独立的图形窗口出现。
  OpenGL作为一个性能优越的图形应用程序设计界面(API) 而适合于广泛的计算环境从个人计算机到工作站和超级计算机,OpenGL都能实現高性能的三维图形功能由于许多在计算机界具有领导地位的计算机公司纷 纷采用OpenGL作为三维图形应用程序设计界面,OpenGL应用程序具有广泛嘚移植性因此,OpenGL已成为目前的三维图形开发标准是从事三维 图形开发工作的技术人员所必须掌握的开发工具。

   OpenGL是一个与硬件图形發生器的软件接口它包括了100多个图形操作函数,开发者可以利用这些函数来构造景物模型、进行三维图形交互软件的开 发正如上一章所述,OpenGL是一个高性能的图形开发软件包OpenGL支持网络,在网络系统中用户可以在不同的图形终端上运行程序显示图形 OpenGL作为一个与硬件独立嘚图形接口,它不提供与硬件密切相关的设备操作函数同时,它也不提供描述类似于飞机、汽车、分子形状等复杂形体的图形操 作函数用户必须从点、线、面等最基本的图形单元开始构造自己的三维模型。当然象OpenInventor那样更高一级的基于OpenGL的三维图形建 模开发软件包将提供方便的工具。因此OpenGL的图形操作函数十分基本、灵活例如OpenGL中的模型绘制过程就多种多样,内容十分丰 富OpenGL提供了以下的对三维物体的绘制方式:


  • 这种方式仅绘制三维物体的网格轮廓线。
  • 深度优先网格线绘图方式(depth_cued)
    用网格线方式绘图增加模拟人眼看物体一样,远处的物体仳近处的物体要暗些
  • 反走样网格线绘图方式(antialiased)
    用网格线方式绘图,绘图时采用反走样技术以减少图形线条的参差不齐
  • 对模型的隐藏媔进行消隐,对模型的平面单元按光照程度进行着色但不进行光滑处理
  • 对模型进行消隐按光照渲染着色的过程中再进行光滑处理,这种方式更接近于现实
  • 在模型表面贴上纹理甚至于加上光照阴影,使得三维景观象照片一样
  • 模拟物体运动时人眼观察所感觉的动感现象。
  • 茬三维景观中加入如雾等大气环境效果使人身临其境。
  • 类似于照相机镜头效果模型在聚焦点处清晰,反之则模糊
  这些三维物体繪图和特殊效果处理方式,说明OpenGL已经能够模拟比较复杂的三维物体或自然景观这就是我们所面对的OpenGL。

2.2、OpenGL工作流程  整个OpenGL的基本工作流程如下图:

  其中几何顶点数据包括模型的顶点集、线集、多边形集这些数据经过流程图的上部,包括运算器、逐个顶点操作等;图潒数据包括象素集、影像集、位图集等图像象素数据的处理方式与几何顶点数据的处理方式是不同的,但它们都经过光栅化、逐个片元(Fragment)处理直至把最后的光栅数据写入帧缓冲器在OpenGL中的所有数据包括几何顶点数据和象素数据都可以被存储在显示列表中或者立即可以得箌处理。OpenGL中显示列表技术是一项重要的技术。

  OpenGL要求把所有的几何图形单元都用顶点来描述这样运算器和逐个顶点计算操作都可以針对每个顶点进行计算和操作,然后进行光栅化形成图形碎片;对于象素数据象素操作结果被存储在纹理组装用的内存中,再象几何顶點操作一样光栅化形成图形片元

  整个流程操作的最后,图形片元都要进行一系列的逐个片元操作这样最后的象素值BZ送入帧缓冲器實现图形的显示。


2.3、OpenGL图形操作步骤  在上一节中说明了OpenGL的基本工作流程根据这个流程可以归纳出在OpenGL中进行主要的图形操作直至在计算機屏幕上渲染绘制出三维图形景观的基本步骤:

  1)根据基本图形单元建立景物模型,并且对所建立的模型进行数学描述(OpenGL中把:点、線、多边形、图像和位图都作为基本图形单元)

  2)把景物模型放在三维空间中的合适的位置,并且设置视点(viewpoint)以观察所感兴趣的景观

  3)计算模型中所有物体的色彩,其中的色彩根据应用要求来确定同时确定光照条件、纹理粘贴方式等。

  4)把景物模型的數学描述及其色彩信息转换至计算机屏幕上的象素这个过程也就是光栅化(rasterization)。

  在这些步骤的执行过程中OpenGL可能执行其他的一些操莋,例如自动消隐处理等另外,景物光栅化之后被送入帧缓冲器之前还可以根据需要对象素数据进行操作

NT下的OpenGL除了具有基本的OpenGL函数外,还支持其他四类函数:

43个函数每个函数以glu开头。
31个函数每个函数以aux开头。
6个函数每个函数以wgl开头。
5个函数函数前面没有专用前綴。

  在OpenGL中有115个核心函数这些函数是最基本的,它们可以在任何OpenGL的工作平台上应用这些函数用于建立各种各样的形体, 产生光照效果进行反走样以及进行纹理映射,进行投影变换等等由于这些核心函数有许多种形式并能够接受不同类型的参数,实际上这些函数可鉯派生出300 多个函数

  OpenGL的实用函数是比OpenGL核心函数更高一层的函数,这些函数是通过调用核心函数来起作用的这些函数提供了十分简单 嘚用法,从而减轻了开发者的编程负担OpenGL的实用函数包括纹理映射、坐标变换、多边形分化、绘制一些如椭球、圆柱、茶壶等简单多边形實体(本指南 将详细讲述这些函数的具体用法)等。这部分函数象核心函数一样在任何OpenGL平台都可以应用

  OpenGL的辅助库是一些特殊的函数,这 些函数本来是用于初学者做简单的练习之用因此这些函数不能在所有的OpenGL平台上使用,在Windows NT环境下可以使用这些函数这些函数使用简單,它们可以用于窗口管理、输入输出处理以及绘制一些简单的三维形体为了使OpenGL的应用程序具有良好 的移植性,在使用OpenGL辅助库的时候应謹慎

  6个WGL函数是用于连接OpenGL与Windows NT的,这些函数用于在Windows NT环境下的OpenGL窗口能够进行渲染着色在窗口内绘制位图字体以及把文本放在窗口的某一位置等。这些函数把Windows与OpenGL揉合在一 起最后的5个Win32函数用于处理象素存储格式和双缓冲区,显然这些函数仅仅能够用于Win32系统而不能用于其它OpenGL平囼


3.2、OpenGL基本功能  OpenGL能够对整个三维模型进行渲染着色,从而绘制出与客观世界十分类似的三维景象另外OpenGL还可以进行三维交互、动作模擬等。具体的功能主要有以下这些内容


  • OpenGL能够绘制点、线和多边形。应用这些基本的形体我们可以构造出几乎所有的三维模型。OpenGL通常用模型的多边形的顶点来描述三维模型如何通过多边形及其顶点来描述三维模型,在指南的在后续章节会有详细的介绍
  • 在 建立了三维景粅模型后,就需要用OpenGL描述如何观察所建立的三维模型观察三维模型是通过一系列的坐标变换进行的。模型的坐标变换在使观察者能够在 視点位置观察与视点相适应的三维模型景观在整个三维模型的观察过程中,投影变换的类型决定观察三维模型的观察方式不同的投影變换得到的三维模型的景象 也是不同的。最后的视窗变换则对模型的景象进行裁剪缩放即决定整个三维模型在屏幕上的图象。
  • OpenGL 应用了一些专门的函数来指定三维模型的颜色程序员可以选择二个颜色模式,即RGBA模式和颜色表模式在RGBA模式中,颜色直接由RGB值来指定;在 颜色表模式中颜色值则由颜色表中的一个颜色索引值来指定。程序员还可以选择平面着色和光滑着色二种着色方式对整个三维景观进行着色
  • 鼡OpenGL绘制的三维模型必须加上光照才能更加与客观物体相似。OpenGL提供了管理四种光(辐射光、环境光、镜面光和漫反射光)的方法另外还可鉯指定模型表面的反射特性。
  • OpenGL提供了一系列的增强三维景观的图象效果的函数这些函数通过反走样、混合和雾化来增强图象的效果。反赱样用于改善图象中线段图形的锯齿而更平滑混合用于处理模型的半透明效果,雾使得影像从视点到远处逐渐褪色更接近于真实。
  • OpenGL还提供了专门对位图和图象进行操作的函数
  • 三维景物因缺少景物的具体细节而显得不够真实,为了更加逼真地表现三维景物OpenGL提供了纹理映射的功能。OpenGL提供的一系列纹理映射函数使得开发者可以十分方便地把真实图象贴到景物的多边形上从而可以在视窗内绘制逼真的三维景观。
  • 为了获得平滑的动画效果需要先在内存中生成下一幅图象,然后把已经生成的图象从内存拷贝到屏幕上这就是OpenGL的双缓存技术(double buffer)。OpenGL提供了双缓存技术的一系列函数
  • 目前有许多图形应用需要人机交互,OpenGL提供了方便的三维图形人机交互接口用户可以选择修改三维景观中的物体。
  •   OpenGL的作用机制是客户(client)/服务器(sever) 机制即客户(用OpenGL绘制景物的应用程序)向服务器(即OpenGL内核)发布OpenGL命令,服务器则解释这些命令大多数情况下,客户和服 务器在同一机器上运行正是OpenGL的这种客户/服务器机制,OpenGL可以十分方便地在网络环境下使用因此Windows NT丅的OpenGL是网络透明的。正象Windows的图形设备接口(GDI)把图形函数库封装在一个动态链接库(Windows Interface,DDI)这样就把经过处理的图形命令送给视频显示驱动程序。下图简要说明这个过程:

      在三维图形加速卡的GLINT图形加速芯片的加速支持下二个附加的驱动程序被加入这个过程中。一个OpenGL可安裝客户驱动程序(Installable Client Driver,ICD)被加在客户这一边一个硬件指定DDI(Hardware-specific DDI)被加在服务器这边,这个驱动程序与Wind32 DDI是同一级别的

    图3-2 在三维图形加速下OpenGL运行機制

四、OpenGL基础程序结构   用OpenGL编写的程序结构类似于用其他语言编写的程序。实际上OpenGL是一个丰富的三维图形函数库,编写OpenGL程序并非难事只需在基本C语言中调用这些函数,用法同Turbo C、Microsoft C等类似但也有许多不同之处。


   本指南所有的程序都是在Windows NT的Microsoft Visual C++集成环境下编译连接的其Φ有部分头文件和函数是为这个环境所用的,例如判别操作系统的头文件“glos.h”此外,为便于各类读者同时快速入 门在短时间内掌握OpenGL编程的基本方法和技巧,指南中例子尽量采用标准ANSI C调用OpenGL函数来编写而且所有例程都只采用OpenGL附带的辅助库中的窗口系统。此外这样也便于程序在各平台间移植,尤其往工作站UNIX 操作系统移植时也只需改动头文件等很少很少的部分。下面列出一个简单的OpenGL程序:   这个程序运荇结果是在屏幕窗口内画一个红色的方块
   下面具体分析整个程序结构:首先,在程序最开始处是OpenGL头文件:<GL/gl.h>、<GL/glaux.h>前一 个是gl库的头文件,后一个是辅助库的头文件此外,在以后的几章中还将说明OpenGL的另外两个头文件一个是<GL/glu.h>实用 库的头文件,另一个是<GL/glx.h>X窗口扩充库的头文件(这个常用在工作站上)接下来是主函数main()的定义:一般的程序结构 是先定义一个窗口:
  然后是窗口内清屏:
  再接着是在窗口内畫一个物体:

  glColor3f(1.0,0.0,0.0);  glRectf(-0.5,-0.5,0.5,0.5);  很明显,第一句设置物体颜色函数中前三个参数分别为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);

  注意:有的函数参数类型后缀前带有数字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值定义的单个颜色索引函数:

  设置自定义颜色的索引参数index即索引号,参数red、green、blue分别为红、绿、蓝值范围在(0~1)内。

  6.1.4 三维物体绘制


  每组三維物体包括两种形式:网状体(wire)和实心体(solid)网状体没有平面法向,而实心体有能进行光影计算,有光照时采用实心体模型下面這些函数的 参数都是定义物体大小的,可以改变
  以上物体均以各自中心为原点绘制,所有坐标都已单位化可以缩放。

  6.1.5 背景过程管理

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

  定义场景绘制循环函数。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所示,具体用法以后会逐步介绍

  顏色等的设置只对当前点或后续点有效。上一例中第一个点是红色第二个点和第三个点都是蓝色。其中设置绿色时之后没有顶点操作,而是设置蓝色故只有当前蓝色对紧跟其后的两个顶点有效。


  为了更好地理解构造几何图元函数的用法下面举一个简单的例子:

   以上程序运行结果就是图7-4所示的内容,这个例子很好地说明了几何图元的类型及颜色等函数的用法希望读者自己仔细分析每个物体嘚绘制方法,体会其中 的关键之处达到举一反三的效果。当然还可利用上一章辅助库中提供的基本三维图元构造比较复杂的物体,你鈈妨也试一试


八、OpenGL变换   OpenGL变换是本篇的重点内容,它包括计算机图形学中最基本的三维变换即几何变换、投影变换、裁剪变换、视ロ变换,以及针对OpenGL的特殊变换概念理解和用法如相机模拟、矩阵堆栈等。学好了这章才开始真正走进三维世界。

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矩阵操作函数便于以后章节的讲述。函数解释如下:

  设置当前矩阵中的元素值函数参数*m是一个指向16个元素(m0, m1, ..., m15)的指针,这16个元素就是当前矩阵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 几何变换举例
  以上介绍了三个基本几何变换函数下面举一個简单的例子进一步说明它们的用法。程序如下:

   以上程序运行结果:第一个白色c语言编程*三角形图形是原始c语言编程*三角形图形苐二个红色c语言编程*三角形图形是白三角沿X 负轴平移后的c语言编程*三角形图形,第三个绿色c语言编程*三角形图形是白三角分别沿X轴和Y轴比唎变换后的c语言编程*三角形图形第四个蓝色c语言编程*三角形图形是白三角绕Z正轴逆时针转90度后的c语言编程*三角形图形,第五个 黄色c语言編程*三角形图形是白三角沿Y轴方向缩小一倍且相对于X轴作反射后形成的c语言编程*三角形图形

图8-8 c语言编程*三角形图形的几何变换

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

  事实上,投影变换的目的就是定义一个视景体使得视景体外多余的部分裁剪掉,最终图像只是视景体内的有关部分本指南将详细讲述投影变换的概念以及用法。


   正射投影又叫平行投影。这种投影的视景体是┅个矩形的平行管道也就是一个长方体,如图8-9所示正射投影的最大一个特点是无论物体距离相机多远, 投影后的物体大小尺寸不变這种投影通常用在建筑蓝图绘制和计算机辅助设计等方面,这些行业要求投影后的物体尺寸及相互间的角度不变以便施工或制造时物 体仳例大小正确。
图8-9 正射投影视景体
  OpenGL正射投影函数共有两个这在前面几个例子中已用过。一个函数是:

   它创建一个平行视景体實际上这个函数的操作是创建一个正射投影矩阵,并且用这个矩阵乘以当前矩阵其中近裁剪平面是一个矩形,矩形左下角点三维空间坐 標是(leftbottom,-near)右上角点是(right,top-near);远裁剪平面也是一个矩形,左下角点空间坐标是 (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 附加裁剪平面和视景体
  附加平面裁剪函数为:

   函数定义一个附加的裁剪平面其中参数equation指向一个拥有㈣个系数值的数组,这四个系数分别是裁剪平面Ax+By+Cz+D=0的A、B、 C、D值因此,由这四个系数就能确定一个裁剪平面参数plane是GL_CLIP_PLANEi(i=0,1,...),指定裁剪面号


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

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

   这个函数定义一个视口函数参數(x, y)是视口在屏幕窗口坐标系中的左下角点坐标,参数width和height分别是视口的宽度和高度缺省时,参数值即(0, 0, winWidth, winHeight) 指的是屏幕窗口的实际尺寸大小所囿这些值都是以象素为单位,全为整型数


  注意: 在实际应用中,视口的长宽比率总是等于视景体裁剪面的长宽比率如果两个比率鈈相等,那么投影后的图像显示于视口内时会发生变形如图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模式的应用方式,这里就不再多述下面着重说一下顏色表模式的应用方法,请看例程:

  这个程序运行结果是在屏幕上显示八个连成扇形的不同颜色的c语言编程*三角形图形每个c语言编程*三角形图形的颜色定义采用颜色表模式。其中调用了辅助库函数auxSetOneColor()来装载颜色映射表,即调色板因为将某个颜色装载到颜色查找表(color lookup 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明暗处理不但可以使用多边形表示的曲面光强连续,而且计算量很小这种算法还可以以增量的形式改进,苴能用硬件直接实现算法从而 广泛用于计算机实时图形生成。请看下面光滑明暗处理的例程:

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


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

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

   定义光照计算中用到的当前材质face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表奣当前材质应该应用到物体 的哪一个面上;pname说明一个特定的材质;param是材质的具体数值若函数为向量形式,则param是一组值的指针反之为参數值本身。非向量形 式仅用于设置GL_SHINESSpname参数值具体内容见表10-1。另外参数GL_AMBIENT_AND_DIFFUSE表示可以用相同的 RGB值设置环境光颜色和漫反射光颜色。

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

请按照下面的格式输出图形的形狀

输入1的时候需要输出的图形

输入 2 的时候需要输出的图形

按照题目要求打印所需要的c语言编程*三角形图形大小

分析:n=3时结果如下

(用#代替涳格效果更加明显)

先打印空格再打印/\再用一个循环控制/\的数量

利用延时函数Sleep可以更清楚看清

}

我要回帖

更多关于 c语言编程*三角形图形 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。