您的位置:首页 > 其它

Irrlicht游戏引擎初步分析与研究

2011-12-23 10:18 323 查看
Irrlicht游戏引擎主要是由一个名叫Nikolaus Gebhardt奥地利人所设计,是sourceforge上的一个开源项目,也是著名的开源游戏引擎。Irrlicht是一个德国神话故事中的一种动物的名字,它能够发光和飞翔,可以在大部分的沼泽地附近发现它。单词"Irrlicht"是两个德国单词("irr"意思是疯狂的;而"Licht"意思是光)的组合。在英语中,它被译为"鬼火"。该项目从2004开始一直至今。在这个网站上你能够找到它的源代码、文档以及更多的息:http://irrlicht.sourceforge.net/

 
主要技术特性

Irrlicht是一款由c++编写的3D游戏引擎,由于底层的代码封装良好,所以该引擎可以在多个平台上使用,如WINDOWS、LINUX等。

整个引擎使用了类COM的中间件封装技术,这确保了引擎的跨平台使用和可扩展性,也就是当引擎内部被修改,原游戏逻辑代码不用改一行代码也可正常使用,而当需要向引擎添加新的技术特性,只需要符合它的规范和接口就可以很轻易的加入新的特性。

所有的类均可实现serializing和dynamicly creating,这个特性可以将运行时的引擎状态保存为文件,然后再从文件恢复引擎状态。

3D引擎的常见问题在于速度,而irr游戏引擎速度非常快。


引擎概览

先看下名字空间的划分,Irr总命名空间下有5个子命名空间,可以看到irr具有非常清晰的结构:

irr  Irrlicht引擎中的一切都在此命名空间下实现。除了它的5个子命名空间的内容之外,irr空间中提供了引擎的一些底层构架的支持,如事件处理系统,操作系统抽象,引用计数,设备抽象等。

irr::core 提供了基础的数学和数据结构构件,如向量,矩阵,列表,数组等等。

irr::gui 此命名空间包含了一些 创建一个简单的GUI所需的类

irr::io 此命名空间提供输入/输出的接口:读/写文件,访问zip文件等等

irr::scene 所有与场景管理相关的都可以在此命名空间中找到:camera, Mesh加载,像八叉树和广告牌之类特殊的场景结点,等等

irr::video 此命名空间包含访问图形驱动器的一些类,所有的2D和3D渲染都在此完成。它将d3d,Opengl等绘图的部分进行封装,与外部隔离起来。

引擎基本架构分析
引擎的基层是由一系列抽象类构成,这些抽象类给上层类提供了基本的接口,而整个引擎的基本架构均是由结构和抽象类搭建,而引擎在实现时只需实现所继承抽象类(#add,原为虚基类,不过此处是个错误的叫法,虚基类指的是虚拟继承中的基类,顶了天你能叫纯虚类--虽然也是错误的叫法,但跨越雷池一步便万劫不复,永不超生)的虚函数即可。

整个引擎架构构造的非常精巧,它既是面向对象编程的范例之作,也是c++语言使用的典范。由于作者还缺乏对该引擎透彻的理解,所以只能从大方向来谈谈这个引擎的架构。

整个引擎可分为初始化和系统模块、核心数据模块(core)、图形界面模块(gui)、输入输出模块(io)、场景管理模块(scene)以及显示模块(video)。该引擎并未包含声音系统,此引擎的声音系统由额外的声音插件irrKlang提供。

初始化和系统模块:

IUnknown类是大多数类的基类,主要功能是提供引用计数和在DEBUG模式中提供类名。

ITimer提供时间对于游戏计时的访问和控制。(游戏计时对于游戏非常重要。)

IEventReceiver提供的接口可以用于接收消息,如鼠标、键盘消息或用户自定义消息。

IrrlichtDevice类是引擎的总管。通过调用createDevice函数后就会返回这个类的指针,从而获得引擎的控制权。IVideoDriver、IGUIEnvironment、ISceneManager、IFileSystem等重要类都会由它创建。

 
核心数据模块(core):

主要包括数组、向量、2D坐标、3D坐标和字符串等的存储及操作。

 
图形界面模块(gui):

Irrlicht引擎提供了图形界面接口,这使得游戏不需要另外挂载gui。Irrlicht引擎提供的gui接口也与操作系统无关,可以实现跨平台使用,但该gui接口所提供的功能有限,美观度不高,且在使用过程中出现过bug,曾导致整个系统崩溃,相信此bug是由于没有很好与windows平台相兼容造成。

 

首先它提供了基本的界面元素类(GUI Element)和它们的操作,如window, button, checkbox, editbox, listbox, scrollbar等。这些类均派生至IGUIElement类,IGUIElement提供了一般性的界面元素操作接口,如setVisible,move等。

IGUIElementFactory为gui提供动态创建的功能,它可基于名字和ID创建图形界面。

IGUIEnvironment类是整个图形界面模块的中枢所在,它负责添加、管理和绘制各种GUI element。当游戏需要绘制界面时,调用drawAll方法即可绘制所有界面。

 
输入输出模块(io):

这个模块为引擎提供了文件读写功能,集成了对zip文件的读写。这个模块还提供了一个速度很快的轻量级xml文件分析器,这个特性将在很大程度上方便游戏的开发,如识别RPG游戏脚本的识别,游戏场景的存储等。IFileSystem类负责协调和管理此类。

 
场景管理模块(scene):

场景管理是整个引擎的关键所在。它以场景节点(scene node)的形式管理所有画面,这些场景包括动画网格(animated mesh)、告示牌(bill board)、摄像机(camera)、网格(mesh)、粒子系统(particle system)和阴影(shadow volume)等。

这个模块还负责碰撞检测,它提供了一个简单易用的编程接口。

它主要由3大类族组成:

ISceneNode类族,都是继承于ISceneNode类的场景节点;

网格模型(mesh)类族,负责网格模型从文件导入到内存和网格的常规操作;还有一类动画型网格(animated mesh),这类类能够识别出具有动画帧的mesh模型,它支持的格式有b3d, md2, md3, x, ms3d和bsp。

ICameraSceneNode类能够接收消息,这样就能够通过鼠标和键盘控制游戏画面的切换。

ISceneManager类是这个模块的管家,它管理所有场景节点、网格模型资源、取景器和其他一切画面效果。

 
显示模块(video):

此模块主要提供操作显卡驱动的功能。

IVideoDriver类是这个模块的核心,当调用beginScene方法后即可开始绘制,调用endScene方法后即会渲染所要绘制的图像并将图像输出到显示器。

 

之前我曾经提到这个引擎采用了类似COM的封装。它将引擎的一切都进行了包装,只留出了接口。首先调用全局函数creatDevice,得到IrrlichtDevice类的一个实例指针,然后这个类会创建多个重要类的实例,如IVideoDriver、IGUIEnvironment、ISceneManager、IFileSystem。并且IrrlichtDevice类提供了访问这些类实例的指针。然后当需要访问这些实例时,使用这些指针进行访问即可。当需要访问其他类的时候都必须通过这些类来创建其他类实例和它们的指针来访问它们。并且在游戏逻辑中是不能出现这些类的实例的,因为提供的头文件也就是它们的接口被声明为纯虚函数,所有类都必须通过create**函数族来创建实例,而且用create**函数创建的类,在不使用时,都要调用drop函数来释放,不调用drop是不会释放实例所占用的资源;当要引用一个类的时候还要调用grab函数来增加对它的引用。之所以这样是因为引擎所管理的对象非常多,它并不清楚什么时候可以释放掉资源,一旦重复释放资源或遗漏释放资源均有可能造成引擎的崩溃。在每个由IUnknown类继承的子类都会有grab和drop函数,在其内部还会保持一个引用计数,当调用grab函数时就增加这个引用计数,当调用drop函数时就减少这个引用计数,当这个计数为0的时候就释放掉这个对象。

 
引擎基本特性的使用

 

典型用法:

这段代码是irr的典型使用,其他使用方法均是在此基础上形成,只不过加入了更复杂的控制逻辑。

 

#include <irrlicht.h>

using namespace irr;

 

 int main()

 {

        // 创建引擎

        IrrlichtDevice *device = createDevice(video::EDT_DIRECT3D8,

                core::dimension2d<s32>(640,480));

 

        video::IVideoDriver* driver = device->getVideoDriver();

        scene::ISceneManager* scenemgr = device->getSceneManager();

        // 载入quake2 .md2 模型

        scene::ISceneNode* node = scenemgr->addAnimatedMeshSceneNode(

                scenemgr->getMesh("quake2model.md2"));

 

        // 增加材质和发光效果

        if (node)

        {

                node->setMaterialTexture(0, driver->getTexture("texture.bmp"));

                node->setMaterialFlag(video::EMF_LIGHTING, false);

        }

 

        // 增加一个FPS取景器

        scenemgr->addCameraSceneNodeFPS();

 

        // 绘制一切,开始游戏循环

        while(device->run() && driver)

        {

                driver->beginScene(true, true, video::SColor(255,0,0,255));

                scenemgr->drawAll();

                driver->endScene();

        }

 

        // 退出引擎

        device->drop();

        return 0;

 }

 

碰撞检测:

游戏中使用得很平凡的可能就是碰撞检测了。

     scene::ITriangleSelector* selector = 0;

     if (q3node)

     {        

         q3node->setPosition(core::vector3df(-1350,-130,-1400));

         selector = smgr->createOctTreeTriangleSelector(q3levelmesh->getMesh(0), q3node, 128);

         q3node->setTriangleSelector(selector);

         selector->drop();

     }

     scene::ICameraSceneNode* camera = 

         smgr->addCameraSceneNodeFPS(0, 100.0f, 300.0f, -1, 0, 0, true);

     camera->setPosition(core::vector3df(-100,50,-150));

 

     // 这句是重点,它创建了一个检测器,并将它加到了camera节点上

     scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(

         selector, camera, core::vector3df(30,50,30),

         core::vector3df(0,-3,0), 

         core::vector3df(0,20,0));

     camera->addAnimator(anim);

     anim->drop();

 

特效使用:

一款游戏可能需要使用很多特效,这段代码用于创建一个环绕飞行的发光体。

 

     // 首先创建一个环绕飞行的灯光

     node = smgr->addLightSceneNode(0, core::vector3df(0,0,0),

         video::SColorf(1.0f, 0.6f, 0.7f, 1.0f), 600.0f);

     scene::ISceneNodeAnimator* anim = 0;

     anim = smgr->createFlyCircleAnimator (core::vector3df(0,150,0),250.0f);

     node->addAnimator(anim);

     anim->drop();

 

     // 然后将billboard特效贴到这个灯光上,billboard效果是创建一个使用贴图并且无论从哪个方向// 上看都相同的贴图,通常用于创造粒子特效。

     node = smgr->addBillboardSceneNode(node, core::dimension2d<f32>(50, 50));

     node->setMaterialFlag(video::EMF_LIGHTING, false);

     node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);

node->setMaterialTexture(0, driver->getTexture("http://www.cnblogs.com/media/particlewhite.bmp"));
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: