1 前言
我曾经细致阅读过 OGRE 和 OSG 官方提供的文档,有《Pro OGRE 3D Programming》、OGRE自带手册(manual)、王锐老师等翻译的《OpenSceneGraph Quick Guide》,同时在网络上查阅了大量的 OGRE 架构源码分析的文章。简单使用过 OSG,对 OSG 的场景管理器设计和编程风格有所了解,而在近期的项目中大量使用 OGRE,相对于 OSG,对 OGRE 的认识比较深刻一些。目前 OGRE 的最新版本是 1.7,OSG 的最新版本是 2.9.7。
本文是对 OGRE 和 OSG 这两大三维图形绘制引擎的一个不全面的个人比较,主要简单介绍它们在运行效率、平台支持、资源管理、场景树管理、功能支持、可扩展性、易用性和相关支持方面的异同,而不是评论谁优谁劣(当然本人也没这资历),通过了解差异后,根
据不同项目要求做出不同选择。
因为本人使用这两个绘制引擎的时间不长、运用的功能特性也不全,所以有些比较结论可能不合理,欢迎指正,通过交流,共同进步。
2 绘制引擎简介
2.1 OGRE
OGRE 是 Object-Oriented Graphics Rendering Engine(面向对象的图形绘制引擎)的简称,是一个用 C++开发的面向对象且使用灵活的 3D 引擎,是一个被广泛使用的开源三维图形渲染库。它成功地被应用于诸多三维仿真领域,其中包括网络游戏和一些商业的三维仿真项目。
它的目的是让开发者能更方便和直接地开发基于 3D 硬件设备的应用程序或游戏。引擎中的类库对更底层的系统库(如:Direct3D 和 OpenGL)的全部使用细节进行了抽象,并提供了基于现实世界对象的接口和其它类。OGRE 的主要特性有:
效率特性
简单、易用的面向对象接口设计使你能更容易地渲染 3D 场景,并使你的实现产品独立于渲染 API(如 Direct3D、OpenGL、Glide 等等)。
可扩展的程序框架(framework)使你能更快的编写出更好的程序。
为了节省你的宝贵时间,OGRE 会自动处理常见的需求,如渲染状态管理,空间裁剪,半透物体排序等等。
清晰、整洁的设计加上全面的文档支持。
在很多商业产品(特别是电子游戏)上得到应用,并被证实是一个稳定的引擎。
平台和 3D API 支持
支持 Direct3D 和 OpenGL。
多平台支持,支持 Windows(所有版本)、Linux 和 Mac OSX。
在 Windows 平台上可以使用 Visual C++或 Code::Blocks 编译。
在 Linux 平台和 Mac OSX 平台(使用 XCode)上可以使用 gcc 3+编译。
材质、Shader 支持
强大的材质声明语言使你可以在代码之外维护材质资源。
支持顶点和像素着色器(Shader),同时支持低级的汇编着色器和高级的着色器,如Cg、D3D 中的 HLSL 和 GLSL,并为许多常用的常量提供自动的绑定的,如世界视点矩阵、光照状态、视点世界坐标等。
支持固定渲染管线的全部功能,如多纹理、多遍绘制融合、纹理坐标生成和修改、为低端的不可编程显卡提供独立的颜色融合操作。
支持多个材质技术,你可以设计不同显卡配置的不同技术,OGRE 自动选择最佳的技术。
支持材质的 LOD;你的材质可以在它们远离视点时减少资源消耗。
支持从 PNG、JPEG、TGA、BMP 或 DDS 等文件中加载纹理;支持不常见的 1D 纹理、立体纹理、立体盒纹理和压缩纹理(DXT、S3TC)。
可以通过插件实时提供及更新纹理,如从视频上。
支持透射纹理映射(Projective Texturing)。
网格 Meshes
灵活的网格数据格式支持,独立于顶点缓存、序号缓存、顶点声明和缓存映射。
支持渐进的网格 LOD,可以自动或手动生成。
支持用 Bézier 样条实现的曲面。
静态几何分批绘制。
动画
支持复杂的骨骼动画
灵活的形状动画支持
支持场景节点动画,并提供样条插值
普通动画路径支持可插入的物体适配器(不是很清楚,详见官网说明)
场景特性
拥有高效率和高度可配置性的场景管理器,并且支持多种场景类型。使用系统默认的场
景组织方法,或通过亲自编写插件使用自己的场景组织方法。
提供的 BspSceneManager 插件是快速的室内渲染器,它支持加载 Quake3 关卡和 shader脚本分析。
多等级的场景组织体系;场景结点支持物体的附属(attach),并带动附属物体一起运动,实现了类似于关节的运动继承体系。
特效
粒子系统包括可以通过编写插件来扩展的粒子发射器(emitter)和粒子特效影响器(affector)。通过脚本语言可以不用重新编译就设置和更改粒子属性。支持并自动管理粒子池,从而提升粒子系统 的性能。
支持天空盒、天空面和天空圆顶,使用非常简单。
支持公告板,以实现特效。
自动管理透明物体(系统自动帮你设置渲染顺序和深度缓冲)
其它特性
资源管理和文档加载(ZIP、PK3)。
支持高效的插件体系结构,它允许你不重新编译就扩展引擎的功能。
运用“Controllers”你可以方便地改变一个数值。例如通过生命值动态改变一个飞船的防护罩的颜色值。
支持内存泄露检测的内存调试管理器
通过 ReferenceAppLayer 例程了解如何让 OGRE 与其它库协同工作,如做碰撞可信度的ODE 库。
可以用 XMLConverter 让二进制格式文件与 XML 相互转换,方便交流和编辑。
2.2 OSG
OSG 是 OpenSceneGraph 的简称,是一个开放源码、跨平台的图形开发包。它为诸如飞行器仿真,游戏,虚拟现实,科学计算可视化这样的高性能图形应用程序开发而设计。它基于场景图的概念,它提供一个在 OpenGL 之上的面向对象的框架,从而能把开发者从实现和
优化底层图形的调用中解脱出来,并且它为图形应用程序的快速开发提供很多附加的实用工具。
它完全是由标准 C++程序和 OpenGL 写的,充分利用 STL 和设计模式,发挥开源开发模型的优势来提供一个免费的开发库,并且重点集中在用户的需求上。随着使用一个全特性的场景图 OpenSceneGraph 的关键优势在于它的性能、可扩展性、可移植性和快速开发
(productivity),更具体的来说:
性能
支持视图投影剔除(view frustum culling)、隐藏面剔除(occlusion culling)、小特性剔除(small feature culling)、细节层次节点(LOD)、OpenGL 状态排序(state sorting)、顶点数组、顶点缓冲对象(vertex buffer objects)、OpenGL 着色语言和把显示列表(display lists)作为场景图内核的一部分。它们共同使 OpenSceneGraph 成为一个高性能的图形库。OpenSceneGraph
也支持绘制流程(drawing process)的定制,比如场景图的连续细节层次(CLOD)的网格(参见虚拟地形项目和 Delta3D)。
快速开发
场景图的内核封装了包括最新扩展的大部分 OpenGL 功能,提供诸如剔除和排序的渲染优化功能,同样提供能快速开发高性能图形应用程序的一整套补充库。应用程序开发者可以更关心实质性内容和如何操控这些它们,而不再是底层的代码通过学习已有的场景图,比如:Performer 和 Open Inventor,把它们同像设计模式这样现代软件工程理念联合起来,加上早期开发周期中的大量反馈信息,设计一个清晰的可扩展的库已经成为可能。用户可以很简单的适应 OpenSceneGraph 并且把它集成到自己的应用程序中
数据装载
为了读入和写出数据库,数据库支持库(osgDB)支持动态的插件机制,从而支持大量数据格式,目前的发布版本有 55 种单独的插件支持 3D 数据和图像格式的装载。
支持的 3D 数据格式包括 COLLADA、LightWave (.lwo)、Alias Wavefront (.obj)、OpenFlight (.flt),多线程页面调度支持的 TerraPage (.txp)、Carbon Graphics GEO (.geo)、3D Studio MAX (.3ds)、Peformer (.pfb)、AutoCAd (.dxf)、Quake Character Models (.md2)、Direct X (.x)和 Inventor Ascii 2.0 (.iv)/ VRML 1.0 (.wrl)、Designer Workshop (.dw)、AC3D (.ac) 和自带的.osg ASCII 文本格式。
支持的图像格式包括.rgb、.gif、.jpg、.png、.tiff、.pic、.bmp、.dds (包含压缩的一系列Mip 贴图影像)、.tga 和 quicktime (在 OSX 环境下),全范围的高质量、抗锯齿字体也能通过freetype 插件支持,基于字体的图像也可以通过.txf 插件支持。
用户也可以通过与一个同盟项目(VirtualPlanetBuilder)生成大规模地形空间数据(multi GB),使 用 OpenSceneGraph 的自带数据分页调度支持来查看这些数据。
节点工具箱
这个场景图同样有一套节点工具集,它们是可以在你的应用程序中编译或者在运行时装载的独立库:
osgParticle——粒子系统
osgText——高质量抗锯齿文本
osgFX——特效框架结构
osgShadow——阴影框架结构
osgManipulator——交互控制
osgSim——虚拟仿真相关的效果
osgTerrain——地形绘制
osgAnimation——动画
osgVolume——体绘制(通过 Dicom 插件支持医学数据)
可移植性
场景图的内核已经被设计成尽量少的依赖具体的平台,很少的部分超出了标准 C++程序和 OpenGL。这就使得这个场景图可以快速移植到大部分系统中——最开始在 IRIX 开发,然后移植到 Linux,接着 到 Windows,再后来就是 FreeBSD, Mac OSX,Solaris,HP-UX, AIX 甚至是 PlayStation2!
完全独立与窗口操作系统的场景图内核库使得用户在它上面可以增加他们自己的指定窗口库和应用程序,在发布版本中 osgViewer 库提供自带窗口支持,可支持 Windows (Win32),Unix (X11) 和 OSX (Carbon)。osgViewer 库也可以轻松的和你的窗口开发包集成起来,作为OpenSceneGraph-2.0 发布版本的一部分,有例子演示了如何在 Qt, GLUT, FLTK, SDL, WxWidget, Cocoa and MFC 中的使用。
可伸缩性
场景图内核的可扩展性使得它不仅仅可运行在便携式设备,甚至高端的多核、多 GPU的系统和集群上。这可能是因为场景图内核为 OpenGL 的显示列表和纹理对象支持多重图形渲染环境(multiple graphics contexts),剔除和绘制的遍历过程被设计成隐藏渲染数据为局部变量,这样可以以几乎只读的方式使用场景图内核。这样就允许多对剔除—绘制过程运行在多个 CPU 上,CPU 则是绑定在多个图形子系统之上。对多图形设备渲染环境和多线程的支持可以在 osgViewer 中方便使用,发布版本中所有的例子都可以以多线程和多 GPU 的方式运行。
多语言支持
OpenSceneGraph 以社区项目的形式支持多种语言,比如 Java,Lua 和 Python。
3 OGRE 与 OSG 的异同
通过上一节的简介可以大致了解到这两大 3D 绘制引擎的功能特性,同时也容易察觉到两者的异同。下面就两者的具体说明:
设计和体系
如果你曾经使用传统而基本的方法进行过 3D 应用程序开发(换句话说,就是有使用OpenGL 或者 Direct3D 这种底层 API 的经验),你会了解到它们有一些相似而且繁琐的过程:
通过调用 API 设置渲染状态;通过调用 API 传送几何体信息;通过调用 API 通知 GPU 渲染;清理;返回到第一步,直到渲染完一帧进入下一帧。这个过程会让你陷入纷杂的 API 操作之中,相对于真正的应用,可能你会被浪费在基本的几何体操作中去。如果使用面向对象的方法来渲染几何体,就可以从几何体级别的处理工作中抽离出来,转而处理具体的场景和在场景中的物体。其中的物体包括:可活动的物体、静态物体组成的场景本身、灯光、摄像机以及其他。你只需简单的把物体放到场景之中,OGRE 或 OSG 绘制引擎可以帮助你完成杂乱的几何渲染处理。也是为什么我们在开发 3D 应用程序时不直接使用 OpenGL 或 D3D 的原因。
OGRE 和 OSG 在架构设计上存在着许多共同之处,都是为了兼顾系统的高效性、可移植性和可扩展性,采用了以下设计理念和工具进行系统的设计和构建:
ANSI 标准 C++
C++标准模板库(STL)
设计模式(Design patterns, Gamma95)
通过设计模式的一些模式如 Abstract Factory、Listener、Adopter、Singleton 等,提高程序库的扩展性并易于与其它库协同工作。如 OSG 和 OGRE 库都有大量的功能强大插件支持,并可以同第三方界面库(如 Qt、MFC、WxWidget 等)分工合作。
但两者也存在着一些明显的不同之处。OGRE 从它的命名上可以直接看出,它是一个面向对象的三维绘制引擎。相比 OpenGL 和 D3D 的显明带有面向过程特征的 API,经过抽象的面向对象 API 更简明,使用更方便。而 OSG 是在 OpenGL 基础上提供了很多使用方便的功能包,并没有对底层图形接口(OpenGL)进行抽象。下面《Pro OGRE 3D Programming》中关于面向对象的优势所在的论述:
嗯,现在的图形引擎就像任何庞大的软件系统。在一开始很苗条,但很快变成惊人复杂的怪兽,让人难以理解它。这样大的系统难于管理,任何对系统的修改都可能影响其可靠性。而在这样一个不断出现新技术和手段的领域,修改又是必不可少。大量的使用 c 函数调用也无法对这一情况有任何改善 —— 即使所有的函数都是同一个人写的。通常会发现,几个月以后,一小段代码也会变得复杂难懂;该如何组织这些函数也会变成一个难题。
面对对象是解决复杂性问题的一个常用手段。它逐步的把代码分解到函数中,把函数和表示状态的数据用类组织起来,以表示现实中的各种概念。它能让你把复杂性隐藏在容易确定的代码包当中,只暴露出简单易用的接口。这样你就有了可以搭建在一起的“建筑材料”。你也可以通过组织这些材料使它们有一致的外部接口,而在内部,实现这些接口的方法却各不相同。这同样减少了复杂性,因为开发者只需要学习一种接口。
同时,OGRE 只专注于绘制,不负责其它模块,如用户界面、声音、网络、碰撞检测等,其它模块都是以插件的形式存在。而 OSG 提供了更多的功能,如前者所没有的功能,如虚拟仿真、体绘制、分页地形加载(最新 OGRE1.7 也引入了部分相关功能)等。所以如果是要利用现有成熟模块的项目可以使用 OSG,而需要开发更成熟更商业化的产品可以使用OGRE。
平台支持
从前面的特性分析可以看出,OGRE 与 OSG 对平台的支持的侧重点有所不同,如 OGRE侧重于成熟的商业化的平台,如 D3D 及主流图形操作系统,从而可以。而 OSG 强调支持多个操作系统,如 FreeBSD、Solaris、HP-UX、AIX 等,只要是支持 OpenGL 的平台,OSG 就有可能支持。由于大部分游戏及商业软件是基于 D3D 的,而 OGRE 对 D3D 提供了很好的支持,所以如果是开始游戏,OGRE 是一个很好的选择。
资源管理
不管地形、纹理还是字体等一切对象,绘制它们都需要不同的资源。如何加载、重用、卸载这些资源是非常重要的,因此,有专门的一批类来完成这些事情。OGRE 提供了一个功能完美的资源管理系统,包括对材质、Shader、粒子系统等一系列资源的分离于代码外的管理。OGRE 定义了功能强大的材质声明文件,可以在文件中直接定义纹理、绘制状态、Shader等信息,从 OGRE1.6 起还支持简单的变量和声明继承等,极大的方便了资源管理工作,更代码思路更清晰。
在图形引擎中,有大量的状态管理和上下文相关操作的代码。封装能把这些代码放在独立的资源声明文件中,这样以来代码就更容易理解。而且由于封装避免了复制代码方式的重用,也使得程序变得更可靠。且这些资源声明文件也是独立于平台的,这是 OGRE 作为一个成熟的 3D 绘制引擎的一个重大特性。
场景树管理
OGRE 与 OSG 都有一个场景树在管理整个场景的相关信息,通过场景树可以方便的管理场景物体,并且在向底层接口提交绘制操作前进行一些软裁剪和绘制顺序调整工作。同时OGRE 与 OSG 的场景树上每个节点所代表的内容是不同的。
首先,Ogre 对场景图的操作维持在接口级别;它并不关心去操作图形的具体算法实现。换言之,Ogre 只是通过 API 来操作场景图,进而忽略了具体的算法实现。其次,Ogre 的场景图接口只负责维护场景结构。节点中没有包含任何固有的内容和管理方法。具体的内容被
放置到一种可渲染(Renderable)对象之中,它提供了场景中全部几何图形(包括活动的的或者其他所有的)。它们的渲染的属性(也可以说是材质)被包含在实体(Entity)对象中,在实体对象里面同样包含着一个或多个子实体(SubEntity)对象,这些子实体才是是真正可
以被渲染对象。
场景图形树结构的顶部是一个根节点。从根节点向下延伸,各个组节点中均包含了几何信息和用于控制其外观的渲染状态信息。
ORGE《Pro OGRE 3D Programming》中提到:
虽然没有得到权威的论证,但我还是坚信场景图和场景内容的分离的设计一定是整个Ogre 项目中最亮眼的地方。虽然看起来它是一个如此的简单易懂,不过对于那些仍然坚守“传统的设计方法”来完成场景图设计的人仍然会难以理解。
在传统设计中(就是很多商业和开源 3D 引擎所采用的)将场景内容和场景结构放到一个继承体系中,并将场景内容生硬的作为场景节点的子类。我断言这是一个极其失败的设计方案。如果不修改所有的子类,基本上是没有办法更改或者扩充图形算法的,因此让修改基类的接口非常困难,进而导致以后的维护工作变得举步维艰。此外这种“所有节点源自同一节点类型”的设计思想会让整个程序变得凝固且难以复用(至少从维护的观点看):
当增加新的基类功能方法或者属性的时候,不管是否真的需要,这些都强迫的塞入所有子类。最后导致哪怕是对基本功能做很小的修改,都会牵一发会动全身, 导致开发维护最终变得难与控制。这种糟糕的设计理念让陷入的人们痛苦不堪,从而希望摆脱这种逻辑采用全
新的设计方法。
可以看出 OGRE 是出于可维护性和可扩展性才选择这种场景树管理方式的。配合 OGRE强大的代码资源分离功能,及可扩展的多场景管理器支持能力,这种简明的场景树管理设计取得了重大成功。
易用性
为了使代码可以支持 D3D 和 OpenGL 引擎,OGRE 编程中不推荐直接使用 D3D 或 OpenGL的 API,且绘制流水线与底层的 API 有一定区别,这就提高了入门难度,加大了学习曲线的陡峭程度。而OSG 只是基于OpenGL 单个底层API 的,所以可以直接在OSG 工程中加入 OpenGL的 API 调用,且一般情况下只也是唯一方案,如要使用 OSG 所没包括的新的 OpenGL 扩展。
从这点来看 OSG 比较适合要用到新的显卡技术的项目,而 OGRE 比较适合技术通用、成熟且要求使用更适合游戏的 D3D 引擎的项目。如前面提到的 OGRE 有一个强大的、功能齐全的资源管理器,可以大大减轻资源管理复杂度,提高资源加载、分配和利用效率。这有助于把美工、效果与代码分离,使编程时逻辑更清晰。这是程序设计的一个主流方向,如 Nokia的 Qt 用户界面库就是一直朝这个方向发展的。
相关支持
OGRE 与 OSG 在对一些资源和功能的支持上也存在这差异,如 OGRE 没有提供像 OSG 那样广泛的 Mesh 文件格式支持。其实 OGRE 只支持自身特有的.mesh 文件支持,而其它模型只能通过转换到这种格式才可以载入。同时 OGRE 也没有提供输入输出相关支持,需要通过独立模块 OIS(Object Oriented Input System)来支持输入输出操作。总的来说,OGRE 专注于 3D 绘制,而 3D 应用程序所需要的其它功能可以由插件或其它库完成。相对而言,OSG提供的支持会多些,如体绘制(osgVolume)、仿真模拟(osgSim)、声音支持(osgAL)等模块。
4 小结
本文简单介绍了一些 OGRE 与 OSG 的一些特性及之间的功能对比,在简化 3D 图形编程在设计理念下,两者又保持着自己独特的设计路线。OGRE 的特色在于成熟的设计模式、出色的资源管理方式和良多的跨平台性(特别是支持 D3D);OSG 的特色在于丰富的相关开源项目和文档、很多现成的功能模块。
同是开源项目,OSG 由一个超过 200 人的大规模开发队伍,而 OGRE 却拥有一个精小强悍的开发团队(现在共 7 人)。OGRE 相对而言比较活跃,功能更新频繁,这对于技术变化快速的图形绘制领域是重要的。至今,已有多款商业游戏使用了 OGRE 图形绘制引擎,如国内的网络游戏“天龙八部”、近期流行游戏“火炬之光”(Torchlight 2009.10)、网游“Zero Gear”等。OSG 偏向于虚拟仿真领域,强调库的功能胜于程序设计理论。两者都拥有着强大的开源社区,并是开源项目,随时可以方便的查看源代码,这对于开发应用程序是很有帮助的。
5 参考文献
[1]. OpenSceneGraph Quick Start Guide,Paul Martz[美],王锐 钱学雷 译,2007
[2]. Pro OGRE 3D Programming,Gregory Juker,邸锐 李旭东 译,2006
[3]. OGRE Manual v1.7 ('Cthugha'),http://www.ogre3d.org/docs/manual/
[4]. OGRE Features,http://www.ogre3d.org/about/features
[5]. OSG Introduction,http://www.openscenegraph.org/projects/osg/wiki/About/Introduction