基于OpenGL的鱼雷弹道显示研究与实现*
2010-08-11姚旺生
杨 涛 姚旺生
(海军工程大学 武汉 430033)
1 引言
随着系统仿真理论方法和应用技术研究的深入,以及计算机硬件技术和软件技术的发展,虚拟仿真技术在军事领域得到了快速发展。在鱼雷武器的研制生产中,应用虚拟仿真技术可以缩短设计制造周期,降低了设计制造成本,提高了产品质量。以往鱼雷武器系统的战术性能考核和评定,主要是通过湖海实验确定,但由于复杂的水下环境和各种因素的干扰(例如海流、风浪、温度、杂质(泥、沙)等),对整个系统的现场实验会造成相应的影响;另外湖海实验的经费、时间以及其它客观条件的制约,使得进行现场实验的次数有限,很难得到真实、全面、可靠的实验数据。因此,在实验室内建立虚拟仿真系统,成为鱼雷武器系统设计、实验、评估的重要手段。而鱼雷弹道显示系统的实现,综合了计算机图形、虚拟现实和多媒体等技术,创建了仿真对象的3D模型和虚拟环境效果,构造了具有逼真的3D视景仿真,使弹道以形象、直观的形式表现在研究者面前,方便了他们对鱼雷弹道分析与研究。
鱼雷弹道显示系统采用Visual C++6.0+3DSMax+OpenGL,模拟鱼雷在水中主要场景,设计了鱼雷运动状态的弹道显示系统,并在计算机上成功地完成了鱼雷运动的视景仿真。其中,Visual C++6.0作为开发平台;3DSMax用来建立系统模型,输出通用的 3ds文件格式,供程序使用;OpenGL命令则提供图形软件和硬件之间的接口,调用OpenGL子程序,生成绘图命令和数据,然后交付硬件执行。
2 基于OpenGL的三维模型
本文场景中的模型全部采用3DSMax软件来建立,并在其提供的界面下建立生成3ds格式的模型文件,最终转化成OpenGL程序实现对模型的控制。这样做的优点是既可以避免在OpenGL程序中用较低级的命令来建立三维立体模型的繁重劳动,又可以通过OpenGL程序实现对模型的交互控制,且构建的模型能体现更多的细节。
本文主要采用网格建模为主,结合基本几何体建模和布尔运算等方法来构建该型鱼雷模型。下面以某型鱼雷为例简单介绍建模过程。主体部分考虑用放样建模,放样的原理是定义一条路径和多个截面,然后按一定的方式将截面放置到路径上,同时可以对截面和路径作任意的修改,例如旋转,缩放,修改几何形状等。另外可以用两个与 shape正交的视图来约束物体的外形,即适配技术。该模型图如图1所示。
图1 某型鱼雷建模
3 鱼雷弹道显示系统的分析与设计
3.1 系统功能
在鱼雷弹道显示系统中,需要以三维动画的方式显示鱼雷的运行轨迹及空间姿态,并且提供对图形显示过程进行控制的手段,主要包括如下功能:
1)建立模型库。实现模型与相关属性的绑定,并实现模型的移动、旋转、放大、缩小等功能,对不同型号的鱼雷模型进行管理。
2)实现全景模式、漫游模式和跟踪模式三种观察模式,使用户可以从不同角度、不同位置观看场景,为用户评估鱼雷性能提供参考。
3)建立一个逼真的虚拟水下海洋环境,包括对海底地形及海水的模拟。
4)在不影响显示速度的条件下,尽可能模拟鱼雷运行过程中各种效果,生成动态的运行特效(如音响渲染、爆炸效果等)。
3.2 系统结构
系统总体功能结构如图2所示,主要由三个子模块来实现。
图2 系统功能结构图
◦鱼雷/环境子模块:主要包括鱼雷模型的构建和海底环境的生成,用户可以根据实际需求输入建立鱼雷三维实体模型以及周围环境模型(如天空、水下、海底等)。
◦数据通讯子模块:分为网络接口和数值仿真两部分,主要作用是把鱼雷运动数据传递给鱼雷弹道显示部分。鱼雷运动数据可来自测试系统的数值仿真,也可来自其他系统的弹道仿真计算机。其中,数值仿真部分:对鱼雷进行动力学仿真,产生鱼雷运动弹道参数。用户可设置仿真参数(如仿真算法、仿真步长以及仿真类型)和仿真对象(如鱼雷选择或设置、仿真弹道段选择以及起止条件设置)。网络接口部分:采用TCP/IP协议与网络连接。
◦声音子模块:用以实现鱼雷视景仿真的声音效果。用户可设置声音效果的有无,音量的大小等。
3.3 系统实现
3.3.1 OpenGL绘图环境初始化
为了能够使用OpenGL命令,首先需要在预编译头文件StdAfx.h中导入OpenGL库头文件,这样预编译头文件才能提供对OpenGL库和用户库的支持。还必须在Project菜单下的Settings项中对Link选项卡内链接以下库:glu32.lib、opengl32.lib 、glaux.lib。
3.3.2 建立OpenGL应用程序框架
使用VC++6.0的MFC AppWizard按照软件所需界面要求定制出相应的程序框架后,再使用Class Wizard修改所生成的视类,就可以建立Window s下OpenGL应用程序框架。
1)在PreCreateWindow方法中设置窗口类型为具有WS_CLIPSIBLINGS和WS_CLIPCH IL-DREN风格的窗口,保证成功地设置像素格式。
2)改写View类的Create,按自己的要求注册View类,使其具有CSDWNDC风格,为View类的整个生命期保留一个唯一的设备描述表。每次使用OpenGL函数时都要将OpenGL的图形操作描述表和一个Windows设备描述表联起来。为了消除额外的开销,可以只作一次关联。为此要为视窗口类建立一个自己的设备描述表。
3)在OnCreate()中,重新设置像素格式,创建图形操作描述表,并使它成为当前图形操作描述表。
4)可在View的初始更新OnInitialUpdate方法中完成绘图场景的初始化,如设置消除背景色、光源属性、材料属性、深度测试方式和最初的场景变换等。
5)在OnSize中,完成对窗口大小变化的响应。必须重新定义视口大小和投影变换矩阵,以使图形不因窗口的变化而变形。
6)在OnDraw中要完成场景的重新绘制,绘制完场景之后,加入下面一条语句:SwapBuffers(wglGetCurrentDC())。SwapBuffers()是Win32API提供的一个用于OpenGL的函数。当OpenGL使用DoubleBuffers以支持动画显示时,需要使用该函数将在BackBuffer上绘制的场景交换到FrontBuffer中显示。SwapBuffers()需要与图形操作描述表相联的设备描述表句柄作为参数,而函数wglGetCurrentDC()恰好提供了与当前使用的图形操作描述表相联的设备描述表句柄。
7)在程序退出时应该清空当前使用的图形操作描述表,并删除所创建的图形操作描述表。
3.3.3 鱼雷模型的读入
系统使用模型3DSMax建立鱼雷模型,输出为通用的3ds文件格式。3DS文件由许多块组成,每个块首先描述其信息类别,即该块是如何组成的。块的信息类别用ID来标识,块还包含了下一块的相对位置信息。物体的层次结构并不复杂,场景中给予每个物体一个数字以标识其在场景树中的顺序。3DS文件中也使用相同的方法标识了物体在场景树中的位置。作为根物体给予了数字-1(FFFF)作为其数字标识。当读取文件的时候,就会得到一系列的物体数字标识。如果当前数字标识比前一个大,那么当前物体是前一个物体的子物体;反之,当数字标识比前一个数字标识小,则又回到上一层结构,如图3所示。
图3 3DS文件结构
本系统中模型读入函数很多,主要用于读取不同的内容,如下所示:
int ReadKFTrackTag(long fileSize,long tagStart,long tag-Size,FILE *fp,char*nodeName,tVector*pivot,Chunk3DS chunk);
int ReadKFObjectNode(long fileSize,long nodeStart,long nodeSize,FILE*fp);
int ReadKFDATA(long fileSize,long kfdataStart,long kfdataSize,FILE*fp);
int Read3DSChunk(FILE*fp,Chunk3DS&chunk);
int ReadPercentage(FILE*fp,float&value);
int ReadColor(FILE*fp,float&red,float&green,float&blue);
int ReadPointArray(CTriObject*newchild,long fileSize,FILE*fp);
int ReadFaceArray(CTriObject*newchild,long unsigned fileSize,FILE*fp);
int ReadMeshMatGroup(CTriObject*newchild,Material-Dict*matdict,long fileSize,FILE*fp);
int ReadTriObject(MaterialDict*matdict,long fileSize,FILE*fp,long triStart,long triSize,char*group-Name);
int ReadNamedObject(MaterialDict*matdict,long file-Size,long namedStart,long namedSize,FILE*fp);
int ReadMatEntry(MaterialDict*matdict,long fileSize,long matStart,long matSize,FILE*fp);
int ReadMDATA(M aterialDict*matdict,long fileSize,long mdataStart,long mdataSize,FILE*fp);
int Read3DSFile(long fileSize,long fileStart,long fileLen,FILE*fp);
int Is3DSFile(FILE*fp);
BOOL Reader(char*filename,CTriList*_list);
3.3.4 视点的设置
为了实现在不同的位置对鱼雷弹道进行观测,在本系统中定义了8个摄像机,切换不同的摄像机可以实现不同角度的观测,并且在系统中添加了按键响应函数,按不同的键可以切换到不同的视点。下面以第一台摄像机的使用为例,具体函数如下:
第一步:初始化函数。
int InitGL(GLvoid)//视点模式
{camera[0].x=0;
camera[0].y=0;
camera[0].z=0;
camera[0].type=CAM_A;}
第二步:视点设置函数。
void Camera(void)
{switch(var.cameratype)
{case CAM_A:
var.xcam=var.xmis+4;
var.ycam=var.ymis+3;
var.zcam=var.zmis+15;
gluLookAt(var.xcam,var.ycam,var.zcam,var.xmis,var.ymis,var.zmis,0.0f,1.0f,0.0f);
break;}
3.3.5 光照处理
绘制好模型后,必须进行光照处理,有了光照后物体才真正表现为三维物体。因此,必须创建光源、选择光源模式、定义材料属性,以得到理想中的三维模型。
GLfloat light_position[]={1.0,1.0,1.0,0.0};
glLightfv(GL_LIGHTO,GL_POSITION,light_position);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHTO);
4 仿真结果
本仿真系统是在Visual C++6.0平台上,通过OpenGL图形库函数来实现可视化仿真。与内测数据通信,在某型鱼雷弹道数据和姿态数据的驱动下,在显示屏上模拟出了鱼雷启动、运行、加速等场景,画面连续,逼真,可变视点观察。图4为鱼雷内测系统得到的运行状态。
图4 鱼雷水下正常航行场景
5 结语
本系统可移植性强,不仅自带鱼雷动力学仿真计算功能,而且能通过数据通讯子模块接受来自其他系统或网络接口传递来的数据,通过更换不同的对象模型就可模拟不同型号的鱼雷或者其他水下航行体可视化过程,具有一定的推广价值。下一步工作主要是完成与鱼雷陆上仿真实验系统的连接测试,另外还需对水下复杂环境的建模仿真、海面波浪的渲染和鱼雷模型的纹理映射等方面进一步的修改加强,使可视化过程更加真实、可靠。
[1]Dave Shreiner,MasonWoo,Jackie Neider,et al.OpenGL Programming Guide(Sixth Edition)[M].北京:人民邮电出版社,2007
[2]Kruglinski D J.Visual C++技术内幕(第四版)[M].潘爱民,译.北京:清华大学出版社,1999
[3]Richard S.Wright.Jr.Michael Sweet.OpenGL超级宝典[M].北京:人民邮电出版社,2000
[4]Edward Ange.OpenGL编程基础(第三版)[M].段菲,译.北京:清华大学出版社,2008
[5]李颖,薛海斌,朱伯立,等.OpenGL函数与范例解析手册[M].北京:国防工业出版社,2002
[6]陈玉军,张琦.基于MFC的OpenGL仿真与3D模型的获取[J].中国制造业信息化,2005(4):103~105
[7]张宇文.鱼雷弹道与弹道设计[M].西安:西北工业大学出版社,1999,9
[8]康凤举.现代仿真技术与应用[M].北京:国防工业出版社,2003,9