祝新霞,马明栋
(1.南京邮电大学 通信与信息工程学院,江苏 南京 210003; 2.南京邮电大学 地理与生物信息学院,江苏 南京 210023)
现如今,虚拟现实已渗透到人们生活的方方面面[1]。它被认为是一种先进的科学技术,相较于传统的人机界面以及流行的视窗操作。人们采用一种全新的方式,即通过计算机对复杂数据进行可视化操作与交互,极大地促进了虚拟现实技术的发展[2],广泛应用于科学计算可视化、城市规划、建筑设计、广告宣传、医疗、场景仿真等领域[3]。场景漫游是虚拟现实的一个重要应用部分,具有人机实时交互特性,可以在虚拟场景中自由行走,不受时间和空间的限制,实现真正意义上的交互,给人以身临其境的感觉。
文中采用OpenSceneGraph三维图形引擎实现了一个虚拟校园场景漫游系统,同时研究了漫游过程中的碰撞检测技术。该系统的实现和设计充分体现了OSG在主流三维仿真平台的优势和潜力,其开源、面向对象的优点,可以加快开发过程,提高渲染效率。
OSG具有支持大规模场景的分页、粒子系统与阴影、多线程、多显示的渲染,以及支持各种文件格式等特性[4]。OSG是一个高性能的开源的跨平台的图形开发三维引擎,诸如飞行器仿真、虚拟现实、科学计算可视化等高性能图形应用程序的开发,就是利用OSG设计实现的[5]。OSG结合Visual C++开发,其基于场景图的概念,为图形程序的开发提供场景管理和渲染优化功能,同时OSG是一个基于OpenGL函数库的面向对象框架,促使开发者从实现和优化底层图形的调用功能的实现中解放出来,为快速开发图形应用程序提供了许多附加的实用工具。
(1)开源。
OSG跟目前市面上一些商业化的三维图形引擎不同,它的所有源码都是遵循OSGPL开源协议开发,基于OSG的程序和软件的使用与发布无需额外费用。
(2)源码质量高。
基于OSG的开源特点,它的源码历经了无数优秀开发人员的测试和修改,其程序架构和执行效率都有较好的提升。
(3)跨平台操作。
OSG支持的操作平台包括Windows、UNIX、Linux、MacOSX、IRIX、Solaris等多种操作系统,可以跨平台操作,具有较强的可移植性。
(4)可扩展性强。
OSG提升了强大的可扩展能力,其支持节点扩展、属性渲染、回调和交互事件,并支持第三方插件。
OSG核心库(core library)是OSG存在的基础,核心场景数据库和操作场景图形的组织和管理都是由OSG核心库完成的,并且为导入外部数据库提供接口[6]。OSG核心库主要由以下五个库构成:
osg库:作为最基本数据库,提供基本场景图形构建场景图节点类、几何体类,用作向量和矩阵运算类。
osgUtil库:又叫工具库,提供了通用的公用类,用于场景图及内容操作,统计和优化场景图形数据,以及渲染器的创建。
osgDB库:读写数据库,也是一个文件工具类,提供场景中读写数据的工作。通过遍历场景图层次结构以完成数据处理工作,实现场景图管理。
osgViewer库:管理视窗库,提供场景中视口及可视化内容的管理,有利于OSG与各种GUI结合。
osgGA库:用于改写界面事件。
场景图是用于游戏和计算机图形学等软件的数据结构设计方法,即在抽象的场景中绘制元素组织结构、相互关系[7]。实际上大规模管理场景图形通常使用树结构或图结构组成一组节点集。当前大多数渲染引擎组织其空间数据集皆采用自顶向下且分层的树状结构,以提高渲染效率。例如渲染场景中包含一辆卡车和一条路况顺畅的马路,由于场景图的节点不代表几何关系,可申请一个节点用来表示移动,如图1所示。
图1 场景图
根节点一般处于场景图结构的顶部,由根节点延伸至各组节点,各自的几何信息以及用来控制其外观的渲染状态信息均包含在组节点中。这些节点皆可没有或含有多个子成员。场景图的底端展示了组成场景中各个叶节点的物体实际信息。图2表示典型的场景图树型结构的组织方式。
图2 典型场景图树型结构
整个三维场景结构可以由根节点表示,物体状态切换、矩阵变换、细节层次等属性信息可由根节点延伸的组节点表示;管理属性信息的开关节点(osg::Switch)、变换节点(osg::Transform)、细节层次节点(osg::LOD)等是由组节点派生出来的;叶子节点(osg::Geode)反映场景空间结构和对象状态,数据节点之间共有行为和属性一般通过叶子节点提取[8]。
场景图形结构是建在底层API函数之上的,它为3D程序提供了所需的空间数据组织能力及其他特性。OSG程序层次结构如图3所示。
图3 典型OSG程序结构层次模型
三维场景处于漫游系统中时被认为是静止的。在实际设计时,使用相机从场景的不同位置和不同角度去观察,然后把相机从不同位置和不同角度拍摄到的“场景”输出到屏幕,就完成了虚拟场景漫游效果[9]。三维图像显示过程如图4所示。
图4 三维图像显示流程
人们通常是通过眼睛来观察事物的,当视点发生移动时,周围的景物相对于视点在做反向移动,该过程反应到大脑,在大脑中形成场景漫游效果。漫游功能实现在于漫游器的选择。在OpenSceneGraph中,既可用默认漫游器,也可使用自定义的漫游器。
Viewer是场景的核心管理器,即漫游器。在漫游过程中必须根据响应事件的类osgGA::GUIEventHandler来响应操作。Viewer通过实时修正场景相机(Camera类)的观察矩阵(代表观察者位置和姿态的矩阵)方法来实现平滑的场景浏览效果[10],因此自定义漫游器就是设置相机观察矩阵的过程。osgGA::CameraManipulator类由osgGA::GUIEventHandler类派生而来,Viewer可以通过设置矩阵的公共接口和响应得到有效控制。一般的场景操作如图5所示。
图5 一般的场景操作
矩阵为OSG提供了一个通用模型。在OSG中,不仅所有视图矩阵操作是通过矩阵完成,而且不同相机间的交互也是通过矩阵完成[11]。OSG osgGA::CameraManipulator的派生类用来实现OSG的相机操作功能,而控制相机的关键是实现osgGA::CameraManipulator类的4个纯虚函数:
将水热预处理后的微藻生物质离心15 min,离心机转速为 5 000 r·min-1(RCF=5 000×g),取离心后的固体物质用于DSC的实验分析。
virtual voidsetByMatrix(const osg::Matrixd & matrix){} /*设置相机的观察矩阵*/
virtual voidsetByInverseMatrix(const osg::Matrixd& matrix){} /*设置相机的视图矩阵*/
virtualosg::Matrixd getMatrix() const {} /*获取相机的观察矩阵*/
virtualosg::Matrixd getInverseMatrix() const{}/*获取相机的视图矩阵*/
调用getMatrix来获得SetByMatrix函数所需的矩阵,实现向下一个照相机传递矩阵。当从一个相机切换到另一个相机时调用setByMatrix函数,将上一个相机的视图矩阵传过来,据此设置相机的初始位置。
getInverseMatrix是变换矩阵的逆矩阵,它会在更新遍历中被场景相机调用,返回当前的视图矩阵。利用这个方法对时间进行处理,可以改变场景状态,进而在调用getInverseMatrix矩阵时,改变场景内相机的位置情况[12]。这个函数在void Viewer::updateTraversal()中被调用。
_camera->setViewMatrix(_cameraManipulator->getInverseMatrix());
另外,handle作为主要控制器函数也是必须的。
virtualbool handle(const osgGA::GUIEvent Adapter & ea,osgGA::GUIActionAdapter& us);
handle方法含有两个参数,分别是GUI事件的提供者和对GUI进行反馈,可以让GUIEventHandler根据输入事件操作GUI。若要对事件进行处理,可由GUIEventHandler继承得到自己的类,然后将handle方法覆盖,在继承的类中对事件进行处理。osgProducer::Viewer类维护一个GUIEventHandler队列,在该队列里事件依次传递,handle函数返回值决定此事件是否继续让GUIEventHandler处理,若返回true,停止事件处理;否则GUIEventHandler继续对该事件进行处理[13]。图6为实现方向键控制相机视口的效果图。
碰撞问题是由用户的交互和物体的运动产生的。实时检测物体的碰撞并计算出相应的碰撞反应,更新显示结果来避免发生与现实情景不符的穿透现象[14]。
图6 方向键控制相机视口的效果图
处理碰撞检测的方法有两种:一是求交器检测法,二是包围盒检测法。求交器检测法是将遍历器绑上求交器,以实现整个场景的求交过程。常用的有直线求交器和多边形求交器。因为直线求交器只检测直线与多边形的碰撞事件,故多用于判断鼠标点击事件。该系统要实现既定功能,应使用多边形求交器。设置初始值时需同时设置被检测的多边形,若此多边形每帧发生变化,则每帧都需重新设定多边形求交器的参数,就是polytope类型变量,以指定多边形网格。这一过程消耗时间较长,又因其默认位置为坐标原点,所以需要获取真实的世界坐标。
OSG中包围盒检测方法也有两种,分别是用getBound()函数返回的球形包围盒和用getBoundingBox()函数返回的立方体包围盒。getBoundingBox()的函数唯独Drawable节点含有,但所有Node节点却皆含getBound()函数,故MatrixTransform节点的getBound()函数包含位置旋转信息。因为MatrixTransform节点挂载实体节点,所以只能使用球体包围盒方法。但球体包围盒的缺点是范围不准确,因此得到的数据可能比实际物体稍微大一点儿。
该系统采用直线求交器检测方法。osg::LineSegment为线段类,表示一个起点和终点构成一条线段,如:osg::ref_ptr
在虚拟场景中,加快显示画面的速度可通过有效管理和组织虚拟场景,提高场景漫游效率来实现。OSG可以非常简单方便地对虚拟场景进行管理和漫游,是目前技术较先进和性能较好的虚拟现实开发包。文中通过实践场景漫游的过程,验证了OSG对虚拟场景的漫游原理和发生碰撞时的检测方法,为以后在工程实践的应用提供了重要的参考依据。
图7 碰撞检测前后效果图
参考文献:
[1] 王 锐,钱学雷.OpenSceneGraph三维渲染引擎设计与实践[M].北京:清华大学出版社,2009.
[2] 肖 鹏.OpenSceneGraph三维渲染引擎编程指南[M].北京:清华大学出版社,2010.
[3] MARTZ P.OpenSceneGraph快速入门指导[M].王 锐,钱学雷,译.北京:清华大学出版社,2006.
[4] 杨石兴,曹明亮.Step Into OpenSceneGraph[M].郑州:郑州大学虚拟实现实验室,2014.
[5] 徐 凌.基于OpenSceneGraph引擎的漫游系统的研究与实现[D].武汉:武汉理工大学,2008.
[6] 温转萍,申闫春.基于OSG的虚拟校园漫游系统的设计与实现[J].计算机技术与发展,2009,19(1):217-220.
[7] SHREINER D,WOO M,NEIDER J,et al.OpenGL编程指南[M].邓郑详,译.第4版.北京:人民邮电出版社,2005.
[8] 申闫春,朱幼虹,曹 莉,等.基于OSG的三维仿真平台的设计与实现[J].计算机仿真,2007,24(6):207-211.
[9] 张艳丽,谭同德,赵新灿,等.基于OSG的虚拟化学实验平台的构建设计[J].计算机工程与设计,2010,31(12):2909-2913.
[10] 杨 晓,廉静静,张新宇.基于OSG的虚拟场景中包围盒碰撞检测的研究[J].计算机技术与发展,2011,21(9):32-34.
[11] YUAN P,WANG S,ZHANG J,et al.Virtual reality platform based on open sourced graphics toolkit OpenSceneGraph[C]//International conference on computer-aided design and computer graphics.[s.l.]:IEEE,2007:361-364.
[12] HIGHT J,NOVAK J.Game development essentials:game project management[M].[s.l.]:Gengage Learning,2010.
[13] ZLATANOVA S,RAHMAN A,SHI W.Topological models and frameworks for 3D spatial objects[J].Computers & Geosciences,2004,30(4):419-428.
[14] 孙 倩,刘晶晶.OSG视景仿真技术应用[J].中国科技信息,2017(3):18-20.