基于OpenGL的三维动画课件的设计与制作
2014-08-11张三川
张三川
(陕西广播电视大学 图书馆,陕西 西安 710119)
【远程教育】
基于OpenGL的三维动画课件的设计与制作
张三川
(陕西广播电视大学 图书馆,陕西 西安 710119)
在对OpenGL的工作原理和工作方式进行分析的基础上,以3D太阳系模型课件为例,探索基于OpenGL技术的三维动画课件的设计和制作技术,较好地解决了3D模型的2D渲染、物体的转动以及转动轨迹、3D模型的远近视角等问题。
OpenGL;三维动画;渲染;光照;纹理映射;透视矩阵;课件
引言
三维动画能够逼真地模拟现实环境,创造常规拍摄所无法实现的场景和事件,出色展现从微观世界到宏观世界,从真实空间到想象空间的各种景象,使人产生视觉冲击,给人以身临其境、耳目一新之感。三维动画被广泛应用于教育、科研、医学、军事、娱乐等诸多领域。在教育上,动画可以激活学习兴趣,实现对抽象和复杂概念的深层理解,深受师生的喜爱,因此在课件中广泛应用。
OpenGL是SGI公司开发的一套高性能的图形处理库,它是图形硬件的软件界面,是程序员管理这些图形硬件的桥梁。OpenGL处理图形具有高实时性、大计算量的特点。通过OpenGL可以创建交互式的应用程序,实现具有逼真效果的三维图形。OpenGL已被认为是高性能图形和交互式视景处理的标准,目前包括ATT公司UNIX软件实验室、IBM公司、DEC公司、SUN公司、HP公司、Microsoft公司和SGI公司在内的几家在计算机市场占领导地位的大公司,都采用了OpenGL图形标准。包括微软在内的许多著名公司提供的编译平台,如Visual C++6.0、C++ Builder、VB等开发工具,都将OpenGL作为一个重要的模块扩展进来,从而大大增强了这些编译平台的图形处理能力。
本文以3D太阳系模型课件为例,在Visual C++6.0使用OpenGL技术,探索三维动画课件的设计和制作方法,尝试解决3D模型的2D渲染、物体的转动以及转动轨迹、3D模型的远近视角等问题。
一、 OpenGL软件
(一)OpenGL简介
OpenGL是一个高性能的图形开发软件包,约有120个函数,分别包含在标准库(OpenGL.lib)、实用库(glu.lib)和辅助库(glaux.lib)中。开发者可以利用这些函数来构造景物模型、进行三维图形交互软件的开发。OpenGL是作为一种新型的接口来设计的,其与硬件无关的特性使它可以在不同的硬件平台上实现。为了实现这一跨平台性能,OpenGL没有设置执行窗口任务或获取用户输入的命令,程序员必须通过所使用的窗口系统来控制正在使用的特定硬件。作为底层的平台,OpenGL也不提供具体三维物体模型的高级命令, OpenGL的程序员必须用一系列的点、线、面来组合成自己想要的模型。虽然有着像微软的direx这些产品的竞争,但OpenGL 仍然在不断发展进步中。在渲染质量上,OpenGL作为三维图形设计领域的工业标准,在图象渲染方面有很大优势,常常使用在对图象要求较高的领域。而Direx由于计算速度快,则更多的应用于游戏制作。OpenGL被设计成独立于硬件、独立于窗口系统,能够运行在各种操作系统的各种计算机上,以及客户/服务器模式。它低端应用上的主要竞争对手是MS-Direct三维,该图形库是以COM接口形式提供的,所以较为复杂,稳定性差,另外微软公司拥有该库版权,目前只在Windows平台上可用。
(二)OpenGL工作流程
OpenGL的基本工作流程见图1。
图1 OpenGL基本工作流程
处理由左侧开始,首先根据基本图形单元建立景物模型,并且对所建立的模型进行数学描述(OpenGL 把点、线、多边形、图像和位图都作为基本图形单元)。数据可以通过流程立即执行这些命令;或者组织到一个“显示列表”后再执行它们。“各顶点操作及图元集” 阶段主要是处理OpenGL 的几何图元——点、线段和多边形。“光栅化”生成了一系列的帧缓冲区地址和相应的用于描述点、线段或多边形的二维值。在这些步骤的执行过程中, OpenGL 可能执行其他的一些操作,例如自动消隐处理等。另外,景物光栅化之后被送入帧缓冲器之前还可以根据需要对象素数据进行操作[1]。
二、 基于OpenGL的三维动画课件的实现技术
(一)基本要求及技术难点
课件要求在Visual C++6.0的平台下,用OpenGL函数库完成太阳系静态和动态模型的建立。要求用pageUp/Down来控制远近视角,用上,下,左,右键来控制视角的上下左右移动,用L键来控制太阳光源的启用和关闭。要求模型应能在一定程度上反映太阳系中各个天体的大小、位置,以及运动速度的关系。
在课件设计中,存在以下技术难点:球体的建立,大小、位置的确定;环的建立,大小、位置的确定;星空背景的建立;球体、环等物体的渲染;球体、环等物体的运动;光源的建立和物体受光照的材料属性的定义;Windows操作系统下消息的捕捉和处理。
(二)解决方案
1.球体的建立,大小、位置的确定
球体的建立函数有两类,一类是OpenGL辅助库中的函数auxWireSphere(Gldouble radius)和auxSolideSphere(Gldouble radius);另一类是OpenGL实用库中的函数gluShpere(GLUquadricObj *qobj,Gldouble radius,Glint slices,Glint stacks)。这里选后者。
gluShpere函数在以当前坐标原点为球心,半径为radius,经线纬线条数分别为slices 和stacks绘制一个球体。如果纹理运算被打开,则按照特定算法将纹理贴图绘制在球体上。
gluShpere函数中的GLUquadricObj型的二次曲面对象由函数GLUquadricObj* gluNewQuadric(void )函数创建。该函数返回创建对象的指针。如果返回的是NUL,则说明内存不足。创建的二次曲面使用完后,要用void gluDeletQuadric(GLUquadricObj* obj)函数将它删除。
2.环的建立及其大小、位置的确定
环可以通过OpenGL实用库中的gluPartialDisk(GLUquadricObj * qobj,GLdouble innerRadius,GLdouble outerRadius,GLint slices,GLint loops,GLdouble startAngle,GLdouble sweepAngle)函数实现。这个函数返回一个部分圆片(可以是扇型,圆环或者这两者的结合),这个部分圆片圆心位于当前坐标原点,圆片位于z=0平面内。qobj是二次曲面对象。innerRadius和outerRadius分别确定这个部分圆的内半径和外半径,在这两个参数下,圆被切割成环(特殊地,当内半径为0时,这个圆环就是一个整圆)。slices为这个圆的边数(因为实际上,OpenGL中的每一条曲线,每一个曲面都是由多条直线,多个平面相连接而近似的,而这里slices和前述球体的经线slices和纬线stacks正是由程序员来定义近似的程度的)。startAngle和sweepAngle是用来将圆切割成扇型,这两个参数确定了扇型的起始角度和终止角度。如果纹理映射运算被激活,则会按照特定算法来将贴图覆盖在这个部分圆上。由于本设计中用到此函数是为了绘制行星的光环和小行星带,是环型而不是扇型,因此最后两个参数分别设置为0和360。
3.星空背景的建立
作为整个浩瀚宇宙的一部分,太阳系位于无数天体之中。因此这个太阳系模型必须要在无数星星的背景下建立。这个背景应在所有太阳系星体之后,而不能挡在某个星体或者某些星体之前。解决这样的方法将用到深度缓存。深度缓存中的深度测试将把所有位于视点更近的物体显示出来,而更远的被挡住的物体将不显示出来,这符合人们的视觉习惯。
如果要利用深度缓存作为解决方法,需要将背景绘制得比所有的星体更远。而在这里,遇到另一个问题,那就是如果将背景设置的足够远而满足深度测试,就会因为太远而看不清楚作为背景的图片中的内容,而只是非常模糊的一片,甚至于根本看不见背景(因为距离视点太远的缘故)。
解决方法是:既然深度测试是根据深度缓存来进行的,而深度缓存又叫做z缓存,它是记录现有画面中每一个象素的距离视点的距离的。我们可以在视点不远处绘制背景。这时,深度缓存记录的是这个作为背景的图象中每个象素距视点的距离。在绘制其他图形时,可以人为的将深度缓存清空,而不去清空屏幕的内容。这时,深度缓存每个象素点的距离被改为“无限远”,他们将位于所有后绘制的图形之后。而这样的背景不会再因为太远而看不清或看不见。
背景绘制即是绘制一个大的矩形,由纹理映射贴上具有星空背景的位图。绘制矩形的一组函数如下:
glBegin(GL_QUADS);
glTexCoord2f(0.0f,0.0f); glVertex3f(-20.0f,-20.0f,-10.0f);
glTexCoord2f(2.0f,0.0f); glVertex3f(20.0f,-20.0f,-10.0f);
glTexCoord2f(2.0f,2.0f); glVertex3f(20.0f,20.0f,-10.0f);
glTexCoord2f(0.0f,2.0f); glVertex3f(-20.0f,20.0f,-10.0f);
glEnd();
glBegin和glEnd之间是OpenGL绘制以点确定形状的图形的方式,所有能以点来确定其形状的简单图形都绘制在这两个函数中。glBegin所带参数用于通知OpenGL想要绘制什么形状的图形(如线段、三角形、矩形、相连的线段群、三角形群等等)。glVertex*( GLType x,GLType y,GLType z,GLType w)用于通知OpenGL这些点所在的坐标。x/y/z/w这些参数的个数是2,3或者4。用来指定点所在的坐标。定义顶点的颜色,法向量和纹理映射时要和这个函数一起调用。如果开启了纹理运算,则可以用glTexCoord*()来控制这个图形上的纹理贴图。
4.球体、环等物的渲染
渲染是图形编程中不可或缺的一步。如果没有了渲染这一步,所有绘制出来的图形将枯燥和呆板,人们见到的仅仅是一个个单一颜色的堆放,失去了真实感。
纹理映射对不同的OpenGL对象有不同的影射方式。在这里仅针对须用到的影射方式加以解释。对于由顶点确定的图形,在确定其顶点时确定其纹理坐标,由glTexCoord*()来指定。对于实用库中的二次曲面函数,由于它是由实用库对标准库函数调用而产生的函数,由实用库对其纹理影射方式进行了规定,不再需要程序员自己指定影射方式。于是只需要提供纹理映射所需位图,把纹理影射交给OpenGL实用库完成。
在纹理映射之前需要将作为纹理的位图读入内存,再调用gluBuild2Dmipmaps(GLenum target,GLint components,GLint width,GLint height,GLenum format,GLenum type,const void * data)生成需要的纹理,激活纹理运算glEnable(GL_TEXTURE_2D)。这时就可以在需要的地方贴图了。
5.球体、环等物体的运动[2]
由于各个天体的运动规律大致相同,只是圆周运动的线速度,角速度以及自转角速度不同,即是参数不同。这里以地球的绘制为例:
glRotatef(angleEarthRevolution,0.0f,0.0f,1.0f);
glTranslatef(radiusEarthRevolution,0.0f,0.0f);
glRotatef(-angleEarthRevolution,0.0f,0.0f,1.0f);
glPushMatrix();
glRotatef(angleEarth,0.0f,0.0f,1.0f);
GLUquadricObj *earth;
(3)呼吸道护理:护理人员应密切关注患儿呼吸,因患儿气管细弱,在帮助患儿吸痰时,应使用直径较小,材质柔软的吸管,动作应放轻柔,不可过重,同时,应注意调整负压,保持用时在15s之内,以免损害粘膜,防止出现呼吸暂停的现象。
glBindTexture(GL_TEXTURE_2D,texture[3]);
earth=gluNewQuadric();
gluQuadricNormals(earth,GLU_SMOOTH);
gluQuadricTexture(earth,GL_TRUE);
gluQuadricOrientation(earth,GLU_OUTSIDE);
gluQuadricDrawStyle(earth,GLU_FILL);
gluSphere(earth,radiusEarth,25,25);
gluDeleteQuadric(earth);
最后,计算下一时刻各个天体的运动参数,然后在下一次程序调用此函数时作为各个天体的转动参数。
6.光源的建立和物体受光照的材料属性的定义
光照是太阳系中一个重要的部分,以太阳为中心的点光源是太阳系的唯一光源。光照的结果是各个星球不是漆黑一片,也有了诸如日月食等自然现象。
以太阳为中心的点光源向四周放射漫射光,其他各个星球正对太阳的一面因光照而明亮,背对太阳的一面因无光照而黑暗。光照的建立很简单,但要注意以下几点:①点光源位于太阳内部,也即太阳实际上是背面(内部)受光照,而正面(外部)背对着光源。在激活光照的情况下,太阳的正面(外部)因为背对着光源而暗淡。这并不是我们想要的结果,我们希望太阳的外部明亮。解决的方法是,设立太阳的光照材质,让太阳表面发光;②在激活光照的情况下,星空背景将因为处于“无穷远”而受不到光照而显得暗淡。解决的方法和上面一样:设置星空的光照材质为自己发光;③小行星带和某些行星的光环因为所在面平行于光源光线而接受不到光源发出的光,因而也是暗淡无光。而实际上,小行星带能接受太阳的光照的。为了模拟真实情况,也用上面的方法来解决这个问题。
OpenGL中的光照分为两种:一种是位于无穷远处的平行光(用来模拟地球上受太阳光照是的情形,或者光源足够远时物体受光照的情形);另一种是上面提到的点光源。光由坐标系中某一点向四周放射,不同远近的物体,甚至物体的不同部位都会反射不同的光照强度。
有了光照,还需要定义每个物体的光照材质。比如我们总不希望看到一个光滑的银色金属球和一本书对于同一个光源返回的是同样的光。于是还需要定义光源发出的光中漫射光,镜面反射光,环境光的强度和成分。用这些参数和物体的材质中对应环境颜色,散射颜色,镜面反射颜色参数作相应的运算来决定最终物体的反射光。
建立光源将用glLight*( GLenum light,GLenum pname,TYPE param) 函数。定义物体的光照材质将用glMaterial*( Glenum face,Glenum pname,TYPE param)函数,它用于定义光照计算的当前材料属性。材质的环境颜色,散射颜色和镜面反射颜色分别与光源的环境颜色,散射颜色和镜面反射运算得到物体最终表现出来的颜色。
三、 结束语
本文采用OpenGL软件包开发工具,在Visual C++ MFC环境下完成了3D太阳系模型课件的设计和制作。课件的运行情况见图2.
图2 课件运行截图
[1]李保杰,马明栋. OpenG实现三维可视化工作流程[J].四川理工学院学报(自然科学版),2005,18(3):54-58.
[2]刘琪.基于OpenGL的三维景观动态仿真[J].武汉工程大学学报,2011,33(7):108-110.
[责任编辑 王爱萍]
2014-04-06
张三川(1956— ), 西安市人,陕西广播电视大学图书馆高级工程师。
G436
A
1008-4649(2014)02-0031-05