清源游民 gameogre@gmail.com
设计哲学
传统上,使用 Direct3D 或 OpenGL 来渲染场景和对象,需要遵循一系列程序处理流的步骤:调用 API 设置渲染状态,调用 API 发送几何体信息,通知 API 或 GPU 去渲染几何体。对每个几何体都是如此返复,直到当前帧被完全渲染。在一下帧同样如此。
使用面向对象的方法来渲染几何体简化了上述过程。通过处理组成场景的各种对象而不是原始的几何体。这些对象包括:可运动对象,静态对象(构成世界布局),光,相机等。那些 3D API 则不再需要:只是把这些对象放到场景中, Ogre 负责处理琐碎的细节。而且,可以用更加直观的方法来操纵对象,而不是使用矩阵。总的说来,我们可以处理对象,它的属性,调用更直观的方法,而不再用顶点列表,三角形列表,旋转矩阵等手段来管理了。
Ogre 提供了面向对象的框架,包括了对象模型中的渲染处理的所有部分。渲染系统抽象了底层 3D API 的复杂性。场景图形功能被抽象成单独的接口,这样一来,各种不同的场景图形管理算法可以即插即用。在场景中的所有可渲染对象,无论是可移动的,还是静态的,都被一组公共接口抽象,这些接口提供了实际的渲染操作(例如 techniques 和它所包含的 passes ) .
设计亮点
一“设计模式”的合理使用
Ogre 中大量使用了经典的设计模式。例如,使用“ Observer ”模式来通知应用程序特定事件的发生,在 demo 中 FrameListener 的使用使得程序可以接收 frame-started and frame-ended 事件通知。“ Singleton ”模式强制实现类的单实例。“ Iterator ”模式用来遍历数据结构的内容。
“Visitor” 模式用来在对象上执行某种操作。 Façade 模式用来抽象底层,提供一个单一类接口。
“ Factory” 用来创建实例。
二 场景图与内容分离
传统上,场景图与内容同处于同一继承体系下。它要求从场景结点子类化内容类,也就是说内容类从场景结点继承。实践证明这种设计非常糟糕。 首先, Ogre 操作场景图形在接口层 , 它不假设特定图形算法的实现。实际上, Ogre 操作场景图形仅仅通过它的签名(方法),完全忽略底层的算法实现。
第二, Ogre 的图形接口只关心图形结构,不包含任何内在的访问或管理功能。后者被推到 Renderable 中,场景中的所有几何( movable or otherwise )都从它继承。这些 Renderalbes 的渲染属性(材质, materials )被包含到 Entity 对象中去。 Entity 可以包含一个或多个 SubEntity 。这些子实体是实际的可渲染对象。下面是各对象的一个关系图:
通过这样的设计,场景管理与场景内容充分解藕。过于场景图来说,通过 Movable Object 几何,渲染属性变得有效。注意到 Movable 不是从 Scene Node 继承而来的。 Movable Object 是 attached 到 Scene Node 上去的 . 当扩展,改变,重构场景图形实现时对场景内容对象的设计与实现没有任何影响。
从另一方面来说,由于场景图形不需要知道内容类的任何变化。只要实现一些简单的场景图形“确实“需要知道的一些接口。因此,我们可以任意的 attached 一些自定义的东西到场景结点上,比如声音信息等。(听说有个 OgreAL, 它包装了 OepnAL ,猜想就是这样做的吧)。
三 插件结构
OGRe 被设计成可扩展的。 Ogre 通过“基于契约的设计 ” 来完成。 Ogre 可以被设计成一组共同工作的组件,它们通过一些已知接口来相互交流。这带来极大的灵活性,某种功能的不同实现与改变非常容易。举例来讲,由于 ogre 处理场景图元管理是在接口级,用户可以随意的选择特定算法的实现。而且,当用户创建一个新的实现,可以很容易的以插件的形式提供给 Ogre, 实现时只要遵循 ogre 定义的一些接口 . File archives , render systems 也以插件的形式提供,粒子系统也是。 插件形式的吸引人之处是,为了加入插件,不需要重新编译 Ogre 库 . 插件可以在运行时加载。
四 硬件加速的渲染支持
Ogre 被设计成只支持硬件加速图形渲染,直接软件渲染不是它的选项。 Ogre 使用完整的硬件加速能力,包括可编程 shaders 。 Unreal 引擎能做什么, Ogre 就能做什么!!( ^_^, 作者说的)。引擎直接支持的全局光照 (precomputed Radiance Transfer 等 ) 还没有实现,因为这些多数用于非实时计算场合,因此不是什么问题 .Ogre 现在和未来将可能只使用 Direct3D 与 OpenGL 。
五,灵活的渲染队列结构
Ogre 采取一个新方法来解决场景中各部分渲染次序问题。粗略地看,标准过程通常如下工作:渲染地形或世界几何,渲染可移动对象,渲染各种特效,渲染 OverLay, 渲染背景或天空盒 . 然而,正如典型的实现一样(像集成电路处理模块),这个过程很难改变 . 在许多例子中, 很难改变渲染的顺序,导致难以维护与不灵活的设计的。 渲染队列的概念是: Ogre 以一次一个的方式渲染一组可以排序的队列,也已同样的方式渲染每个队列中的内容。也就是队列本身有优先级,同样队列中的对象也有自己的优先级。
上图中,队列由后向前渲染( Background à OveryLay ) , 在最前的队列中从左至右渲染。
在这种机制下重新组织渲染顺序非常简单,只要重新分配优先级就可以了。队列可以定制,队列中的对象也可以。整个队列可以“ turned on” and “turned off” ,队列中的对象也可以。 每个队列提供了事件通知(如 prerender and postrender ) , 应用程序有机会改变队列中的对象渲染。这个机制对于开发和维护复杂程序都相当有用。
六 健壮的材质系统
Ogre 的材质由一个或多个 technique 组成, technique 是 pass 的集合。 Pass 是材质级别的渲染单元,导致一次图形硬件的 ”draw” 调用。可以有多个 pass, 每个 pass 是一次全新的渲染操作,包括硬件渲染状态改变。
最吸引人的特性是 automatic fallback 。 Ogre 自上向下地( technique 列出的顺序)寻找最适当的 technique.Ogre 还能尽力地重新组织 technique 中的 pass, 以迎合最小的技术需求。例如,当前硬件只支持单纹理单元,而你程序中最小复杂度的技术,需要至少两个纹理单元,那么 ogre 会把一个 pass 拆分成两个,通过混合两个单元纹理的方式达到同样的效果。
Ogre 材质系统也支持 schemes 的概念。 Schemes 可以理解作为普遍的“非常高,高,中,低“不同等级的图形设置。在这种情况下,可以定义四个 schemes , 并为每一个分配 techniques( 复数 ) 。这样就可以 ogre 的所谓 technique fallback 查找那些属于特定 schemes 的 techniques 。使得材质管理更容易点。
用材质脚本完成的事,同样也可以用代码的方式完成。代码的方式也支持 schemes 与 technique fallback 。
七 本地优化的几何与骨骼格式
Ogre 使用它单独的 mesh 与骨骼格式。不能直接加载第三软件包生成的数据。社区中有转换第三文件格式的工具,但它不是 Ogre 库的一部分。 Ogre 使用自己的格式是为了效率。
八 多种类型的动画
Ogre 支持三种类型的动画:骨骼动画,变形动画, Pose 动画
骨骼动画,把顶点绑定到骨骼上。对象的每个顶点可以受到四个独立的骨头影响。每种影响被赋于一个用数量表示的权重。骨骼动画只在关键帧上执行前向运动学模式。 Ogre 当前不支持逆向动画 .
Morph 动画是一种顶点动画技术,他储存关键帧上的绝对的顶点位置信息,在运行时在两个关键帧之间插值。这与 Pose 动画不同, Pose 动画存储的是偏移数据而不是绝对位置。 Pose 动画可以混合以形成复杂动画。 Morph 动画比 Pose 动画功能有限,因为他存储的是绝对值,因此难以与其他 Morph 动画混合。 Morph 动画与 Pose 动画之间也不能混合 .
所有的动画类型都可以与骨骼动画混合使用 .
所有动画类型都可使用软件执行或是利用 GPU 硬件执行。
Ogre 动画是基于关键帧的,内插方式有线性与立方样条这两种选择。
九 Compositor Postprocessing ( 怎么翻译 ~?)
用来在一个视口中创建二维的,全屏的后处理效果 . 例如模糊,黑白电视,等等效果( Ogre 有个很好的示例) Compositor 也有类似于材质系统的 technique 与 pass 的概念。在视口最终被输出前,多个计算与渲染可被执行。像材质的 fallbacks,Compositor framework 提供了 fallback 处理,例如,当输出的像素格式无效时。理解 compositor 最容易的方法是把它当成片段程序(像素渲染)的扩展。不同之处在于:传统的图形管线每个材质 pass 只充许一个片段程序,而 Compositor framework 则可以像打乒乓球一样来来回回好多次。 Compositor 脚本扫行在 ViewPort 上,因此它可以面向任何的 render target, 可以是可渲染纹理,主,副渲染窗口。与材质系统一样,它除了利用脚本实现,也可以使用代码实现。
十 扩展资源管理
在 ogre 中,资源定义为:渲染几何体到可渲染目标上用到任何东西。很明显包括: mesh, skeleton, material , overlay script , font , Compositor script, GPU program , texture 。
每种资源都有自己的 manager, 它主要负责控制特定类型资源在内存中的占用数量。换句话说,它控制着资源实例的生命期。不过仅仅在一点上控制:首先,它只能储存同样多的实例,取决于这种类型的资源所分配的内存。第二, ogre 不会删除正被其他部分引用的实例。
资源本身实际负责加载自己。这是资源系统的一个设计特性:手工资源加载。手工加载意味着资源加载,处理,是利用一个方法调用实现的而不是从文件系统中隐式地加载。
资源在 ogre 中有四种状态:未定义, 声明,未加载, 加载。
未定义,说明 ogre 对它一无所知。
声明,它已经在档案中进行了索引。
未加载,已经进行了初始化(脚本,已经被解析过了),引用已经被创建
加载,已经在它的资源 manager 所管理的内存池中占用空间了。
可以用“组”来管理管理各类资源。组中资源之间的关系是任意的,完全取决于程序员:创建 GUI 的所有资源可以分为一组,以 A 字母开头的资源也可以分为一组,等等。有个 缺省的组:General
在 ogre 中查找某个资源实例时,不会考虑,资源所在的组。有时,我们可以将资源组命当成某种的 ” 命名空间来用“。
Archives 中的资源是非手动加载的。 Archives 是普通文件容器的简单抽象。它包括文件系统与 ZIP 档案。用户可以实现自定义类型的 archive 。
posted on 2007-03-05 23:22
清源游民 阅读(1879)
评论(0) 编辑 收藏 引用 所属分类:
OGRE