1、计算机图形学实 验 指 导 书Ver 2.0傅由甲 卢宇 编重庆理工大学计算机科学与工程学院2008 年 10 月I目 录目 录 I1 OPENGL与三维图形 11.1 OPENGL 介绍 11.2 OPENGL 函数的语法 31.3 OPENGL 是状态机 41.4 OPENGL 相关的函数库 41.5 OPENGL 的缓冲区 42 MICROSOFT VISUAL C+ 6.0 MFC编程基础 62.1 MFC 事件驱动简介 .62.2 MFC 事件驱动编程 .62.3 在 VC 下实现 OPENGL 程序的编译 .12实验 1 WINDOWS 操作系统图形开发基础 .13一、实验要求和目
2、的 .13二、相关知识提要 .13三、实验内容及步骤 .15四、实验习题 .18实验 2 基本光栅图形生成 19一、实验要求和目的 .19二、相关知识提要 .19三、实验内容及题目 .22实验 3 图形变换 24一、实验要求和目的 .24二、相关知识提要 .24三、实验内容及步骤 .26四、实验习题 .27实验四 交互式绘图技术 .28一、实验要求和目的 .28二、实验内容及步骤 .28三、实验习题 .33实验五 光照处理 .34一、实验要求和目的 .34二、相关知识提要 .34三、实验内容及步骤 .37四、实验习题 .40II实验六 纹理映射 .41一、实验要求和目的 .41二、相关知识提要
3、 .41三、实验内容及步骤 .44四、实验习题 .45实验七 曲面生成 .46一、实验要求和目的 .46二、相关知识提要 .46三、实验内容及步骤 .49四、实验习题 .54实验八 综合实验(供优秀学生选做) .55一、实验要求和目的 .55二、实验内容 .55三、实验步骤 .5511 OpenGL与三维图形1.1 OpenGL介绍我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,必须能在三维空间描绘这些物体。最近几年计算机图形学的发展使得三维表现技术得以形成,这些三维表现技术使我们能够再现三维世界中的物体,能够用三维形体来表示复杂的信息,这种技术就是可视化(Visua
4、lization) 技术。OpenGL 已被认为是高性能图形和交互式视景处理的标准,目前包括 ATT 公司 UNIX 软件实验室、IBM 公司、DEC 公司、SUN 公司、HP 公司、Microsoft 公司和 SGI 公司在内的几家在计算机市场占领导地位的大公司都采用了 OpenGL 图形标准。值得一提的是,由于 Microsoft 公司在 Windows NT、Windows97 及后续版本中提供 OpenGL 图形标准,OpenGL 在微机中广泛应用,人们可以在微机上实现三维图形应用,如 CAD 设计、仿真模拟、三维游戏等。OpenGL 实际上是一种图形与硬件的接口。它包括了 100 多
5、个图形函数,开发者可以用这些函数来建立三维模型和进行三维实时交互。为了实现一个完整功能的图形处理系统,设计一个与 OpenGL 相关的系统结构为:其最底层是图形硬件,第二层为操作系统,第三层为窗口系统,第四层为 OpenGL,第五层为应用软件。由于许多在计算机界具有领导地位的计算机公司纷纷采用 OpenGL 作为三维图形应用程序设计界面,OpenGL 应用程序具有广泛的移植性。因此,OpenGL 已成为目前的三维图形开发标准,是从事三维图形开发工作的技术人员所必须掌握的开发工具。OpenGL 作为一个与硬件独立的图形接口,它不提供与硬件密切相关的设备操作函数,同时,它也不提供描述类似于飞机、汽
6、车、分子形状等复杂形体的图形操作函数。用户必须从点、线、面等最基本的图形单元开始构造自己的三维模型。OpenGL 提供了以下的对三维物体的绘制方式:(1) 线框绘图方式(wireframe)-这种方式仅绘制三维物体的网格轮廓线;(2) 深度优先线框绘图方式(depth_cued)-用线框方式绘图,增加模拟人眼看物体一样的效果,远处的物体比近处的物体要暗些;(3) 反走样线框绘图方式(antialiased)-用线框方式绘图,绘图时采用反走样技术以减少图形线条的参差不齐;(4) 平面消隐绘图方式(flat_shade)-对模型的隐藏面进行消隐,对模型的平面单元按光照程度进行着色但不进行光滑处理;
7、(5) 光滑消隐绘图方式(smooth_shade)-对模型进行消隐按光照渲染着色的过程中再进行光滑处理,这种方式更接近于现实;(6) 加阴影和纹理的绘图方式(shadows,textures)-在模型表面贴上纹理甚至于加上光照阴影,使得三维景观象照片一样;(7) 运动模糊的绘图方式(motion-blured)-模拟物体运动时人眼观察所感觉的动感现象;(8) 大气环境效果(atmosphere-effects)-在三维景观中加入如雾等大气环境效果,使人身临其境;(9) 深度域效果(depth-of-effects)-类似于照相机镜头效果,模型在聚焦点处清晰,反之则模糊。2整个 OpenGL
8、的基本工作流程如下图几何顶点数据显示列表评价器 逐个顶点操作和图元组装纹理映射光栅化 片元操作 帧缓冲区像素数据 像素操作图 1-1 OpenGL 基本工作流程其中几何顶点数据包括模型的顶点集、线集、多边形集,这些数据经过流程图的上部,包括运算器、逐个顶点操作等;像素数据包括像素集、影像集、位图集等,像素数据的处理方式与几何顶点数据的处理方式是不同的,但它们都经过光栅化、逐个片元(Fragment)处理直至把最后的光栅数据写入帧缓冲器。在 OpenGL 中的所有数据包括几何顶点数据和像素数据都可以被存储在显示列表中或者立即可以得到处理。OpenGL 要求把所有的几何图形单元都用顶点来描述,这样
9、运算器和逐个顶点计算操作都可以针对每个顶点进行计算和操作,然后进行光栅化形成图形片元;对于像素数据,像素操作结果被存储在纹理组装用的内存中,再象几何顶点操作一样光栅化形成图形片元。整个流程操作的最后,图形片元都要进行一系列的逐个片元操作,这样最后的像素值被送入帧缓冲器实现图形的显示。在 OpenGL 中进行主要的图形操作直至在计算机屏幕上渲染绘制出三维图形景观的基本步骤为:(1) 根据基本图形单元建立景物模型,并且对所建立的模型进行数学描述(OpenGL中把点、线、多边形、图像和位图都作为基本图形单元) ;(2) 把景物模型放在三维空间中的合适的位置,并且设置视点(viewpoint)以观察所
10、感兴趣的景观;(3) 计算模型中所有物体的色彩,其中的色彩根据应用要求来确定,同时确定光照条件、纹理粘贴方式等;(4) 把景物模型的数学描述及其色彩信息转换至计算机屏幕上的像素,这个过程也就是光栅化(rasterization)。在这些步骤的执行过程中,OpenGL 可能执行其他的一些操作,例如自动消隐处理等。另外,景物光栅化之后被送入帧缓冲器之前还可以根据需要对像素数据进行操作。OpenGL 能够对整个三维模型进行渲染着色,从而绘制出与客观世界十分类似的三维景象。另外 OpenGL 还可以进行三维交互、动作模拟等。具体的功能主要有以下这些内容。(1)模型绘制OpenGL 能够绘制点、线和多边
11、形。应用这些基本的形体,可以构造出几乎所有的三维模型。OpenGL 通常用模型的多边形的顶点来描述三维模型。(2)模型观察在建立了三维景物模型后,就需要用 OpenGL 描述如何观察所建立的三维模型。观察三维模型是通过一系列的坐标变换进行的。模型的坐标变换使观察者能够在视点位置观察与视点相适应的三维模型景观。在整个三维模型的观察过程中,投影变换的类型决定观察3三维模型的观察方式,不同的投影变换得到的三维模型的景象也是不同的。最后的视窗变换则对模型的景象进行裁剪缩放,即决定整个三维模型在屏幕上的图像。(3)颜色模式的指定OpenGL 应用了一些专门的函数来指定三维模型的颜色。程序开发者可以选择二
12、个颜色模式,即 RGBA 模式和颜色表模式。在 RGBA 模式中,颜色直接由 RGB 值来指定;在颜色表模式中,颜色值则由颜色表中的一个颜色索引值来指定。开发者还可以选择平面着色和光滑着色二种着色方式对整个三维景观进行着色。(4)光照应用用 OpenGL 绘制的三维模型必须加上光照才能更加与客观物体相似。OpenGL 提供了管理四种光(自发光、环境光、镜面光和漫反射光)的方法,另外还可以指定模型表面的反射特性。(5)图像效果增强OpenGL 提供了一系列的增强三维景观的图像效果的函数,这些函数通过反走样、混合和雾化来增强图像的效果。反走样用于改善图像中线段图形的锯齿而更平滑,混合用于处理模型的
13、半透明效果,雾使得影像从视点到远处逐渐褪色,更接近于真实。(6)位图和图像处理OpenGL 还提供了专门对位图和图像进行操作的函数。(7)纹理映射三维景物因缺少景物的具体细节而显得不够真实,为了更加逼真地表现三维景物,OpenGL 提供了纹理映射的功能。OpenGL 提供的一系列纹理映射函数使得开发者可以十分方便地把真实图像贴到景物的多边形上,从而可以在视窗内绘制逼真的三维景观。(8)实时动画为了获得平滑的动画效果,需要先在内存中生成下一幅图像,然后把已经生成的图像从内存拷贝到屏幕上,这就是 OpenGL 的双存技术(double buffer)。OpenGL 提供了双缓存技术的一系列函数。(
14、9)交互技术目前有许多图形应用需要人机交互,OpenGL 提供了方便的三维图形人机交互接口,用户可以选择修改三维景观中的物体。1.2 OpenGL函数的语法OpenGL 函数以 “gl”为前缀,并把组成函数名的每个单词的首字母进行大写(glClearColor()) 。类似地, OpenGL 还定义了以前缀 GL_开头的常量,所有单词使用大写形式,并以下划线分割(例如 GL_COLOR_BUFFER_BIT) 。此外,有些函数,同一函数有多个不同版本,如 glColor3f(),glColor3ub() ,glColor3bv() 等都用于设置当前绘图颜色,其中“3”表示函数接受 3 个参数,
15、 “f”表示参数类型为浮点数, “ub”表示参数类型为 8 位无符号整数, “bv”表示参数是含 3 个元素的数组,数组中每个元素为 8 位无符号整数。OpenGL 为同一函数定义不同参数类型的版本主要为了方便用户根据自己的数据格式向OpenGL 传递参数。表 1-1 列出用于指定数据类型的后缀字母,以供参考:后缀 数据类型 对应典型 C 语言 OpenGL 类型定义b 8 位整数 signed char GLbytes 16 位整数 short GLshort4i 32 位整数 int 或 long GLint, GLsizeif 32 位浮点数 float GLfloat, GLclamp
16、fd 64 位浮点数 double GLdouble, GLclampdub 8 位无符号整数 unsigned char GLubyte, GLbooleanus 16 位无符号整数 unsigned short GLushortui 32 位无符号整数 unsigned int 或 unsigned long GLuint, GLenum, GLbitfield1.3 OpenGL是状态机OpenGL 是个状态机。设置它的各种状态(或模式) ,则这些状态一直生效,直到它们被修改。OpenGL 所维护的状态变量很多,例如颜色,控制当前视图和投影变换,直线和多边形点画模式,多边形绘图模式,像素
17、包装约定,光照位置和特征,被绘制物体的材料属性等。许多表示模式的状态变量可以用 glEnable()和 glDisable()函数进行启用和禁用。每个状态变量(或模式)都有一个默认值。任何时候,都可以向系统查询每个状态变量的当前值。使用 6 个函数之一完成这个任务:glGetBooleanv(),glGetDoublev() ,glGetFloatv(),glGetIntegerv(),glGetPointerv() ,glIsEnabled()。所选择的具体函数取决于希望返回的结果的数据类型。有些状态变量还有更为特定的查询函数,可以查阅OpenGL 编程指南等参考书,在此不在详述。1.4 O
18、penGL相关的函数库OpenGL 提供了一组功能强大但又比较原始的渲染函数,所有高层绘图操作必须根据这些函数完成。同样,OpenGL 程序必须使用窗口系统的底层机制。有一些函数库可以用来帮助简化任务,它们是:(1) OpenGL 工具函数库(GLU)包含了一些函数,它们利用低层 OpenGL 函数来执行诸如为特定视图定向和投影设置矩阵、多边形分格化以及表面渲染等任务。所有OpenGL 实现都把这个函数库作为它的一部分。GLU 函数都使用前缀 glu。(2) 所有的窗口系统都提供一个函数库,对该窗口系统的功能进行扩展,以支持OpenGL 渲染。对于 Microsoft Windows,WGL
19、函数提供了 Windows 到 OpenGL 的接口。所有的 WGL 函数都使用前缀 wgl。(3) OpenGL 实用工具包( GLUT)是 Mark Kilgard 所编写的一个独立于窗口系统的工具包,其目的是隐藏不同窗口系统 API 的复杂性。GLUT 函数使用前缀 glut。1.5 OpenGL的缓冲区OpenGL 需要用到 4 个缓冲区进行图形显示,它们分别是:颜色缓存、深度缓存、模板缓存和累积缓存。这里我们只介绍颜色缓存和深度缓存的基本概念,更多内容请参阅OpenGL 编程指南 。1.5.1颜色缓存颜色缓存由红、绿、蓝、alpha 位等位平面(bitplane)组成的,有前缓存(f
20、ront 5buffer) 、后缓存(back buffer) 、左前(front_left )和右前( front_right)缓存、左后(back_left)和右后(back_right )缓存。左前缓存是必须的颜色缓存。前缓存是可见缓存,后缓存是不可见缓存。前后缓存技术可以实现动画操作。与颜色缓存相关的主要函数有:(1) 清除颜色缓存:glClear(GL_COLOR_BUFFER_BIT),用于清除当前显示缓冲区内容,为开始新的绘制做好准备。(2) 设置清除颜色:glClearColor(red,green,blue,alpha) ,用当前颜色(red,green,blue ,alph
21、a)清除当前显示缓冲区内容,为开始新的绘制做好准备。(3) 屏蔽颜色缓存:glColorMask(),分别设置红、绿、蓝和 alpha 的可写属性。(4) 选择颜色缓存:glDrawBuffer(),对双缓存中的一个进行选择。(5) 交换颜色缓存:swapBuffer(),交换前后缓存中的颜色,以实现动画。1.5.2 深度缓存深度缓存也叫 Z-buffer,它记录每个像素点所对应的物体点到视点的距离,由此决定表面的可见性。在进行消隐的时候,OpenGL 必须知道各物体间的相对位置关系,从而模拟出物体相互遮挡的效果,因此,需要进行深度测试。而深度测试的结果就生成了深度缓存。与深度缓存相关的 Op
22、enGL 操作主要有:(1) 清除深度缓存:glClear(GL_DEPTH_BUFFER_BIT),用于清除当前显示缓冲区内容,为开始新的绘制做好准备。(2) 设置清除值:glClearDepth(1.0) ,1.0 为最大深度。(3) 屏蔽深度缓存:glDepthMask(GL_TRUE),表示可以写深度缓存;glDepthMask(GL_FALSE),表示禁止写深度缓存。(4) 启动和关闭深度测试:glEnableGL_DEPTH_TEST),表示开启深度测试;glDisable(GL_DEPTH_TEST),表示禁止深度测试。(5) 确定测试条件:glDepthFunc(),根据函数参
23、数确定测试方式,具体的参数说明请参考实验五。(6) 确定深度范围:glDepthRange(GLclampd zNear, GLclampd zFar),参数 zNear 和 zFar分别说明视景体的前景和后景面向窗口坐标映射的规格化坐标,便于后续使用。62 Microsoft Visual C+ 6.0 MFC编程基础2.1 MFC事件驱动简介用 OpenGL 编写的程序结构类似于用其他语言编写的程序。实际上,OpenGL 是一个丰富的三维图形函数库,编写 OpenGL 程序并非难事,只需在基本 C 语言中调用这些函数,用法同 Turbo C、VC+等类似。微软基础类库(Microsoft
24、foundation class,MFC)是微软为 Windows 程序员提供的一个面向对象的 Windows 编程接口,它大大简化了 Windows 编程工作,使开发人员不必从头设计创建和管理一个标准 Windows 应用程序所需的程序,节省了时间;同时它提供了大量代码,指导用户编程时实现某些技术和功能。在事件驱动编程方面,通过 MFC 的核心消息映射机制,定义一个消息与处理函数的对照表,实现消息处理的分离编程。每当产生一个事件,便可通过这个对照表找到相应的消息处理函数,执行这个函数完成相应功能;相应的,程序员只需利用 VC 集成开发环境提供的工具指定当鼠标在哪个 GUI 对象上操作时执行哪
25、个函数即可,MFC 事件驱动编程模式如图 2.1 所示。2.1 MFC 中事件驱动编程模式为了提高交互式绘图性能,为以后二维/三维开发打下基础,考虑到 Microsoft Visual C+ 的 MFC 开发环境提供了 GDI 工具及相对较好的交互式绘图环境,所以,本书采用该环境进行二维/三维图形的实验。2.2 MFC事件驱动编程2.2.1 建立 MFC工程步骤一:打开 Microsoft Visual C+ 6.0 应用程序。在菜单中选择 “文件”“新建”打开建立用户应用程序对话框,在对话框的“工程”页面左边选择 MFC AppWizardexe;在右边“位置”编辑框中键入要建的项目存放位置
26、,例如 D 盘根目录;在右边“工程”编辑框中键入要建的项目的名称,例如 MFCTest,这时我们会看到 “位置”编辑框中信息变7为“D:MFCTest ”,表示我们的项目文件都将存放在这个目录中。如图 2.2 所示。图 2.2:建立 MFC 应用程序步骤二:我们点击“确定”按钮进行下一步设置。在“MFC AppWizard Step 1”对话框中有“S 单个文档” 、 “M 多个文档” “D 基本对话框”三个选项。 “S 单个文档”表示用户程序一次只能打开一个文档窗口;“M 多个文档”表示用户程序除了一个文档主窗口外,还可以打开若干个显示不同文档的小窗口,即子窗口;“D 基本对话框”表示用户程
27、序的界面是对话框形式的。这里我们选择“S 单个文档” ,然后,单击“下一个”按钮。如图 2.3 所示。图 2.3:MFC AppWizard Step 1步骤三:“MFC AppWizard Step 2 of 6”对话框是关于所建立的程序是否用到数据库,我们选择“否” ,然后,单击“下一个”按钮。步骤四:“MFC AppWizard Step 3 of 6”对话框是关于所建立的程序是否用到复合文档,我们选择“否” ,然后,单击“下一个”按钮。步骤五:“MFC AppWizard Step 4 of 6”对话框是关于所建立的程序的特点及是否支持打印及预览,我们选择其默认设置,单击“下一个”按钮
28、。8步骤六:“MFC AppWizard Step 5 of 6”对话框是关于所建立的程序的风格等的设置,我们选择其默认设置,单击“下一步”按钮。步骤七:“MFC AppWizard Step 6 of 6”对话框我们看到 VC 开发环境已经为我们的用户程序生成了四个类,包括它们的类名、头文件(.h)、实现文件 (.cpp)及基类。单击“完成”按钮,完成 MFC 应用程序框架的建立。如图 2.4 所示。图 2.4:MFC AppWizard Step 6 of 6完成了 MFC 应用程序框架后我们看到 MFC 用户程序开发环境,如图 2.5 所示。图 2.5:MFC 用户程序开发环境开发环境的
29、左边是项目工作区,有三页,依次为类视图(ClassView) 、资源视图(ResourceView )及文件视图( FileView) ,分别对应生成的类、项目资源及相应文件。开发环境右边文档区中则显示相应类的具体代码。92.2.2 编译和运行 MFC用户程序项目现在开发环境已为我们搭建好了框架,我们只需对其进行编译和连接就可以得到一个用户程序的框架。步骤一:在前面打开 MFCTest 项目中,选择菜单的“编译 ”(Build)“全部重建”(Rebuild All),对刚才生成的应用程序框架进行编译和连接。成功后在开发环境的输出栏里看到“MFCTest.exe - 0 error(s), 0
30、warning(s)”提示。步骤二:选择菜单的“编译”“执行 MFCTest.exe”,可看到生成的 MFC 应用程序框架。如图 2.6 所示。图 2.6:MFCTest 应用程序框架2.2.3 关闭和打开用户程序项目要关闭 MFCTest 项目,只需选择菜单的“文件”“关闭工作区 ”(Close Workspace) ;反之,要打开一个已存在的用户程序项目 选择菜单项“文件”“打开工作区” (Open Workspace) ,在弹出的文件对话框中找到要打开的项目名称,这里是D:MFCTestMFCTest.dsw。如图 2.7 所示。图 2.7:打开 MFCTest 项目102.2.4 在
31、MFC中建立新类的方法右键单击项目工作区的类视图页面的项目名称,在右键菜单中选择“New Class”,弹出如图 2.8 所示“新类(New Class ) ”对话框:图 2.8 建立新类在 Class type 中选择新建类的类型,其中“Generic Class”表示新建一般类,这也是本书实验中建类时经常用到的选项。在 Name 栏中键入类名,按照 VC 约定,新类以”C” 作为前缀,表示建立的是一个类,VC 将新建的类按头文件(*.h) 和实现文件(*.cpp)分开保存,并以去掉“C ”前缀的类名作为文件名。如果建立的类是一个派生类,则在“Bass class”栏中选择基类。最后点“OK
32、”键完成类的建立。2.2.5 在 MFC中添加类成员变量和成员函数的方法右键单击项目工作区的类视图页面中需添加成员的类名,在右键菜单中选择“Add Member Function”,添加成员函数,或者“Add Member Variable”添加成员变量,根据约定,类的成员变量名一律以”m_”为前缀,以便和临时变量或全局变量区别。2.2.6 在 MFC中添加菜单项方法步骤一:切换到项目左边工作区的资源视图页(ResourceView) ,双击“Menu”文件夹下的 IDR_MAINFRAME,则项目右边出现菜单栏。如图 2.9 所示。11图 2.9 菜单编辑界面步骤二:双击菜单栏上的预留菜单项
33、,弹出菜单项属性对话框。在其标题栏中输入菜单项标题,如“茶壶” ,在 ID 栏中给菜单项取一个 ID 号,如图 2.10 所示。如果没有取,系统自动命名该菜单项 ID,如果对自动命名的 ID 不满意(大多数情况) ,可以再次打开属性对话框,给菜单项取一个自己满意的 ID。2.10 菜单项属性对话框2.2.7 在 MFC中添加消息响应的方法按照 MFC 规定,对于窗口类,如视图类,对话框类等可以添加事件响应处理函数。方法如下:切换到项目左边工作区的类视图页(ClassView) ,鼠标右击需添加事件响应的窗口类,在弹出的下拉列表中选择“Add Windows Message Handler”,弹
34、出“New Windows Message and Event Handlers for class *”对话框,如图 2.11 所示。该对话框左边框中以“WM_”开头列出所有可供响应的事件消息,右上角框中列出项目中已作处理的响应事件消息,右下角则列出某个事件消息是哪个类或对象的。当我们要处理某个事件时,如“鼠标左键按下” ,我们在弹出的对话框中左边双击 “WM_LBUTTONDOWN”,将其添加到右边的“Existing message/Event handlers:”列表框中,如图 2.11 所示,然后选择“Add and Edit”,则 VC 会自动添加该事件的处理函数,并将界面切换到处
35、理函数位置,供程序员编写相应的处理代码。菜单栏预留菜项单122.11 消息/事件处理对话框2.3 在 VC下实现 OpenGL程序的编译OpenGL 包括*.h 库,*.lib 库和*.dll 库三部分。一般情况下, Windows 操作系统已包含OpenGL 的核心库。设 VC 安装在 C:Program Files下,则在 VC+6.0 中*.h 核心库存放在“C:Program FilesMicrosoft Visual StudioVC98IncludeGL”中;*.lib 核心库存放在“C:Program FilesMicrosoft Visual StudioVC98Lib”中;*
36、.dll 核心库存放在“C:WINDOWSsystem32”中。对于 OpenGL 的其它函数库,可放在与核心库相同的文件夹下。具有 OpenGL 所需的函数库后,在 VC+6 的“Project”菜单下,选择 “Setting”项,弹出“Project Setting”对话框,选择 “Link”项,在“Libaray”栏目中加入 OpenGL 提供的函数库:“opengl32.lib glu32.lib glaux.lib”。最后,在调用 OpenGL 函数的 C+文件中将函数所在头文件包含进来,就可以使用OpenGL 了。13实验 1 Windows 操作系统图形开发基础一、实验要求和目的
37、掌握 Windows 图形环境及图形程序开发方法;掌握 MFC 应用程序中 OpenGL 程序开发基本方法;掌握 VC+程序设计方法。二、相关知识提要1GDI 工具的使用(1)GDI 工具主要指 MFC 中各种 GDI(图形设备接口)函数,包含了可用于绘制点、线、矩形、多边形、椭圆、位图以及文本的功能函数。VC 中对其进行封装,形成 GDI 对象类,并派生出以下各类:CBitmap、CBrush、CPen 、CFont 、CPalette、CRgn 。(2)在 MFC 类库中,CPen 类封装了 GDI 的画笔工具,CBrush 类封装了 GDI 的画刷工具。在定义画笔和画刷工具时,都要调用构
38、造函数创建默认的画笔(黑色,实线,宽度为一个像素)和画刷(将封闭图形内部填充为白色) 。绘图时使用画笔和画刷步骤如下: 创建 CPen 类对象或 CBrush 类对象; 调用合适的成员函数初始化画笔或画刷; 将画笔或画刷对象选入当前设备文本对象,并保存原先的画笔或画刷对象; 调用绘图函数绘制图形; 将原先的画笔或画刷对象选入设备文本对象,以便恢复原来状态。(3)颜色的数据类型是COLORREF,表示RGB值是一个 32位整数,由RGB(红,绿,蓝)的形式指定,每个分量值从0到255,0最低,255最高。3种颜色分量结合起来产生实际颜色。指定RGB值可以用手工(如0x00FF0000是纯蓝),也
39、可以用宏 RGB()指定,如RGB(255, 0, 0)为红色。(4)GDI 定义画笔风格与含义如表S1.1:表S1.1 画笔风格与含义画笔风格 含义 画笔风格 含义PS_DASH 划线,即虚线 PS_INSIDEFRAME 在边界区域内实线PS_DASHDOT 点划线 PS_NULL 空画笔PS_DASHDOTDOT 双点划线 PS_SOLID 实线PS_DOT 点线14(5)CBrush 的成员函数 CreateSolidBrush 用颜色来初始化填充画刷,函数原型如下:BOOL CreateSolidBrush(COLORREF crColor);此外,还可调用成员函数 CreateHa
40、tchBrush 用某种影线来初始化填充画刷。函数原型为:BOOL CreateHatchBrush(int nIndex, COLORREF crColor);其中参数 nIndex 用于指定影线模式,其值如表 S1.2,crColor 用于指定画刷颜色。表 S1.2 画刷影线模式及含义阴影模式 含义 阴影模式 含义HS_BDIAGONAL 反斜线 HS_FDIAGONAL 斜线HS_CROSS 十字线 HS_HORIZONAL 水平线HS_DIAGCROSS 斜十字线 HS_VERTICAL 竖线(6)除了使用定制的画笔和画刷外,MFC 中也库存了一部分绘图工具,使用时只需调用 CDC 成
41、员函数 SelectStockObject 即可,函数原型是:virtual CGdiObject *SelectStockObject(int nIndex);如果调用成功,返回指向 CGdiObject 对象的指针(实际指向的对象是 CPen 或 CBrush对象) ,否则返回 NULL。nIndex 是所要选入的库存对象,对于画笔和画刷,值如表 S1.3。表 S1.3 GDI 库存对象含义宏代码 库存对象 宏代码 库存对象BLACK_BRUSH 黑色画刷 NULL_BRUSH 空画刷(内部不填充)DKGRAY_BRUSH 深灰色画刷 WHITE_BRUSH 白色画刷GRAY_BRUSH
42、灰色画刷 BLACK_PEN 黑色画笔HOLLOW_BRUSH 透明窗口画刷 NULL_PEN 空画笔(什么也不画)LTGRAY_BRUSH 浅灰色画刷 WHITE_PEN 白色画笔2Windows 下开发 OpenGL程序的基本方法(1)在 MFC 单文档应用程序中,视图类用来显示图形,需要修改该类的成员函数代码实现 OpenGL 绘图,主要过程如下: 改造 OnCreate 函数开发 OpenGL 绘图程序时,需要设置像素格式。像素格式告诉 OpenGL 绘制风格、颜色模式、颜色位数和深度位数等重要信息。Windows 平台下 OpenGL 提供了专门函数进行处理。可以在 OnCreate
43、 函数中定义像素格式,并创建一个 OpenGL 操作所必须的绘图上下文RC(rendering context) 。使用 PIXELFORMATDESCRIPTOR 结构指定像素格式,使用wglCreateContext()函数创建绘图上下文 RC。 改造 OnSize 函数当视图发生变化时,应及时将新的客户区尺寸通知 OpenGL,才能够正确在窗口客户区域显示三维场景的二维影像,通过命令 glViewport 完成该工作。 改造 OnDestroy 函数在 OnDestory 成员中用 wglMakeCurrent()和 wglDeleteContext()断开 OnCreate 成员中RC
44、 与设备描述表 DC 的连接,并释放 RC 所占资源。 改造 OnDraw 函数在 OnDraw 函数完成每次屏幕的绘制。15(2)在每次绘制场景前,先要清除 OpenGL 显示缓存中的信息,以免影响绘图效果。用 glClearColor 设置屏幕背景颜色;用 glClear 清除显示缓存。这两个函数为:void glClearColor(red, green, blue,alpha); /背景的 RGBA 信息void glClear(mask); /清除标志缓冲区mask 参数如表 S1.4 所示:表 S1.4 OpenGL 缓冲区代码及含义缓冲区 名称 缓冲区 名称颜色缓冲区 GL_CO
45、LOR_BUFFER_BIT 累加缓冲区 GL_ACCUM_BUFFER_BIT深度缓冲区 GL_DEPTH_BUFFER_BIT 模板缓冲区 GL_STENCIL_BUFFER_BIT三、实验内容及步骤1创建 My2D项目和 My3D项目建立两个单文档 MFC 项目,一个为 My2D,另一个为 My3D。My2D 项目用于二维GDI 绘图; My3D 项目用于三维 OpenGL 绘图。2用 GDI工具绘制不同颜色、线型和线宽的直线在 My2D 项目中 在 CMy2DView 类中添加 DrawLine 函数如下:void CMy2DView:DrawLine(CDC *pDC, CPoint
46、 startPoint, CPoint endPoint, COLORREF color, int width, unsigned short type/*画笔风格*/)CPen *pOldPen;CPen newPen; /创建一个新画笔newPen.CreatePen(type, width, color); /设置画笔属性并初始化画笔pOldPen = pDC-SelectObject( /将新画笔选进当前设备,并保存原画笔pDC-MoveTo(startPoint.x, startPoint.y); /将画笔移到直线起点pDC-LineTo(endPoint.x, endPoint.y
47、); /将画笔移到直线终点,实现绘制pDC-SelectObject(pOldPen); /将原画笔选进当前设备,恢复原来状态 在 CMy2DView 类中的 OnDraw 函数中调用 DrawLine 函数(粗体为添加部分),画一条 从(300, 200)到 (600, 100),宽度为 2,颜色为红色的虚线。void CMy2DView:OnDraw(CDC* pDC)CMy2DDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);DrawLine(pDC, CPoint(300,200), CPoint(600, 100), RGB(255, 0, 0
48、), 2, PS_DASH);163用 GDI工具绘制不同颜色的填充矩形 在 CMy2DView 类中添加 DrawSolidRectangle 函数如下:void CMy2DView:DrawSolidRectangle(CDC *pDC, int left, int top, int right, int down, COLORREF filledcolor)CBrush* pOldBrush = NULL;CBrush SolidBrush;SolidBrush.CreateSolidBrush(filledcolor); /设置画刷颜色,并初始化一个实画刷pOldBrush = (CB
49、rush*)pDC-SelectObject(pDC-Rectangle(left, top, right, down);/绘制矩形,参数分别为左上角点及右下角点x,y坐标pDC-SelectObject(pOldBrush); 在 CMy2DView 类中的 OnDraw 函数中调用 DrawSolidRectangle 函数(粗体为添加部分),绘制从左上角(10, 20)到右下角(300, 500) ,颜色为绿色的矩形。void CMy2DView:OnDraw(CDC* pDC)CMy2DDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);DrawSolidRectangle(pDC