开源3D图形渲染引擎OGRE学习笔记
参考资料:
电子书:《
Pro OGRE 3D Programming
》中文翻译本
官方
wiki:
http://www.ogre3d.org/wiki/index.php/Main_Page
中文网站
(
有电子书下载
)
:
http://www.ogre3d.cn/
OGRE(Object-oriented Graphics Rendering Engine)(Ogre,
食人魔
)
,是一款
成熟、稳定、可靠、灵活、跨平台、而且拥有丰富功能开源实时
3D
图形渲染引擎(
并不是游戏引擎)
,由
ogre3d.org
社区维护,遵守
LGPL(GNU Lesser General Public License
)
协议。
同类其他开源引擎:
1. Irrlicht
(
鬼火
)
2. Nebula(
星云
)
3. klayGE
OGRE
引擎特性:
·全面并同等的支持
OpenGL
和
Direct3D
·全面支持
Windows
,
Linux
以及
Mac OS X
平台
·
其完全的面向对象设计,允许您通过插件和子类毫不费力地扩展引擎的功能。
在
Ogre 3D
的名字中包含“
3D
”是很贴切的,因为那就是它所能做的所有事情。它不能处理用户输入,不能管理你的游戏状态,不能做网络通讯,不能播放声音。它只是做为一个
3D
渲染引擎被设计出来,并且那就是它唯一的应用。因为专业,所以它总是能够很好的完成它本分的任务。(虽然
Ogre
引擎中也会包含比如输入系统等一些简单的实现,但官方的说法一般是:这只是为了支持演示程序所提供的,不建议你在自己实际的应用中使用。你需要在
Ogre
去中去寻找其他的库来完善你自己的工具箱。)
当
今大多数软件都会依赖于其他软件或者开发包中提供的外部功能,这样可以让软件的开发在别人已经存在的成果之上,避免了重复制造轮子。如果不需要对常用的功
能重复实现,这样做最直观的好处就是促使工作团队更集中精力解决他们自身软件中所存在的问题,进而产生出更高质量的产品。而且随着开源社区的发展,越来越
多优秀的软件或者程序库可以从网络上免费得到。不过更多的依赖项目也意味着需要相对更复杂的编译环境设置,甚至有时候要编译构建所依赖的项目源代码产生。
如果依赖了一些在活跃开发期的项目,就意味着有可能需要经常更新。
OGRE
的最小依赖集有
FreeType, OpenIL, zziplib
。
我能用
OGRE
做游戏吗?是的,你能。并不象许多其他的
3D
引擎,
OGRE
并不是适合任何类型的游戏。由于开发的原因,
OGRE
只适合第一人称射击游戏。
OGRE
特别适合制作
3D
游戏。
Ogre 3D
自发布以来,被成功地应用于诸多三维仿真领域。其中包括网络游戏和一些商业的三维仿真项目。
在国内,基于
OGRE
的网游大作
MMO
已经有几款了,其中包括搜狐的《天龙八部》、吉比特的《问鼎》、深圳网域的《华夏
2
》以及久游的《疯狂飙车》。
Ogre
是一个庞大而纷杂的对象和模块集合,如果初学者希望直接从对象列表中得到什么信息的话,可能会感到眼晕。但是事实上事情远没有这么复杂,当在你真正开始使用的时候,你会体会到
Ogre
完全面向对象设计的好处,绝大部分的细节都被隐藏在成熟的层次结构之中,只需要你简单的调用,就能实现很绚丽的功能。对于
3D API
或者其他一些引擎的使用者而言,很少能有这种经历,甚至也不会去这么想:在
Ogre
可以用很少的代码来完成一个完整而漂亮的
3D
应用程序。
引擎这个术语暗示
Ogre 3D
为你的
3D
图形的应用程序提供了“强大的动力”,进而允许你更多关注应用程序细节而不是一个
3D
场景的渲染过程。作为应用程序的中间件,
Ogre
扮演了一个专注于处理了三维空间场景的角色。如果你熟悉
Direct3D
或者
OpenGL
,你会知道直接写一个图形程序需要多少代码,当你了解
Ogre
让你可以用很少量的代码来构建一个完整的三维场景(也有用在其他的方面,我们将在之后的文章中介绍)的时候,你就会庆幸有
Ogre
的存在。
Ogre
通过面向对象的方法实现了这样的一个入口,从实际应用进入到
3D
引擎具体的本职工作
:把基本几何体渲染到目标区域(一般情况下指的是
CRT
或
LCD
显示设备的屏幕缓存,但也有例外)。
如果你曾经使用传统而基本的方法进行过
3D
应用程序开发(换句话说,就是有使用
OpenGL
或者
Direct3D
这种底层
API
的经验),你会了解到它们有一些相似而且繁琐的过程:通过调用
API
设置渲染状态;通过调用
API
传送几何体信息;通过调用
API
通知
GPU
渲染;清理;返回到第一步,直到渲染完一帧进入下一帧。这个过程会让你陷入纷杂的
API
操作之中,相对于真正的应用,可能你会被浪费在基本的几何体操作中去。
如果使用面向对象的方法来渲染几何体,就可以从几何体级别的处理工作中抽离出来,转而处理具体的场景和在场景中的物体。
其中的物体包括:可活动的物体、静态物体组成的场景本身、灯光、摄像机以及其他
。你只需简单的把物体放到场景之中,
Ogre
会帮助你完成杂乱的几何渲染处理,从而脱离对调用
API
的
依赖。而且你也可以通过简单的方法来操作场景中的物体来代替矩阵变换:例如,可以简单的通过角度或者弧度来控制物体在不同空间内旋转(包括本地空间、世界
空间和父节点空间),而不必要通过矩阵的变换这种抽象的方法来操作实现变换。简而言之,面向对象让你可以处理更具象的物体、属性和方法。而不用处理抽象的
顶点列表、三角形列表、旋转矩阵等底层概念。
Ogre
的面向对象框架提供了包括全部渲染过程的对象模型。渲染系统
(
Render system
)把复杂且不同的底层
API
(比如
OpenGL
和
Direct3D
)的功能抽象成一个统一的操作接口;场景图
(
Scene graph
)也被抽象成为另外的一组接口,并且允许使用不同的场景管理算法实现“即插即用”的效果;所有可渲染(
Renderable
)对象
,不论是动态还是静态,都被抽象出一组接口,用来被具体的渲染操作调用,比如技术(
Technique
)和其中的通路(
Pass
);可活动对象
提供了一组通用接口接受各种各样的操作方法。
Ogre
做到了场景图与场景内容的分离
。首先,
Ogre
对场景图的操作维持在接口级别;它并不关心去操作图形的具体算法实现。换言之,
Ogre
只是通过信号(它们的方法)来操作场景图,进而忽略了具体的算法实现。其次,
Ogre
的场景图接口只负责维护场景结构。节点中没有包含任何固有的内容和管理方法
。具体的内容被放置到一种可渲染(
Renderable
)对象之中
,它提供了场景中全部几何图形(包括活动的的或者其他所有的)。它们的渲染的属性(也可以说是材质)被包含在实体(
Entity
)对象中,在实体对象里面同样包含着一个或多个子实体(
SubEntity
)对象,这些子实体才是是真正可以被渲染对象
。
场景管理器可以帮助你创建具体的场景节点(
Scene Node
)。所谓的场景节点
就是你在场景中实际移动变换的基本单元。场景中具体的场景内容
需要挂接到场景节点上才能显示。这里所说的内容在大多数情况下指的就是实体
(
Entity
)。实体继承于活动对象(
MovableObject
),并通过场景管理器来进行创建。如果你有已经有一个的实体的具体实例,你就可以把它绑定到已经存在的场景节点上。基本上实体都是从硬盘上的“
.mesh
”文件载入的模型来构建。当场景内容挂接到场景节点之后,你就可以通过场景节点来管理实体了,注意,是变换场景节点,而不是场景内容
。
其中活动对象(
MobeableObject
)可以直接操作所有几何体和渲染属性
。
它并不是场景节点的子类,而是挂接到场景节点中(可以理解为通过组合代替继承)。这意味着如果你需要,程序中的场景节点可以不用了解与之相关的可渲染对象
的任何细节。也意味着你可以扩展,改变,重写,或者其他改变场景图的实现,而不会影响场景内容接口的设计和实现;他们彻底独立于场景图。场景图甚至可以完
全修改而不会影响任何内容类。
反过来说也同样适用:场景图同样不需要对所挂接的场景内容节点有任何了解,只要通过所用的接口来通知就可以完成所需要的功能。因为这些出色的设计,
Ogre
甚至可以完成对“用户自定义(
user-defined
)”内容节点的挂接。如果你决定构造一个拥有环绕立体声的场景,你可以把各种音效实现自定义节点,然后无缝的挂接到场景中。自定义的场景节点只需要实现一个简单的接口,就可以把定制数据挂接到场景中任意的节点上。
可扩展性强的插件体系。
举例来说,
Ogre
在接口层来管理场景图的实现,这样就意味着用户没有被限制在一定要使用哪几种场景管理算法的局限内。用户可以把任何自己程序需要的场景算法“插入”到
Ogre
程序库中,并且它们可以和
Ogre
本身提供的算法一样的良好的工作。如果在某个程序中需要
KD-Tree
场景算法的支持,你只要简单的按照
Ogre
定义的接口实现一个
KD-Tree
场景图的算法,并把它插入到你的
Ogre
程序中就能很好的使用了。
灵活的渲染队列。
Ogre
采用了“场景队列”。这是一个容易理解的概念:
Ogre
将需要渲染的内容分别放在多个有序队列之中,并且队列之间也是有自己的顺序,
Ogre
分别渲染每个队列。
健壮的材质系统。
Ogre
的材质是由一个或者多个渲染技术(
Technique
)组成,每个技术中又含有多个渲染通路(
Pass
)。这种通路指的是一个单独的渲染通道,它是
Ogre
材质渲染中的一个基本单元。换句话说,对象的每一个渲染通路将导致一次对图形硬件的绘图调用。
独有的模型和骨骼文件格式
(*.mesh
和
*.skeleton)
。
Ogre
使用了自己独有的模型和骨骼数据格式。这也等于告诉你
Ogre
无法直接使用其他第三方的模型格式,例如商业游戏中的模型。如果你使用二进制格式来保存模型和骨骼数据文件,
Ogre
可以快速高效的载这些数据。这些二进制文件可以通过外部导出器或者离线工具(命令行
OgreXMLConverter
工具,在附录
A
讨论)来生成。当然,如果你愿意,
OgreXMLConverter
工具内部的类是允许在你自己的应用程序中使用的(假如你想从
3D
模型包中导出模型数据到二进制文件)。通常有一种普遍的创建二进制模型和骨骼文件的方法,先把场景或者角色模型数据从
3D
工具中转换到中间格式——可读的
XML
格式(
Ogre XML
),然后再通过命令行工具转换这个数据到二进制。
Ogre
官方网站上提供了当前大多数
3D
模型工具(包括商业和开源)的导出文件插件。其中包括
Softimage|XSI
、
Autodesk 3D Studio Max
、
Maya
和
Blender
(还有很多没有在这里列举出来,你可以到
Ogre
官方网站上去查看详细列表)。
Ogre
支持三种动画方式:骨骼动画(
Skeletal
)、变形动画(
Morph
)以及姿态动画(
Pose
)。骨骼动画
是通过把顶点绑定到骨骼的骨头(
Bone
)
上来实现的(也被称为矩阵调色蒙皮技术,或简称为蒙皮技术)。在物体上的每个顶点都可以同时被四块独立的骨头影响,影响的具体力度取决于顶点对每块骨头分
配的权重,当骨骼运动的时候,所有被它影响的顶点都根据骨头的位置和权重来更新自身的位置。这种算法可以模拟很多现实的顶点位移,例如可以很好的模拟在移
动的胳膊的时候肩膀的外型的变化(更确切地说,因为当胳膊抬起的时候肩膀相应的肌肉会收缩)。目前
Ogre
还只能支持关键帧形式的正向动力学(
FK
)骨骼动画;也就是说没有提供对逆向动力学(
IK
)骨骼动画的内建支持;如果你的美工在
3D
模型工具中使用了逆向动力学产生相应的动画,这时候可以对骨骼每一帧进行采样来转换成正向动力学的骨骼动画。通常来说,这些工作都可以在导出插件中很好的完成。变形动画与姿态动画都属于顶点动画技术。变形动画
存储了顶点在每一关键帧的绝对位置,然后在运行时对两个位置进行相应的插值计算,因为多个顶点的绝对位置无法叠,所以多个变形动画之间无法相互混合成新的动画。而姿态动画
的不同之处在于它储存的是顶点的相对位置,因此多个姿态动画的轨迹可被混合起来,进而创建出更复杂的顶点动画。不过上面两种类型的动画都可以与骨骼动画很好的混合使用。
合成器框架(
Compositor framework
)
是
Ogre
新加入的一个特性,它允许用户在视口(
Viewport
)级别实现全屏的二维后处理(
Postprocessing
)特效
。例如,你可以把视口中全屏的内容实现的发光或者朦胧处理、黑白渲染、锐化边缘渲染。任何你能想象的对整个视口的操作都可以在合成器框架中实现。
资源
在
Ogre
中的定义是“所有渲染几何体到渲染目标的数据所需要的数据”。这不仅包含模型
,骨骼
,材质
,还包含表层
(
Ovelary
)脚本和字体
,以及有材质处理所需要的一些资源,比如合成器框架
脚本、
GPU
程序
和纹理
。
Root
对象是一个
Ogre
应用程序的主入口点。
因为它是整个
Ogre
引擎的外观(
Façade
)类(请参考设计模式中的外观模式),所以在这里作为第一个被列出来的类,它提供了方便的调用整个
Ogre
每个子系统的接口。通过
Root
对象来开启和停止
Ogre
是最简单的一种方式;当你构造构造一个
Root
实例的时候你就启动了整个
Ogre
,当析构的时候(让它停止活动或者执行
delete
删除它)
Ogre
也就关闭了。
资源管理器
:
OGRE
中的资源类型包括模型(
Mesh
)
,
骨骼(
Skeleton
)
,
材质脚本(
Material
)
,GPU
程序
,
纹理(
Texture
)
,
合成器脚本(
Compositor
)
,
字体信息(
Font
)等。
一般来说,开发者没有必要直接对渲染系统(
RenderSystem
)
进行操作。因为渲染系统是
Ogre
对底层硬件
API
(
OpenGL
或者
Direct3D
)的一层抽象。尽管如此,你还是至少要了解渲染系统所创建的一个对象类型,即渲染目标(
RenderTarget
)
类。它是对
Ogre
中两个重要概念的概括抽象:渲染到窗口和渲染到纹理
。
OGRE
初始化:
Root * root = new Root(“plugins.cfg”, “ogre.cfg”, “ogre.log”);
bool rtn = root->showConfigDialog();
root->initialise(true, ”My Render Window”);
RenderWindow * window =root->getAutoCreatedWindow (); //
创建
render window
root->addFrameListener(myListener); //
添加帧监听
root->startRendering(); //
开始
render
循环
plugins.cfg
文件:
Ogre
中所谓的插件就是符合
Ogre
插件接口的代码模块(在
Windows
下面是
DLL
文件,在
Linux
下是
.so
文件),比如场景管理(
SceneManager
)插件和渲染系统(
RenderSystem
)插件等。在启动的
Ogre
时候,他会载入
plugins.cfg
配置文件来查看有哪些插件可以被使用。
Ogre.cfg
文件:在启动
Ogre
的时候,引擎提供了一个简单的图形界面,可以通过它来配置基本的渲染属性。该配置文件和那个图形界面功能是一样的。
Ogre
渲染窗口的概念是唯一可以被系统用来渲染场景的地方。就如同现实世界中的画布一样,
Ogre
把你程序的内容画到它的表面。为了实现这个目的,
Ogre
至少需要一个摄影机(
Camera
)
来“拍摄”你的场景,同时也需要一个或几个视口(
Viewport
)
,用于存放摄影机的拍摄下来的“胶片”(和渲染窗口的功能有些类似)。
在调用
startRendering()
之后,
Ogre
就会不断地渲染在你场景中所有能被渲染的东西。你可以通过关闭渲染窗口来结束这个过程(比如单击窗口右上角的
x
图标,或者在
Windows
任务栏中右键菜单中选择关闭)。当你在注册了帧监听(
Frame Listener
,之后会介绍)对象,然后在回调结束后返回一个
false
值给系统,同样也能结束程序渲染。作为备用,
Ogre
还提供了一个可以在程序的任何地方调用的方法
Root::getSingleton().queueEndRendering()
来立刻结束程序。不过在使用
startRendering()
进行渲染的时候,最常用的办法还是在帧监听中返回
false
。
场景管理器所做的工作:
在通常的情况下,
Ogre
的场景管理器会负责处理以下事情:
·在场景中创建和放置活动物体、灯光以及摄像机,并维护他们的在场景图中的周游和变换。
·载入和布置世界地图(
World geometry
,与活动实体不同,世界地图是巨大且可以延伸的,通常情况下是不可移动的,比如一个完整的
BSP
地图)。
·对场景查询(
Scene Queries
)的支持,比如回答“在世界的某个原型空间内,都包含了那些物体”。
·剔除不可见物体并且将可见物体放入渲染队列。
·根据当前和渲染物体的透视图,对无方向的光源(
Nondirectional Light
)进行组织和排序(按由近到远)。
·设置并且渲染场景中的阴影。
·渲染场景中的其他物体,如背景和天空盒
·发送组织好的内容到渲染系统执行渲染
Ogre
自身提供两个场景管理器类型
:
OctreeSceneManager
和
TerrainSceneManager
。
OctreeSceneManager
是一个通用的场景管理器。
TerrainSceneManager
是一个为高度场场景优化的场景管理器。
对于程序的开发者而言,场景管理器的直接用途一般是用来创建场景中所使用的对象
,比如:灯光、摄影机、实体、粒子系统以及公告栏这些活动物体,以及天空盒、静态几何体和世界地图(
World geometry
)这些非活动物体。对于场景中存在的物体,不论是否能被渲染,都会交给场景管理器进行具体的管理工作。
场景管理器用场景节点
来
定义场景图的结构。这些场景节点以层次的结构组织在场景管理器中:一个场景节点可以有一个父节点和任意数量的子节点。你可以对场景管理器中的节点进行绑定
或者摘除操作;这里提供一个简单的办法来关闭场景中的某个部分:只要把不希望渲染部分的根节点从场景图中摘除下来,这个部分就不会被渲染了。场景节点必须
通过创建它们的场景管理器来销毁。
创建实体
并进行移动、旋转、缩放:先创建
Entity
,然后
attach
到场景节点,然后对场景节点进行移动、旋转、缩放
(translate, rotate/yaw/pitch/roll, scale
)(
注意:
rotate
是可以沿任意轴旋转,
yaw/pitch/roll
分别只是沿着
x/y/z
三个轴旋转
)
。
场景管理起另外一个很重要的功用就是用来进行空间场景查询
(从场景中得到查询的反馈信息),其中包括:光线查询(
Ray Queries
)、球体查询(
Sphere Queries
)、边界盒查询(
Bounding-Box Queries
)、边界平面查询(
Bounding-Plane Queries
)以及相交查询(
Intersection Queries
)。其中光线查询
返回与给定光线(空间中两点组成的虚拟线)相交的物体信息;球体查询
返回给定球体(通过球中点和半径确定的空间区域)中所有包含的物体信息;边界盒查询
返回给定轴向包围盒(通过两个三维向量作为对角点产生的与空间轴平行的长方体空间)中所包含的物体信息;边界平面查询
返回与给定的无限延伸的平面相交物体的信息;相交查询
返回与指定物体相交的所有物体信息。所有的查询过程都是可进行屏蔽操作
的(
Maskable
),这意味着你可以通过这个功能过滤到你不需要的对象。
多个坐标系,坐标系方向如下:
动画
:
Ogre
有两种不同的操作动画对象的方法,一种是通过关键帧,另外一种是通过控制器。关键帧之间的是动画轨迹。
Ogre
支持下面几种动画轨迹类型(在同一轨迹中的所有关键帧必须使用相同类型):
•数字动画轨迹
(
NumericAnimationTrack
):与数字关键帧
(
NumericKeyFrame
)对应,每个关键帧中都保存了相应的数字数据。这里使用了
AnyNumeric
数据类型来保存这些数值。在
Ogre
自身有一种特殊的数据结构被称为
Any
,它很类似动态语言中的可变类型,可以用来储存各种
C++
类型的数据。
AnyNumeric
是
Any
的子类,负责储存各种数值类型,比如实数和整形。
•节点动画轨迹
(
NodeAnimationTrack
):与变换关键帧
(
TransformKeyFrame
)对应,每个关键帧都包含了两个三元向量和一个四元数,分别用来表现节点在当前帧的位置、缩放以及方向。
•顶点动画轨迹
(
VertexAnimationTrack
):同时对应于顶点变形关键帧
(
VertexMorphKeyFrame
)和顶点姿态关键帧(
VertexPoseKeyFrame
),每个关键帧都保存了特定时间的顶点位置数据,在姿态动画(
Pose
)中还保存了顶点混合权重。
你的应用程序控制
Ogre
中动画的的主要途径
就是“动画状态
(Animation State)
”,
在
代码中你可以通过这些名字来调用实体中的某个动画部分,而物体则返回相应的动画状态以供你使用。其中包括以下动画属性:
•长度
:以秒为单位,获得动画片段的长度。
•当前位置
:得到或者设置当前播放的位置,换句话说是从动画片段(而不是整个动画)开始到当前位置所流逝的时间(秒)。
•动画名称
:尽管你可以通过物体本身得到所有的动画列表,这里仍然提供只读属性的动画名称用来在不知道动画名字情况下调用。
•循环
:设置或者得到在动画片段结束后是否循环播放。
•启用
:设置或者得到这个动画是否启用。
•权重
:动画可以被混合(但有相应的一些限制,在后面介绍)。这个属性可以设置或者得到当动画与其他动画混合的时候的影响的权重。
代码绘制图形或者模型可以使用
:
ManualObject
类。
转载自:https://blog.csdn.net/baozi3026/article/details/5414072