开源3D游戏引擎Irrlicht(鬼火)用法入门
赵刚
Irrlicht(中文名:鬼火)是著名的3D开源引擎之一,该3D引擎结构清晰,执行效率高,上手容易,无论是初学者学习3D游戏引擎,还是用来开发规模较小的3D应用都是很不错的选择。
本文以Irrlicht 1.7.2 版(目前的最新版)为例,讲解其在Windows系统中的用法。
首先需要在http://irrlicht.sourceforge.net/downloads.html 下载Irrlicht的SDK,1.7.2版的SDK尺寸为24.6MB,非常轻巧,几分钟内即可下载到本地。
SDK下载到本地后是一个名为irrlicht-1.7.2.zip文件,将该文件解压(可以右键点击zip在弹出菜单中选择“解压到当前文件夹”,如果装了WinRAR软件的话,得到一个名为irrlicht-1.7.2的目录,进入该目录得到以下结构:
在bin中Win32-VisualStudio目录已经包含了编译好的dll,当然如果需要对引擎做些修改的话就需要重新编译SDK生成dll,编译SDK非常容易,进入source目录下的Irrlicht目录,可以找到Visual Studio的解决方案文件,7.1版,8.0版,9.0版的都有,以使用VisualStudio 2008为例,可以双击Irrlicht9.0.sln文件打开解决方案。
解决方案在Visual Studio 2008 中的表现如下图:
可以试一下不修改任何代码直接生成解决方案,编译过程应该会顺利通过(会有一大堆warning C4819,可以不用理睬她们),完成后会在bin中的Win32-VisualStudio目录下找到一个新的irrlicht.dll。
如果编译过程中出现了fatalerror C1083: 无法打开包括文件:“d3dx9shader.h”这样的错误那说明你没有安装DirectX SDK,如果一定要用DirectX作为底层渲染API,那可以到
http://msdn.microsoft.com/zh-cn/directx/ 下载一个安装上,DirectX SDK尺寸很大500MB+,如果不是特别喜爱微软产品的话,可以不用DirectX SDK直接用OpenGL,但是编译前要告诉irrlicht,嗨!我不用DirectX呢,忽略它好不好!否则irrlicht会执着的报错,让你编译不成功。
怎么告诉irrlicht呢?很简单,
打开include目录下的IrrCompileConfig.h文件,
找到 #define_IRR_COMPILE_WITH_DIRECT3D_9_ 这一句,直接注释掉就可以了
再编译就能成功了,如果不成功,那非常不幸,我也不知道为什么,反正我编译过好几个版本,都能很顺利的编译出来,查查Visual Studio的问题吧。
其实编译成功了也没什么值得喜悦的,因为本来就是会编译成功的,如果你修改了引擎中的很多代码还能编译成功的话,那才值得喜悦一下。
如果想先看看irrlicht引擎的效果可以进入bin目录下的
Win32-VisualStudio目录里面有很多.exe文件,其中第一个是
01.HelloWorld.exe
双击运行,可以立刻看到下面的画面:
看起来是一个挺丑陋的画面,不过不用担心,这个画面不代表irrlicht的实力,只表示irrlicht在你的电脑上运行正常,要画面漂亮,提供漂亮的模型和纹理图片就好了。
还有很多其他demo都可以试一下,比如02.Quake3Map.exe
出来下面的画面,比HelloWorld画面美不少。
运行02.Quake3Map.exe的时候会先出来一个控制台窗口
选a就好了,表示使用OpenGL作为底层渲染API。
运行时鼠标会隐藏起来,这样你无法通过点击窗口上的“X”关闭窗口,要关闭运行窗口退出程序可以按下ALT+F4,这一招很灵。
一定想看看怎样用irrlicht写一个最简单的程序:HelloWorld!了,正好,irrlicht自己带着一个作为入门例子的HelloWorld,我们打开它看个究竟。
进examples目录看到01.HelloWorld目录,进去后双击
HelloWorld_vc9.vcproj即可打开HelloWorld工程,HelloWorld工程里只有一个main.cpp文件,文件内容如下(去除了英文注释):
#include <irrlicht.h>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
#ifdef _IRR_WINDOWS_
#pragma comment(lib, "Irrlicht.lib")
#pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")
#endif
int main()
{
IrrlichtDevice*device =
createDevice(video::EDT_SOFTWARE, dimension2d<u32>(640, 480),
16,false, false, false, 0);
if (!device)
return 1;
device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");
IVideoDriver*driver = device->getVideoDriver();
ISceneManager*smgr = device->getSceneManager();
IGUIEnvironment*guienv = device->getGUIEnvironment();
guienv->addStaticText(L"Hello World! This is the Irrlicht Software
renderer!",rect<s32>(10,10,260,22),true);
IAnimatedMesh*mesh = smgr->getMesh("../../media/sydney.md2");
if (!mesh)
{
device->drop();
return 1;
}
IAnimatedMeshSceneNode*node =
smgr->addAnimatedMeshSceneNode( mesh );
if (node)
{
node->setMaterialFlag(EMF_LIGHTING,false);
node->setMD2Animation(scene::EMAT_STAND);
node->setMaterialTexture( 0,
driver->getTexture("../../media/sydney.bmp") );
}
smgr->addCameraSceneNode(0,vector3df(0,30,-40),
vector3df(0,5,0));
while(device->run())
{
driver->beginScene(true, true,SColor(255,100,101,140));
smgr->drawAll();
guienv->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
main()之前都是些文件包含,使用的名字空间等生命,其中:
#pragma comment(linker,"/subsystem:windows /ENTRY:mainCRTStartup")这句话告诉编译器,程序运行的时候不要弹出控制台窗口,可以注释掉,如果注释掉就会弹出黑色的控制台窗口。
进入main()后,第一件要做的事情是创建设备:
IrrlichtDevice *device =
createDevice(video::EDT_SOFTWARE, dimension2d<u32>(640, 480),
16, false, false,false, 0);
一个irrlicht设备表现为一个窗口,如果创建设备失败,那程序接下来就没什么事可以做了,只能报告一个错误,并退出。
if(!device)
return 1;
如果设备创建成功,就会获得一个窗口,窗口的大小为640*480,video::EDT_SOFTWARE参数告诉irrlicht创建一个使用软件渲染器的窗口,如果希望用OpenGL作为底层渲染API,可以将video::EDT_SOFTWARE修改成video::EDT_OPENGL。
接下来这句:
device->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");设置了窗口的名称,你可以将它修改成你想要的名称。
IVideoDriver* driver =device->getVideoDriver();
ISceneManager* smgr =device->getSceneManager();
IGUIEnvironment* guienv =device->getGUIEnvironment();
这三句将设备里建立好的视频驱动对象,场景管理对象和图像用户接口对象保存在零时变量里,以备后用。
guienv->addStaticText(L"Hello World! This is the Irrlicht Software
renderer!",rect<s32>(10,10,260,22),true);
表示在屏幕的10,10位置出显示一行文字。
IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
表示读入一个3D模型文件,建立一个带骨骼动画的网格对象。
如果建立失败(比如磁盘中根本没有所谓的sydney.md2文件,那就会失败,不过只要用户没有删除SDK里的文件,则这个文件是存在的,建立会成功)。那程序接下来也没什么要展示的啦,退出完事。
if(!mesh)
{
device->drop();
return 1;
}
这里执行了device->drop();表示退出之前要将设备对象释放掉,其实就是不释放程序退出后设备对象也会被释放掉,但作为C++程序员,及时释放没有用的对象是好习惯。
接下来这句:
IAnimatedMeshSceneNode* node =
smgr->addAnimatedMeshSceneNode( mesh );
要理解一下,为什么要执行这么一句,原来irrlicht里所有的在场景里看得见的对象都以SceneNode(场景节点)的方式出现的,刚才从磁盘中建立的网格对象只是在内存中的一个孤立数据,要让irrlicht将她显示出来,比如将她以场景节点的方式加到场景树里去。
场景节点建立出来后还可以对她设置一些参数:
if(node)
{
node->setMaterialFlag(EMF_LIGHTING,false);
node->setMD2Animation(scene::EMAT_STAND);
node->setMaterialTexture( 0,
driver->getTexture("../../media/sydney.bmp") );
}
这几句将节点的的材质属性设成关闭灯光,动作为站立,用sydney.bmp作为纹理。
smgr->addCameraSceneNode(0,vector3df(0,30,-40),
vector3df(0,5,0));
这句告诉irrlicht场景中的摄像机位于世界坐标(0,30,-40)这个位置,镜头的朝向是(0,5,0)
现在渲染的窗口有了,渲染的对象(3D模型)也准备好了,摄像机也对准了,那接下去就该进入没完没了的渲染循环了:
while(device->run())
{
driver->beginScene(true, true,SColor(255,100,101,140));
smgr->drawAll();
guienv->drawAll();
driver->endScene();
}
上面的这个while循环一直会进行下去,直到用户点击窗口上的X或者按下Alt+F4退出程序。
循环结束后,退出程序前仍然要释放设备对象,保持良好的C++编程风格。
运行一下程序,可以看到一个难看的女子在窗口里站着,还时不时转动一下身体望你一眼,想把这个程序改掉吧,那就看你的功力啦,不会,没关系,我会接着写irrlicht的用法。
入门就写到这儿吧。