irrlicht是跨平台,支持多种图形库的开源3d引擎。irrlicht的设计很好的体现了接口和实现分离的原则,整个框架设计精巧清晰,是学习3d引擎设计的不错的教材。
先看下名字空间的划分,可以看到irr具有非常清晰的结构:
irr | Everything in the Irrlicht Engine can be found in this namespace |
irr::core | In this namespace can be found basic classes like vectors, planes, arrays, lists and so on |
irr::gui | The gui namespace contains useful classes for easy creation of a graphical user interface |
irr::io |
|
irr::scene |
|
irr::scene::quake3 |
|
irr::video | The video namespace contains classes for accessing the video driver. All 2d and 3d rendering is done here |
irr空间中提供了引擎的一些底层构架的支持,如事件处理系统,操作系统抽象,引用计数,设备抽象等。
irr::core空间中提供了基础的数学和数据结构构件,如向量,矩阵,四元数,列表,数组,红黑树等。
irr::io空间提供了io操作的构件并提供对象属性序列化和xml支持。
irr::video空间包含了3d图形功能接口和构件。如对图形驱动,材质渲染的抽象。
irr::scene空间包含了基于scene graph的3d引擎渲染和管理,并提供了camera,骨骼动画,粒子系统等的丰富支持。
irr::gui空间包含了irrlicht的GUI模块,同样也是基于接口的设计。
我 想重点剖析的是irr::video和irr::scene,这是3d引擎的核心部分,目的是分析irrlicht是如何将不同的图形API进行抽象的, 以及如何使用scene graph-material体系进行引擎的运转,并将各种3d技术融入到这个体系中的。另外irr如何做到跨平台支持的也会进行剖析。
作为引擎的概览,首先看下文档中的short example:
IrrlichtDevice *device =
createDevice
(
video::EDT_DIRECT3D8
, core::dimension2d(640,480)); video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* scenemgr = device->getSceneManager();
这三句代码显示了irrlicht最基本的三个对象-设备,图形驱动和场景管理器。简单看来,通过全局函数createDevice根据指定的驱动类型创建一个设备,之后可通过设备对象得到驱动对象以及场景管理器对象。
device->setWindowCaption(L
"Hello World!"
);
设备对象具有一些设备相关的能力,比如这儿可以设置窗口标题。
// load and show quake2 .md2 model
scene::ISceneNode* node=scenemgr->addAnimatedMeshSceneNode(scenemgr->getMesh(
"quake2model.md2"
));
// if everything worked, add a texture and disable lighting
if
(node)
{
node->setMaterialTexture(0, driver->getTexture(
"texture.bmp"
));
node->setMaterialFlag(
video::EMF_LIGHTING
,
false
);
}
// add a first person shooter style user controlled camera
scenemgr->addCameraSceneNodeFPS();
这几行代码显示了scene graph体系,ISceneNode是irrlicht场景中基础组成部分节点的抽象,这儿添加了一个动画mesh节点,和一个camera节点。节点 具有材质属性(当然camera并不需要材质,但是ISceneNode作为一个抽象要尽量兼顾各种节点,为了让接口的层次简单些,这样做也是一个实用的 方法)
// draw everything
while
(device->run() && driver)
{
driver->beginScene(
true
,
true
, video::SColor(255,0,0,255));
scenemgr->drawAll();
driver->endScene();
}
这几行是引擎运转的过程,首先引擎运转的条件是设备仍然在运转:device->run(),可通过closeDevice关闭设备。 scenemgr->drawAll()执行了所有节点的渲染,节点的渲染不仅仅是draw,节点的transform计算,动画计算(包括骨骼动 画),camera这种特殊节点的操作(特殊的节点还有光源等),都包含在渲染的范畴中,在drawAll中统一调用,各种节点实现各自的渲染,最终由 scenemgr统一管理(如排序)绘制,这正是基于scene graph架构的引擎的特点之一。
device->drop();
这一句体现了irrlicht的引用计数机制,通过grab,drop管理对象引用次数。这儿如果一切正常应该是引用drop为0,device销毁自己,退出程序。
从 这个很短的例子可以看到irrlicht的基本构件和运行过程。irrlicht提供了scene的管理机制,并提供了大量预定义好的scene nodes,实现了很多的功能,这样你就可以很方便的使用引擎。并且这种机制的好处是,节点可以不断的扩展,并可以在以后的项目中复用。
当然,irrlicht引擎不是完美的,我准备在这个源码剖析的系列的最后,分析一下irrlicht的一些具体问题和不足,当然作为一个开源引擎,irrlicht已经非常好了,我的主要目的正是通过分析学习irrlicht给自己设计3d引擎打一个基础。