用C++实现跨平台游戏开发之Irrlicht引擎
Irrlicht引擎是一个用C++书写的高性能实时的3D引擎,可以应用于C++程序或者.NET语言中。通过使用Direct3D(Windows平台),OpenGL 1.2或它自己的软件着色程序,可以实现该引擎的完全跨平台。
尽管是开源的,该Irrlicht库提供了可以在商业级的3D引擎上具有的艺术特性,例如动态的阴影,粒子系统,角色动画,室内和室外技术以及碰撞检测等(见图1)。
Irrlicht 3D引擎
Irrlicht是一个德国神话故事中的一种动物的名字,它能够发光和飞翔,可以在大部分的沼泽地附近发现它。单词”Irrlicht”是两个德国单词(”irr”意思是疯狂的;而”Licht”意思是光)的组合。在英语中,它被译为”鬼火”。
Irrlicht十分幸运地为一个巨大的活跃的开发团队以大量的工程所支持。然而,因为Irrlicht主要由游戏名家Nikolaus Gebhardt所设计,所以该游戏在设计上十分连贯。你可以在网上到处发现有Irrlicht的增强程序,如可选用的地形生成器,入口生成器,输出器,world层生成器,相关教程和编辑器等。而且,它独立地创建了到Java,Perl,Ruby,BASIC,Python,LUA甚至更多种语言的绑定。而最为重要的是,它是完全自由的。
Irrlicht特性
在深入分析API之前,请让我更具体地介绍一下Irrlicht提供给了3D游戏开发者哪些功能:
- 一个可以运行于Linux以及Windows 98,ME,NT,2000和XP(MacOS在计划之中)等操作系统之上的引擎
- 针对Direct3D 8生成器或Direct3D 9生成器(可选)提供了Anti-aliasing支持
- 可换肤的GUI环境(包括一个很酷的具有金属质地的带阴影的皮肤),给一些老式的对话框加上漂亮的外观
- 场景管理系统,它允许无缝的室内/室外过渡
- 角色动画系统,带有骨骼和变形目标动画功能
- 一个特殊的效果系统,包括粒子效果(雨,烟,火,雪,等等),告示板,灯光贴图,环境,地图,模板缓冲区阴影,雾,纹理动画,视差贴图,凹凸贴图,还有更多
- 内建的材质支持,包括支持Pixel and Vertex Shaders版本1.1到3.0,ARB Fragment and Vertex程序以及HLSL(GLSL正在计划中)
- .NET语言绑定,这使得引擎可用于所有的.NET语言例如C#,Visual Basic.NET以及Delphi.NET
- 一内建的平台独立的软件生成器,特性有:z-缓冲,Gouraud阴影,alpha混合和透明性,还有快速的2D绘图(见图2)
- 你久已期待的2D绘图功能,例如alpha混合,基于关键色的位图复制,字体绘制,以及混合3D与2D图形
- 能直接导入常见的建模文件格式:Maya,3DStudio Max,COLLADA,DeleD,Milkshape,Quake 3 levels,Quake2 models,DirectX,Pulsar,My3DTools,FSRad以及Cartography Shop
- 能直接从BMP,PNG,Photoshop,JPEG,Targa和PCX导入纹理
- 快速而易用的碰撞检测与响应
- 为快速的3D运算和容器模板库进行了优化处理
- 直接读取档案(可能是压缩的,如.zip文件)
- 集成了快速的XML分析器
在Irrlicht中的特殊效果
在本文的例子中,我将向你展示怎样使用模板缓冲区影子技术,还有粒子系统,告示板,动态光以及水表面场景结点等技术。参见图3。
Irrlicht引擎自动地检查是否你的硬件支持模板缓冲;而如果不支持,则不启动阴影。在这个演示程序中,在方法createDevice()中的’shadows’标志被置位,以产生从一个动画角色投下的动态影子。如果这个实例程序在你的PC上运行太慢,可以把这个标志设置为false或者干脆再买一块更好些的图形加速卡。
为能够使用Irrlicht.DLL文件,你需要链接到Irrlicht.lib库文件。你可以在工程设置对话框中设置这个选项;但是为了容易实现,你可以使用一个pragma预编译注释命令。方法createDevice()负责实例化根对象-它使用引擎完成一切事情。参数如下:
- deviceType:设备类型。当前你可选取Null设备以及软设备,如DirectX8,DirectX9或OpenGL。
- windowSize:要创建的窗口的大小或全屏幕模式。这个例子中使用512x384。
- bits:每像素位数(当在全屏幕情况时)。仅允许值为16或者32。
- fullscreen:指定是否你想使设备运行于全屏幕方式。
- stencilbuffer:指定是否你想使用模板缓冲区以用于绘制阴影。
- vsync:指定是否你想启动vsync(仅在全屏幕情况),可选。
- eventReceiver:一个接收事件的对象,可选。
为适合于本实例环境,你将装载一个3D Studio Max文件(一幢房子)。该房子看起来并没有什么特别的,但是Irrlicht引擎能为你创建一个相当酷的纹理贴图。只需使用造型操纵器并为之创建一个planar纹理贴图即可:
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
int main()
{
//让我们假定用户在本例中使用OpenGL
//当然,也可以指定DirectX 8, 9, 等等.
video::E_DRIVER_TYPE driverType = video::EDT_OPENGL;
//创建设备,如果创建失败立即退出。
IrrlichtDevice *device = createDevice(driverType,
core::dimension2d(640, 480), 16, false, true);
if (device == 0)
return 1;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
}
我对从这个导入文件产生的发射光线颜色的效果并不满意。下列代码显示怎样实现这些步骤:
scene::IAnimatedMesh* mesh = smgr->getMesh("room.3ds");
smgr->getMeshManipulator()->makePlanarTextureMapping(
mesh->getMesh(0), 0.008f);
scene::ISceneNode* node = 0;
node = smgr->addAnimatedMeshSceneNode(mesh);
node->setMaterialTexture(0, driver->getTexture("wall.jpg"));
node->getMaterial(0).EmissiveColor.set(0,0,0,0);
你将添加的第一个特殊的效果是水动画。为此,WaterSurfaceSceneNode导入一个造型文件并使之象水表面一样地波动。如果你让这个场景结点使用一种相当好的材质如MT_REFLECTION_2_LAYER,那么它看起来相当酷:
mesh = smgr->addHillPlaneMesh("myHill",
core::dimension2d(20,20),
core::dimension2d(40,40), 0, 0,
core::dimension2d(0,0),
core::dimension2d(10,10));
node = smgr->addWaterSurfaceSceneNode(mesh->getMesh(0),3,300,30);
node->setPosition(core::vector3df(0,7,0));
node->setMaterialTexture(0,driver->getTexture("water.jpg"));
node->setMaterialTexture(1,driver->getTexture("stones.jpg"));
node->setMaterialType(video::EMT_REFLECTION_2_LAYER);
作为输入造型,你可以创建一个陡峭的平面造型,但是你也可以为此使用任何其它的造型。你甚至能重用room.3ds输入文件(它看上去确实很奇怪)。该实例还用一个普通的石头纹理模型来绘制所有另外的表面。
透明的告示板和灯光
第二个特殊的效果是很基本的但是非常有用:一个透明的告示板,伴之有一个动态的灯光。为产生这种效果,你只需要产生一个灯光场景结点,并让它四处飞行;而且,为了让它看起来更酷一些,可以把一个告示板场景结点依附到它上面:
//创建灯光
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();
// 把告示板依附到灯光
node = smgr->addBillboardSceneNode(node, core::dimension2d(50, 50));
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR);
node->setMaterialTexture(0,driver->getTexture("particlewhite.bmp"));
粒子系统
下面介绍的这个特别效果更有趣:一个粒子系统。在Irrlicht引擎中,粒子系统既是组件化的,也是可扩展的,但是仍然易于使用。你只需要简单地把粒子发射器放到一个粒子系统场景结点,这样以来粒子看上去没有产生源。这些发射器可以据需要进行灵活配置,并经常带有许多参数,如粒子方向,粒子数量,以及粒子颜色等。
当然,发射器类型有区别(例如,一个点发射器能够使粒子从一个固定的点上发出粒子)。如果该引擎提供的粒子发射器还不能满足你的要求,你可以容易地创建你自己的发射器。这只需简单地从IParticleEmitter接口派生一个新类并使用setEmitter()方法把它依附到粒子系统上去即可。
下一个实例将创建一个盒子粒子发射器。你可能已经猜出,它从一个跳跃的盒中随机生成粒子。由参数来定义盒子,粒子的方向,每秒产生粒子的最小和最大数目,颜色以及粒子的最小和最大生命周期。
一个完全由发射器组成的粒子系统将是令人生厌的,因为缺乏真实感。因此,Irrlicht支持粒子影响器-它负责在粒子到处飞扬时予以修整。一旦添加到粒子系统上,它们就能模仿另外的更真实的效果,象重力或风。在本例中的粒子影响器只是简单地修改粒子的颜色来产生一种淡出效果。
可能你已经猜出,粒子影响器是通过派生IParticleAffector接口实现的,然后通过使用addAffector()方法把它添加到粒子系统上去。在你为该粒子系统设置了一种好看的材质后,你就有了一个看上去相当酷的野外宿营火的效果。通过调整材质,纹理,粒子发射器,还有影响器参数,你能容易地创建烟雾,下雨,爆炸,下雪等效果:
scene::IParticleSystemSceneNode* ps = 0;
ps = smgr->addParticleSystemSceneNode(false);
ps->setPosition(core::vector3df(-70,60,40));
ps->setScale(core::vector3df(2,2,2));
ps->setParticleSize(core::dimension2d(20.0f, 10.0f));
scene::IParticleEmitter* em = ps->createBoxEmitter(
core::aabbox3d(-7,0,-7,7,1,7),
core::vector3df(0.0f,0.03f,0.0f),
80,100,
video::SColor(0,255,255,255), video::SColor(0,255,255,255),
800,2000);
ps->setEmitter(em);
em->drop();
scene::IParticleAffector* paf =ps->createFadeOutParticleAffector();
ps->addAffector(paf);
paf->drop();
ps->setMaterialFlag(video::EMF_LIGHTING, false);
ps->setMaterialTexture(0, driver->getTexture,"particle.bmp"));
ps->setMaterialType(video::EMT_TRANSPARENT_VERTEX_ALPHA);
影子投射
最后但也不容忽视一个问题是,你需要为一个动画角色产生一个动态的影子。为此,你装载一个Quake2.md2模型文件并把它放到你的world上去。为了创建影子,你只需要调用方法addShadowVolumeSceneNode()。你可能通过调用ISceneManager::setShadowColor()来控制影子的颜色;注意,这仅是全局可调整的,并影响所有的影子。好,下面就是你的产生动态影子效果的代码:
mesh = smgr->getMesh("../../media/faerie.md2");
scene::IAnimatedMeshSceneNode* anode = 0;
anode = smgr->addAnimatedMeshSceneNode(mesh);
anode->setPosition(core::vector3df(-50,45,-60));
anode->setMD2Animation(scene::EMAT_STAND);
anode->setMaterialTexture(0, driver->getTexture("../../media/Faerie5.BMP"));
anode->addShadowVolumeSceneNode();
smgr->setShadowColor(video::SColor(220,0,0,0));
游戏循环
最后,你能进入由device->run()方法控制的游戏循环。该循环将不断运行,直到通过获取一个关闭窗口事件(例如在Windows操作系统下的ALT-F4击键)来退出设备。你必须在一个beginScene()和endScene()命令对之间绘制每样东西。beginScene()用指定的一种颜色清屏,如果需要的话,可以同时清除深度缓冲区。然后你就可以让场景管理器和GUI环境来绘制它们的内容。随着调用endScene(),每一样东西都被绘制到屏幕上去。在本例中,你还可以动态地在标题栏上显示帧每秒(FPS)数,这对于严肃的游戏开发者是十分重要的事情:
scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS();
camera->setPosition(core::vector3df(-50,50,-150));
int lastFPS = -1;
while(device->run())
{
driver->beginScene(true, true, 0);
smgr->drawAll();
driver->endScene();
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Campfire FX example [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
结束循环后,你必须删除先前用createDevice()方法创建的Irrlicht设备。通过使用Irrlicht引擎,你应该删除所有你用以’create’开头的方法或函数创建的所有对象。你可以通过简单地调用device->drop()来删除该设备对象。
你可能喜欢的Irrlicht插件
正如在前面所介绍的,Irrlicht有一群勤奋的独立开发人员并为之产生了大量的插件,也用之开发了相当多的游戏。这些开发者中提出的许多的改进被再次集成到Irrlicht的随后的发行版本中。下面我列举其中的几个例子,我想这会吸引许多颇有前程的开发者感兴趣:
- OCTTools,是一套用于Irrlicht的工具,由Murphy McCauley所创建,用于操作OCT文件相关的:输出器,加载器,甚至更多。
- ICE(Irrlicht通用引擎)是一个开发框架,它提供了一个工程的轮廓实现,从而加快了新工程的开发。
- MIM,由Murphy McCauley所创建,是一个非常有用的基于XML的文件格式,可用于Irrlicht的加载器,转换器及其各种工具。
- My3D是一个开发工具包,它能够使你把来自于各种3D包(3DStudio MAX,Giles,等等)中的灯光贴图场景直接输出到Irrlicht中。
- Dusty引擎允许程序员创建”任务”-这些”任务”可以完成程序员想做的任何事情。之后,这些任务被添加到一棵普通的任务树上去,而每个任务可以有它们希望数目的孩子任务。任务”组”允许游戏设计者在一棵完整的树上执行普通的操作,例如暂停,继续或破坏等。
- Irrlicht RPG(Erring Light)是一个3D 绕行走游戏引擎,最初是针对RPG类游戏开发的。
- 2D 图像和精灵类组成了一个很有用的库,它扩展了Irrlicht的2D能力。
- Zenprogramming站点,提供第一个针对Irrlicht的非正式的外部地形生成器,此处也提供很多相关的教程。
Trackback: http://tb.donews.net/TrackBack.aspx?PostId=737442