老人关于OGRE引擎的总体介绍

【Ogre总揽】,转至http://edu.gamfe.com/tutor/d/16715.html

 

Ogre是一个庞大而纷杂的对象和模块集合,如果初学者希望直接从对象列表中得到什么信息的话,可能会感到眼晕。但是事实上事情远没有这么复杂,当在你真正开始使用的时候,你会体会到Ogre完全面向对象设计的好处,绝大部分的细节都被隐藏在成熟的层次结构之中,只需要你简单的调用,就能实现很绚丽的功能。对于3D API或者其他一些引擎的使用者而言,很少能有这种经历,甚至也不会去这么想:在Ogre可以用很少的代码来完成一个完整而漂亮的3D应用程序。

Ogre设计理念

Ogre通过面向对象的方法实现了这样的一个入口,从实际应用进入到3D引擎具体的本职工作:把基本几何体渲染到目标区域(一般情况下指的是CRT或LCD显示设备的屏幕缓存,但也有例外)。如果你曾经使用传统而基本的方法进行过3D应用程序开发 style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: 600; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: blue; LINE-HEIGHT: 18px; PADDING-TOP: 0px; TEXT-DECORATION: none" href="http://edu.gamfe.com/gamedev.html">程序开发(换句话说,就是有使用OpenGL或者Direct3D这种底层API的经验),你会了解到它们有一些相似而且繁琐的过程:通过调用API设置渲染状态;通过调用API传送几何体信息;通过调用API通知GPU渲染;清理;返回到第一步,直到渲染完一帧进入下一帧。这个过程会让你陷入纷杂的API操作之中,相对于真正的应用,可能你会被浪费在基本的几何体操作中去。



如果使用面向对象的方法来渲染几何体,就可以从几何体级别的处理工作中抽离出来,转而处理具体的场景和在场景中的物体。其中的物体包括:可活动的物体、静态物体组成的场景本身、灯光、摄像机以及其他。你只需简单的把物体放到场景之中,Ogre会帮助你完成杂乱的几何渲染处理,从而脱离对调用API的依赖。而且你也可以通过简单的方法来操作场景中的物体来代替矩阵变换:例如,可以简单的通过角度或者弧度来控制物体在不同空间内旋转(包括本地空间、世界空间和父节点空间),而不必要通过矩阵的变换这种抽象的方法来操作实现变换。简而言之,面向对象让你可以处理更具象的物体、属性和方法。而不用处理抽象的顶点列表、三角形列表、旋转矩阵等底层概念。



Ogre的面向对象框架提供了包括全部渲染过程的对象模型。渲染系统(Render system)把复杂且不同的底层API(比如OpenGL和Direct3D)的功能抽象成一个统一的操作接口;场景图(Scene graph)也被抽象成为另外的一组接口,并且允许使用不同的场景管理算法实现“即插即用”的效果;所有可渲染(Renderable)对象,不论是动态还是静态,都被抽象出一组接口,用来被具体的渲染操作调用,比如技术(Technique)和其中的通路(Pass);可活动对象提供了一组通用接口接受各种各样的操作方法。

设计特色

对于一位有经验的程序开发 style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: 600; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: blue; LINE-HEIGHT: 18px; PADDING-TOP: 0px; TEXT-DECORATION: none" href="http://edu.gamfe.com/gamedev.html">程序开发者而言,Ogre的体系结构似乎可以是不言而喻的。但如果对于那些对面向对象设计和软件工程有点陌生的开发者而言,Ogre的设计抉择就需要费多一点的功夫来了解了。不过首先,让我们在这章节从一个比较高的层次上来概括一下Ogre总体的设计特色。

对设计模式的使用

Ogre的设计中成功的实现了多种通用的设计模式。其中设计模式(Design Pattern)为特定的软件问题提供一个通用且成熟的解决方案。其中“设计模式”这个词或多或少是被软件工程学界的“四人帮”(Gang of Four)的著作订立下来的,这本书的全称叫做《设计模式:可复用面向对象软件的基础》。作者“四人帮”分别是:Gamma,Helm,Johnson和Vlissides(Addison-Wesley出版社1995年出版,中文版由机械工业出版社出版)。



Ogre中使用设计模式来提高程序库的可用性和弹性。例如,Ogre使用观察者(Observer)模式将自己的每一个状态变化通知给应用程序,客户代码通过注册来监听Ogre中事件和状态的改变来得到相应通知(例如演示程序中使用的FrameListener对象,可以监听到应用程序每一帧渲染的开始和结束事件)。单件模式(Singleton)用来保证一个类只有一个实例,迭代器模式(Iterator)用来历遍一个数据结构中的所有数据。访问者模式(Visitor)可以让你在不改变对象(例如,场景中所有节点)的前提下,增加定义一个新的对象的操作。外观模式(Fa?ade)为子系统中的一组操作接口报漏给调用层一个统一的接口。最后,工厂模式(Factory)(以及它的近亲抽象工厂模式,Abstract Factory)广泛的用来创建抽象接口的实例。

场景图与场景内容分离

虽然没有得到权威的论证,但我还是坚信场景图和场景内容的分离的设计一定是整个Ogre项目中最亮眼的地方。虽然看起来它是一个如此的简单易懂,不过对于那些仍然坚守“传统的设计方法”来完成场景图设计的人仍然会难以理解。


在传统设计中(就是很多商业和开源3D引擎所采用的)将场景内容和场景结构放到一个继承体系中,并将场景内容生硬的作为场景节点的子类。我断言这是一个极其失败的设计方案。如果不修改所有的子类,基本上是没有办法更改或者扩充图形算法的,因此让修改基类的接口非常困难,进而导致以后的维护工作变得举步维艰。此外这种“所有节点源自同一节点类型”的设计思想会让整个程序变得凝固且难以复用(至少从维护的观点看):当增加新的基类功能方法或者属性的时候,不管是否真的需要,这些都强迫的塞入所有子类。最后导致哪怕是对基本功能做很小的修改,都会牵一发会动全身, 导致开发维护最终变得难与控制。这种糟糕的设计理念让陷入的人们痛苦不堪,从而希望摆脱这种逻辑采用全新的设计方法。


Ogre做到了。首先,Ogre对场景图的操作维持在接口级别;它并不关心去操作图形的具体算法实现。换言之,Ogre只是通过信号(它们的方法)来操作场景图,进而忽略了具体的算法实现。其次,Ogre的场景图接口只负责维护场景结构。节点中没有包含任何固有的内容和管理方法。具体的内容被放置到一种可渲染(Renderable)对象之中,它提供了场景中全部几何图形(包括活动的的或者其他所有的)。它们的渲染的属性(也可以说是材质)被包含在实体(Entity)对象中,在实体对象里面同样包含着一个或多个子实体(SubEntity)对象,这些子实体才是是真正可以被渲染对象。图3-1 展示了场景图结构和场景内容之间的关系。注意:尽管场景节点挂接到场景图上面;但场景图仍然没有任何节点状态的直接操作。


图3-1:Ogre中场景图和场景内容关系描述


其中活动对象MobeableObject可以直接操作所有几何体和渲染属性。它并不是场景节点的子类,而是挂接到场景节点中(可以理解为通过组合代替继承)。这意味着如果你需要,程序中的场景节点可以不用了解与之相关的可渲染对象的任何细节。也意味着你可以扩展,改变,重写,或者其他改变场景图的实现,而不会影响场景内容接口的设计和实现;他们彻底独立于场景图。场景图甚至可以完全修改而不会影响任何内容类。


反过来说也同样适用:场景图同样不需要对所挂接的场景内容节点有任何了解,只要通过所用的接口来通知就可以完成所需要的功能。因为这些出色的设计,Ogre甚至可以完成对“用户自定义(user-defined)”内容节点的挂接。如果你决定构造一个拥有环绕立体声的场景,你可以把各种音效实现自定义节点,然后无缝的挂接到场景中。自定义的场景节点只需要实现一个简单的接口,就可以把定制数据挂接到场景中任意的节点上。

就像我在前面说的,这是一个漂亮的设计。虽然在Ogre的开发历史中也经历过一些问题,不过到了现在的版本,这种设计已经得到了绝对的完善,请放心的使用。

插件体系

Ogre被设计成可扩展的。与传统的渲染API设计区别的地方,就是Ogre并没有强迫用户一定要使用某一个组成部分。使用者可以根据自己需要来组合不同的插件来实现不同的效果。Ogre通过一套固有的“契约模型(contract-based)”来支持相应的功能。换句话说,Ogre被设计成为类似集合的装置,里面包含着一些支持不同功能的元素,这些元素通过一套共识的接口(契约)来实现之间的通信协作。



基于这种实现,Ogre可以允许使用极其自由的方法来创建和使用不同的功能。举例来说,Ogre在接口层来管理场景图的实现,这样就意味着用户没有被限制在一定要使用哪几种场景管理算法的局限内。用户可以把任何自己程序需要的场景算法“插入”到Ogre程序库中,并且它们可以和Ogre本身提供的算法一样的良好的工作。如果在某个程序中需要KD-Tree场景算法的支持,你只要简单的按照Ogre定义的接口实现一个KD-Tree场景图的算法,并把它插入到你的Ogre程序中就能很好的使用了。



上面的做法对于所有能被插入的功能同样适用:包括文件管理和渲染系统都这些核心的功能,以及Ogre粒子系统这些非必要的功能都被设计成为插件。



这种插件机制最吸引人的地方,莫过于在加入新的功能插件的时候不用重新编译生成Ogre程序库。只要简单放入符合Ogre规范的插件文件,Ogre就能通过自身的一套机制在初始化或者运行期间动态载入插件。这些插件被载入到程序的进程中来,提供一些简单得信号和协议给Ogre调用。在这里面只是的通知了Ogre“我是谁”或者“我能处理什么资源”,同时提供自身的引用或指针给的应用程序调用。

硬件加速支持

Ogre是一种硬件加速的图形渲染引擎,这意味着至少需要一颗图形处理器(比如NVIDIA或者ATI出品的图形硬件上所拥有的);Ogre并没有提供纯软件渲染的功能。通过对硬件缓存(图形硬件和应用程序共享的内存区域)的使用,Ogre可以自由的选择最适合的运行方式。



这种设计对Ogre的性能提供了巨大的提高空间。作为一个以硬件为基础的渲染API,它能够支持目前绝大多数的硬件加速特性,其中包括可编程着色语言的使用。通过对可编程GPU着色管道的使用,Ogre已经可以达到目前绝大多数商业3D渲染引擎的高度:现在3D应用程序和游戏变成所具有的“幻想”,可以通过可编程着色语言来实现。换句话说,虚幻引擎,Cry引擎能做到的,Ogre一样可以做到。虽然仍会有一小部分最新的特性Ogre还无法在目前版本支持(例如,Direct3D中所支持的高级全局光照解决方案——包括环境光吸收、预计算辐射传递技术等)。不过这些高级算法基本都是在离线过程中使用(换句话说不支持实时渲染),所以对于应用程序并没有多大影响。



当前版本的Ogre支持两种渲染系统:Direct3D 9和OpenGL。这是两种目前使用最广泛的API(起码在Ogre所支持的平台上),可能将来也是如此。所以Ogre官方一直都只保留这两种基本API渲染系统的选择。

灵活的渲染队列

在Ogre的设计中,采用了特别的方法处理场景中不同部分的渲染排序问题。在传统的标准排序(概括地说)中采用如下顺序:渲染地形或者世界地图(World geometry),渲染活动物体,渲染特效,渲染Overlay(表层,包括GUI等),最后渲染背景或者天空盒。但是如果采用这种方法,就如同在程序中焊接了一块电路板,难于改变其中的运行过程。例如,如果想要写一个如同《真人快打》或者《街头霸王》这种格斗游戏,你可能就需要程序中实现和场景的交互效果;或者当需要创建一些不确定的场景特效(像实时阴影),就需要渲染一些“队列外”的图形。这种传统的设计让改变渲染顺序和实现“条件渲染”难于处理;最终可能导致整个设计固化并使代码难以维护。



为了解决这个问题,Ogre采用了“场景队列”。这是一个容易理解的概念:Ogre将需要渲染的内容分别放在多个有序队列之中,并且队列之间也是有自己的顺序,Ogre分别渲染每个队列。



图3-2 描述了Ogre中渲染队列的直观图。每个队列有自己的一个优先级,队列中的对象也同样有自己的优先级。例如,Ogre将按照从后向前(从底到高)的顺序渲染图3-2中的每个队列。在每个队列渲染过程中,Ogre也按照顺序来渲染其中成员。例如,在图中的表层(Overlays)队列中,Ogre将按序渲染HUD(Head Up Display仪表盘),Reticle(分割线),聊天文本,图形目录。


图3-2:Ogre中渲染队列


这个设计的灵活之处就在于组织渲染顺序和调整渲染顺序一样简单。渲染队列可以自由调整优先级,也可以选择打开或关闭(是否移出渲染列表)。同样,这些设置对于队列中的成员也同样有效。


每个队列中都提供了一系列队列内的事件,其中包括渲染前预处理(Prerender)事件和渲染后(Postrender)事件,使应用程序能够根据需要改变队列中对象的渲染状态。从开发和维护的角度看,用短小,简单容易理解的代码段去管理渲染队列是很有价值的,毕竟没有谁喜欢于从庞大的代码中剥离识别出与渲染场景之间的关联细节,。


换句话说,Ogre的渲染队列用优雅的面向对象方法,彻底的解决了传统应用程序中难以处理和解决的渲染顺序问题。


健壮的材质系统

Ogre 的材质脚本系统是整个引擎中最灵活和富有价值的系统之一。在物体已经被载入到场景的情况下,你可以不用修改或者增加任何一行代码,就能改变一个场景中对象的渲染状态。



Ogre的材质是由一个或者多个渲染技术(Technique)组成,每个技术中又含有多个渲染通路(Pass)。这种通路指的是一个单独的渲染通道,它是Ogre材质渲染中的一个基本单元。换句话说,对象的每一个渲染通路将导致一次对图形硬件的绘图调用。虽然你可以在每个渲染技术中使用多个渲染通路,但在此之前你最好明确,在大多情况下,每一个通路都会残生一次完整的渲染状态设置(导致硬件为每个渲染通路转换全部的渲染状态)。这样做明显影响程序的执行效率,但是为了某些华丽的渲染效果,有时候也必须使用多通路渲染的方法来实现。



这里面最漂亮的部分莫过于材质管理中的自动回调(Automatic Fallback)设计;在这种设计的支持下,Ogre能够自动应用“最好”的材质渲染技术——通过对渲染技术的遍历里,自动甄选目前图形硬件所能支持的最优实现方案。同时Ogre也能够在硬件能力不足的时候重组渲染通路来实现相同的效果。例如,在某图形硬件中之能够支持唯一的纹理单元的时候,如果在你最低配置的渲染技术中仍然有需要两个纹理单元的渲染通路,这时候Ogre就会自动把这个使用两个纹理单元的渲染通路拆分成两个各需要单一纹理单元的渲染通路,也就是用多通路来实现相同的渲染效果。



Ogre的材质也支持主题(Scheme)的概念,你可以把主题定义成比较通用的“超高精度,高精度,中精度,底精度”。这样,你就得到了四种不同的材质主题,然后可以把渲染技术分配到你认为合适的主题里(每个渲染技术中针对不同主题设置自身细节)。同时你可以通过通知Ogre在特定的主题中搜索合适的技术,这样使应用程序配置材质管理更容易。



其实你可以使用很多种不同的办法来管理材质,比如在程序中直接通过代码手动创建,其实这可能是经常会用到的方法。你也可以在手动创建的材质中设置主体和渲染技术等在材质脚本中使用的特性。当然,这样就没有直接使用材质脚本方式时不需要改变代码的好处了(事实上,材质最普通的产生方法是被美工创建,然后在3D工具中和模型一起导出到Ogre支持的材质脚本和模型等数据文件中来)。

使用独有的模型和骨骼文件格式

Ogre使用了自己独有的模型和骨骼数据格式。这也等于告诉你Ogre无法直接使用其他第三方的模型格式,例如商业游戏中的模型。你可以通过模型导出工具来把第三方模型转换到Ogre所使用的格式,不过这些转换工具并不属于Ogre引擎本身的范畴。



如果你使用二进制格式来保存模型和骨骼数据文件,Ogre可以快速高效的载这些数据。这些二进制文件可以通过外部导出器或者离线工具(命令行OgreXMLConverter工具,在附录A讨论)来生成。当然,如果你愿意,OgreXMLConverter工具内部的类是允许在你自己的应用程序中使用的(假如你想从3D模型包中导出模型数据到二进制文件)。通常有一种普遍的创建二进制模型和骨骼文件的方法,先把场景或者角色模型数据从3D工具中转换到中间格式——可读的XML格式(Ogre XML),然后再通过命令行工具转换这个数据到二进制。Ogre官方网站上提供了当前大多数3D模型工具(包括商业和开源)的导出文件插件。其中包括Softimage|XSI、Autodesk 3D Studio Max 、Maya和Blender(还有很多没有在这里列举出来,你可以到Ogre官方网站上去查看详细列表)。



类似的,当你决定处理XML格式版本的模型和骨骼数据文件的时候,低下的效率简直是一个梦魇。XML文件的长处是可以在不同体系的系统间交换的数据格式(比如在某一个3D模型制作工具到Ogre二进制之间传递模型和骨骼数据)。但是对于那些需要性能和效率的应用程序来说,这是一个让人讨厌的格式。作为一种中间格式来说,XML的可读性可以让你亲自来检查和手动修改导出数据。这个格式也可以让调试你的导出插件变得容易,例如你在导出管线中增加附属工具对导出对象结构和顺序的调整;通常来说处理XML格式的文件细节要比处理二进制数据文件容易得多。



在二进制数据格式种主要保存了顶点、几何体和骨骼数据,但你也可以离线的处理一些其他的特性一同放入二进制文件中。其中包括自动的LoD(细节层次)处理和对象法线的预计算等等。用离线方式处理这些信息节代替运行时的处理,就能够减少相当一部分载入的时间。

多种类型动画

Ogre支持三种动画方式:骨骼动画(Skeletal)、变形动画(Morph)以及姿态动画(Pose)。



骨骼动画是通过把顶点绑定到骨骼的骨头(Bone)上来实现的(也被称为矩阵调色蒙皮技术,或简称为蒙皮技术)。在物体上的每个顶点都可以同时被四块独立的骨头影响,影响的具体力度取决于顶点对每块骨头分配的权重,当骨骼运动的时候,所有被它影响的顶点都根据骨头的位置和权重来更新自身的位置。这种算法可以模拟很多现实的顶点位移,例如可以很好的模拟在移动的胳膊的时候肩膀的外型的变化(更确切地说,因为当胳膊抬起的时候肩膀相应的肌肉会收缩)。目前Ogre还只能支持关键帧形式的正向动力学(FK)骨骼动画;也就是说没有提供对逆向动力学(IK)骨骼动画的内建支持;如果你的美工在3D模型工具中使用了逆向动力学产生相应的动画,这时候可以对骨骼每一帧进行采样来转换成正向动力学的骨骼动画。通常来说,这些工作都可以在导出插件中很好的完成。



变形动画与姿态动画都属于顶点动画技术。变形动画存储了顶点在每一关键帧的绝对位置,然后在运行时对两个位置进行相应的插值计算,因为多个顶点的绝对位置无法叠,所以多个变形动画之间无法相互混合成新的动画。而姿态动画的不同之处在于它储存的是顶点的相对位置,因此多个姿态动画的轨迹可被混合起来,进而创建出更复杂的顶点动画。不过上面两种类型的动画都可以与骨骼动画很好的混合使用。



上面提及的所有动画都既可以在软件层面执行,也可以通过顶点着色程序在图形硬件中执行。在硬件实现的骨骼动画中,骨头的位置被作为参数传递给顶点着色程序。每个顶点通过和绑定的权重和索引得出具体所使用的骨头数据;变形动画不需要额外的参数传递,只要把新的顶点数据作为第二个顶点缓存传递给顶点着色处理就可以了;对于姿态动画,具体传输数据的数量不能确定,因为每增加一个新的姿态动画混合就需要多一个顶点缓存数据传入顶点着色程序。



和变形动画之间不能被混合一样,变形动画也不能混合到姿态动画里面,反之亦然。然而对于这两顶点种动画来说,都可以良好的和骨骼动画进行混合操作。



Ogre在管理动画的时候引入控制器(Controller)的概念,明确地说,就是通过一个值索引出另外一个值(在动画中,作为索引的值其实就是“时间”)。另外,在Ogre中的动画是使用关键帧的概念的,在关键帧之间的数据通过插值算法计算出来。Ogre中提供了线性样条和三次样条两种不同的插值方法。你需要根据你模型中动画的具体内容来选择匹配的插值方式,或者也可以使用导出工具去具体取样产生。

合成器后处理技术(Compositor Postprocessing)

合成器框架(Compositor framework)是Ogre新加入的一个特性,它允许用户在视口(Viewport)级别实现全屏的二维后处理(Postprocessing)特效。例如,你可以把视口中全屏的内容实现的发光或者朦胧处理、黑白渲染、锐化边缘渲染。任何你能想象的对整个视口的操作都可以在合成器框架中实现。



这种框架的处理方式极其类似材质脚本系统。其中合成器中的技术(Technique)概念和材质脚本中的渲染技术概念一样,都是指的达到某种特效所能使用的不同方法。合成器中的通路(Pass)也和材质脚本中的渲染通路有类似概念,既在创建视口最后的输出之前进行的多次运算或者过滤过程。并且合成器框架也提供了和材质脚本一样的自动回调技术来保证最终输出的像素各式可用。



对Ogre中的合成器框架最简单的理解即是对片段编程(像素着色)管道的扩展。事实上,合成器框架最大限度的利用了图形硬件中的片段可编程特性;虽然合成器框架和材质脚本都定义了渲染通路概念,但不同的是材质脚本中每个渲染通路只能允许一个片段程序执行来改变渲染管线中的数据,而合成器框架中的渲染通路却可以把渲染到像素缓存的结果 “反弹”回来,再次进行多次的渲染,直到合成器中的脚本“满意”为止。当然,如果你小心的处理维护多个像素缓存也可以实现一样复杂的的后处理效果。不过现在有了合成器框架出现,还有什么理由做这些麻烦的事情呢?



合成器脚本的是针对于视口的操作,这就意味着你可以把这些特效应用于任何渲染目标,其中包括渲染到纹理,渲染到主窗口或者里面的子窗口。不论后面是否有已经存在的几何体,最终的渲染结果都很好的显示到表层的矩形的视口中。例如你可以把一些物体渲染在屏幕之外,然后把经过后处理的结果通过渲染到纹理在主屏幕中显示。



和材质脚本一样,合成器框架也可以直接从代码中直接创建。你可以在代码中使用一切可以在基本中存在的属性和方法。合成器框架也有同材质脚本一样的“主题(Scheme)”概念,事实上,合成器框架中的主题操作是通过材质主题来实现的。

可扩展的资源管理

资源在Ogre中的定义是“所有渲染几何体到渲染目标的数据所需要的数据”。这不仅包含模型,骨骼,材质,还包含表层(Ovelary)脚本和字体,以及有材质处理所需要的一些资源,比如合成器框架脚本、GPU程序和纹理。



Ogre中每种资源都提供了自己的资源管理器。这个资源管理器管理着资源们所占内存的大小,进而控制每一个资源实例的生存周期。本质上,资源管理器在管理中只有两条指导性的原则:首先,在内存允许的情况下,尽量储存更多的这种类型的实例(当然是针对已经被载入的资源);其次,绝对不在资源还在被使用的情况下移除相应的实例。



Ogre同时有手动载入和隐式载入两种不同的载入方法:手动载入指的是在代码中通过接口来载入相应的资源,其中包括字体和模型这种资源,在需要使用前需要执行一些代码来载入和初始化。而对于其他一些资源来说,在载入配置文件的时候就已经被预先载入了,其中包括经常使用的纹理资源.



Ogre中的资源有四种不同的概念,资源实例在任何时候都只能是这里面的一种状态。其中包括:未定义状态,Ogre不知道这个资源的存在;已声明的状态,代表这个资源已经被索引,但没有被解析;未载入的状态,代表这个资源虽然已经被初始化(如果它有一个脚本,这个脚本已经被解析完)并且它的引用已经被创建;已被载入状态,代表这个资源的实例已经占用了内存空间。



Ogre在管理资源的时候采用了“命名组(named groups)”的概念。他能使逻辑上的载入、卸载、创建、初始化这些具体的操作变得容易处理。“组”的概念完全取决于你自己对它的定义:你可以把某一个游戏中某一个关卡的资源分配到一个组里面;也可以把构建GUI图形界面所需要的资源分配到一个组;甚至可以把所有以字母A开头的资源分配到一起。这些定义随你喜欢,Ogre本身并不在意这些(有一个例外,就是包罗万象的:General,普通组)。当你的应用程序需要搜索需要的资源的时候,如果在相应的组中存在的话,Ogre就可以帮你找到(你也可以让Ogre在所有组中寻找)。组的划分还有另外一个用处:你可以把组名作为一个区分同名资源的“命名空间”(当你在不同类型的资源中可能使用相同的名字时候,格外重要)。



Ogre中的那些非手动载入的资源都独立存在于档案(Archive)中。Ogre中的档案是一种简单的文件容器。你可以使用通配符搜索里面的文件;能返回所需文件的引用;甚至可以打开和关闭里面的文件。乍听起来,我们似乎在谈论操作系统的目录或者文件夹。不过你可以这么认为,对于Ogre来说,操作系统本身的目录或者文件夹就是一种档案的具体实现,Ogre本身还提供了Zip的档案具体实现,也就是通过一个简单的被压缩的PKZIP格式文件来实现档案的储存。当你你可以提供任何实现方式的档案给Ogre程序使用,比如一个直接到网络其他主机中读取文件的档案实现,如果网络速度足够好,你就可以像在本地一样处理网络数据。

Ogre的处理机制通过扩展名来索引所需要的数据,比如.material,.mesh,.overlay等等。未知格式的文件将被Ogre忽视,所以你在档案中也可以里面混合使用Ogre有关的和Ogre无关的不同资源,不会对Ogre本身有任何影响。

子系统总览

上面介绍了Ogre中很多漂亮的设计特色,他们是通过引擎里面无数的类来实现的。幸运的是你并不需要了解具体里面的运行原理,只需要知道怎么调用它们的使用接口就可以来构建你自己的3D应用程序了。



让我们通过了解最基本和通用的子系统来作为了使用个Ogre的起点。这些系统和类将贯穿整本书的后面的所有章节,为让你很快熟悉Ogre,首先在这里简单的介绍一下它们的作用。可能你现在不会对它们有直观的感觉,不过不用担心,后面的章节还会多次提及它们。



Root对象

Root对象是一个Ogre应用程序的主入口点。因为它是整个Ogre引擎的外观(Fa?ade)类(请参考设计模式中的外观模式),所以在


这里作为第一个被列出来的类,它提供了方便的调用整个Ogre每个子系统的接口。



通过Root对象来开启和停止Ogre是最简单的一种方式;当你构造构造一个Root实例的时候你就启动了整个Ogre,当析构的时候(让它停止活动或者执行delete删除它)Ogre也就关闭了。

资源管理器

为了渲染场景需要相应的资源,Ogre使用了一个单件对象:ResourceGroupManager来作为资源管理器。这个对象的实例负责定位资源具体位置(在应用程序设置的路径中搜索)和初始化(不一定需要载入)已知类型的资源。



默认情况下,Ogre可以识别下面几种类型的资源:



·模型(Mesh):Ogre可以快速载入的二进制模型格式,同时也是Ogre唯一支持的模型文件格式。可以通过OgreXMLConverter工具通过命令行的方式产生这种文件,也可以在3D模型工具中通过导出插件创建。当把它放入Ogre的档案系统中的时候,要确认扩展名一定是“.mesh”,否则Ogre无法识别其类型。如果你的模型是用了变形动画或者姿态动画,就会再Mesh模型文件中同时包含这些动画的执行数据。



·骨骼(Skeleton):一般而言,骨骼数据都是作为模型文件的附属信息,其中提供了模型的骨骼层次关系和相应关键帧数据,但是如果有具体的需要,也可以作为独立的资源。骨骼数据文件的扩展名为“.skeleton”,和模型文件一样,也可以通过OgreXMLConverter工具和导出插件来创建。



·材质脚本(Material):材质脚本文件定义了渲染几何物体所需要的状态信息。模型文件中可以直接引用材质脚本,也可以在具体代码中指定所使用的材质。这些脚本一般通过3D模型导出工具一起导出,它的扩展名是“.material”。



·GPU程序:提供给图形硬件的着色语言文件,其中高级语言的GPU程序(包括HLSL,GLSL和Cg)使用“.program”作为扩展名。而汇编语言的GPU程序扩展名是“.asm” 。在Ogre运行时,将会在载入材质之前对这些文件进行解析(注意,不是编译),这样做的目的是让在材质脚本中可以使用GPU来定义具体材质。



·纹理(Texture):因为Ogre使用了OpenIL图片库来实现纹理的处理,所以基本上可以支持所有目前的2D图片格式作为纹理数据。Ogre可以识别具体图片格式所专用的扩展名(比如,JPG、GIF等等)。



·合成器脚本(Compositor):合成器脚本在Ogre系统中采用了和和材质脚本相同的处理方式。唯一的区别就是合成器脚本扩展名是用了独有的“.compsitor”。



·字体信息(Font):这里说的并不是系统中的字体文件(当然也需要提供),而是Ogre系统使用扩展名为“.fontdef”文件来索引具体定义的字体信息(比如字体大小和系统字体的文件名)。



这里所提及的所有资源都有其相应的资源管理器(ResourceManager)(例如,材质对应MaterialManager,字体信息对应FontManager,依此类推),但是除非你需要自己添加新的资源类型,否则你没有必要处理具体的资源管理器。



Ogre还提供了相关的资源组管理器(ResourceGroupManager),它的作用是通过名字来索引指定资源。不过它不会负责具体针对资源的内存管理(例如,卸载不用的资源,把空间分配给新的资源);这些具体的内存管理工作交给了资源管理器来处理。资源组管理器允许你通过组名来一次载入和卸载整组的资源(例如卸载全部字体信息资源并释放他们占用的内存)。



在默认的情况下,Ogre认为它的资源都是以磁盘文件的形式存在的。不过,对于一些特定类型的文件可以实现手动的方法来产生;虽然目前Ogre内部只支持了模型和字体资源类型的手动产生,不过你可以根据自己的需要,在程序框架中加入自己创建的手动资源载入器,进而可以实现对新类型的手动管理。

场景管理器

可能你会记得我们之前已经讨论过场景管理器(SceneManager),它是Ogre引擎中极其要的组成概念。所有场景图的具体执行过程都来自SceneManager类。当正式进行Ogre程序开发 style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-WEIGHT: 600; PADDING-BOTTOM: 0px; MARGIN: 0px; COLOR: blue; LINE-HEIGHT: 18px; PADDING-TOP: 0px; TEXT-DECORATION: none" href="http://edu.gamfe.com/gamedev.html">程序开发的时候,你会发现为了对场景观进行具体的管理会经常的和场景管理器打交道。虽然大多数时候你的场景中只有一个场景管理器存在。不过如果你喜欢,甚至可以和多个场景管理器很好的“合作”,因为Ogre支持并发多个场景管理器之间协同工作。



场景管理器可以帮助你创建具体的场景节点(Scene Node)。所谓的场景节点就是你在场景中实际移动变换的基本单元。它们也有自己的关联层次(可以有父节点或者子节点);节点的操作支持三种不同的坐标系空间:世界坐标空间,父节点空间和自身空间。所以在你进行移动,缩放,旋转的时候,可以自由选择使用的坐标空间。场景节点可以独立于场景图存在,这里体现了场景内容独立与场景图所带来的好处:内容不会被具体的场景图所影响,可以把它重新挂接到其他的场景图上。



场景中具体的场景内容需要挂接到场景节点上才能显示。这里所说的内容在大多数情况下指的就是实体(Entity)。实体继承于活动对象(MovableObject),并通过场景管理器来进行创建。如果你有已经有一个的实体的具体实例,你就可以把它绑定到已经存在的场景节点上。基本上实体都是从硬盘上的“.mesh”文件载入的模型来构建。不过你也可以通过手动来产生具体的实体,如果你喜欢,Ogre本身也可以帮助你构建比如平面这样的内部支持的模型构造。当场景内容挂接到场景节点之后,你就可以通过场景节点来管理实体了,注意,是变换场景节点,而不是场景内容。



也可以挂接其他对象到场景节点上。例如,把摄象机或者光源挂接到上面。


渲染系统和渲染目标

一般来说,开发者没有必要直接对渲染系统(RenderSystem)进行操作。因为渲染系统是Ogre对底层硬件API(OpenGL或者Direct3D)的一层抽象。尽管如此,你还是至少要了解渲染系统所创建的一个对象类型,即渲染目标(RenderTarget)类。它是对Ogre中两个重要概念的概括抽象:渲染到窗口和渲染到纹理。其中渲染到窗口是几乎每个Ogre应用程序都要用到的功能,而渲染到纹理是一个特殊(但是经常使用)的用来产生高级渲染效果的手段。



Ogre的渲染窗口一般来说指的是是你应用程序的主窗口(也支持多个窗口渲染)。不过你也可以把渲染窗口包含在另外一个窗口中(在创建3D工具的时候经常用到)。但是不论你最终使用哪种方法来创建渲染窗口,你都至少需要一个渲染窗口(不过有一种极端情况,就是你可以Ogre做离线渲染图形处理,然后把结果放在另外的装置上显示,一般来说这是一个非即时3D渲染工具所需要的功能)。



渲染窗口可以通过Root对象自动创建,也可以借助Root或者RenderSystem对象的实例来进行手动创建。当手动创建的时候,你会得到更多的权力来设置窗口的内部具体属性,但是同时给你带来了相应的复杂性。所以对于一般的应用程序而言,自动创建的窗口就足够了。Ogre内部创建的窗口因为要支持跨平台应用,所以在接口层无法得到平台相关的信息(比如Windows的消息),所以当你有特殊需要的时候(比如需要Windows消息支持的中文输入功能)最正规的办法应该是自己创建并维护渲染窗口。但是这种做法相对于直接通过Ogre维护来说复杂了许多。如果你没有信心这么做,可以投机取巧的修改Ogre的源代码(或者使用钩子程序),把所需要的信息截获出来,不过这始终不太好看,也不建议使用。

Ogre中的管理器

Ogre中的管理器是对某对象的相关类型进行管理的类,它可以通过名称来帮助你索引实例或者管理实例的生命期。举例来说,档案管理器(ArchiveManager)既管理档案(Archive)的创建和注册,也能帮助你在注册后索引到具体实例。每一个管理器,包括Root(作为“Ogre的控制中心”,所以也可以被称为管理器),都是作为“单件”对象存在(参考单件设计模式)。创建Root的一个附加功能是帮助你初始了所有Ogre其他管理器对象的实例。



注意:单件模式通常用于维护某个类在程序中只有唯一实例。因为管理器类作为负责管理特定类型和应用的数据和资源的中心对象,所以能很好的适应单件的设计模式。更可贵的是作为单间模式的“赠品”,当管理器被构造之后,实例可以直接在程序的命名空间中的任何地方直接被调用,这样就避免了对实例指针的传递。基于以上的原因单件模式被Ogre广泛的使用于管理器对象的维护。




在下面我将对每个管理器做一个简单的介绍。它们更多的细节会出现在书的后面章节中。



·日志管理器(LogManager):发送日志信息给输到出流,也可以把信息送到需要使用的代码中去。



·控制器管理器(ControllerManager):对控制器(Controller)进行管理,所谓控制器,就是基于变量输入来改变其他类状态的工具类;常用于对动态纹理(Animating Textures)和材质的控制。



·动态链接库管理器(DyLibManager):负责管理动态链接库(Windows上的DLL,Linux上的共享对象),是Ogre插件体系实现的基础。也会在关闭系统时候卸载库。



·平台管理器(PlatformManager):用于对不同硬件和操作系统抽象出来具体的通用对象进行管理。比如其中包括了计时器(Timer)和不同的窗体(例如启动Ogre时用来配置渲染系统的对话框)。



·合成器管理器(CompositorManager):用于管理合成器,以便在屏幕空间实现2D后处理特效。



·档案管理器(ArchiveManager):管理档(Archive)所使用的不同“容器”,例如ZIP文件或者系统目录。



·粒子特效管理器(ParticleSystemManager):管理粒子特效,以及维护发射器和效果器的实现和细节。



·材质管理器(MaterialManager):维护应用程序中所有已经载入的材质,并允许不同对象共享同名的材质实例。



·骨骼动画管理器(SkeletonManager):维护应用程序中所有已经载入的骨骼动画,并允许不同的模型共享骨骼动画实例。



·模型管理器(MeshManager):维护应用程序中所有已经载入的模型,并允许不同实体共享同名的模型对象实例。



·高级GPU程序管理器(HighLevelGpuProgramManager):维护,载入,以及编译程序中所有使用的高级GPU着色程序(包括HLSL,GLSL或者Cg写的GPU程序)。



·GPU程序管理器(GpuProgramManager):维护和载入汇编语言的GPU程序,也可以支持高级GPU程序编译成的汇编着色语言。



·外部纹理资源管理器(ExternalTextureSourceManager):管理外部贴图源类的实例,例如那些使用外部视频流生成的即时纹理。



·字体管理器(FontManager):管理和载入用于表层(Overlay)中文本渲染的字体。



·资源组管理器(ResourceGroupManager):作为“接触点”,用于载入和管理已经注册的应用程序资源,比如模型和材质。



·表层管理器(OverlayManager):管理载入和创建2D层类的接口,通常用于HUD,GUI或者其他渲染到场景最上层的2D内容。



·硬件缓存管理器(HardwareBufferManager):管理硬件缓存(像素缓存,顶点缓存,索引缓存等)。



·纹理管理器(TextureManager):管理应用程序中的纹理的索引和载入。



这些管理器类型只不过是系统提供的管理入口。它们中的所有个体都是靠更多的类来完成具体的工作的。


结语

不要奢望可以在这一个章节中了解Ogre的全貌,无数的宝藏仍然掩埋在Ogre引擎的里面。现在可能你知道了大部分的常用的对象和接口,不过还有很多在这里没有涉及到的。我们将会在后面的章节中尽量的介绍给你。这本书的后面将会覆盖Ogre的所有主要功能,但为了更好的使用,可能你需要一些其他的书和知识作为辅助(比如一些图形学的基本概念)。



如果你只是想简单的在屏幕上画一些几何体,那么可以直接读下面一个章节。但是如果你希望更好的使用Ogre并且不具备足够的基础知识,那就可能需要暂时放下这本书,读一些基础的文章,然后再开始第四章的阅读。不管怎么说,再看完这章节之后,你已经拥有了Ogre和这本书的地图,也希望你能有个愉快的旅程。

转载于:https://www.cnblogs.com/Lipp/archive/2012/09/15/2686543.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值