开源3D游戏引擎Irrlicht(鬼火)Example讲解——CustomSceneNode赵刚Irrlicht引擎自带的第3个Example叫做CustomSceneNode,她演示了用户如何自己创建新的场景节点,如果用户对irrlicht里面已有的SceneNode都不满意,希望自己创建一个有特定功能的SceneNode可以参照这个例子做,这个例子创建的SceneNode很简单,只不过是一个四棱锥,但方法是可以参考的,用户理解后完全可以创建出复杂的SceneNode。程序运行起来如下图:运行03.CustomSceneNode.exe的时候会先出来一个控制台窗口,按a,再按回车即可,表示选择OpenGL作为渲染API。进入bin目录下的examples目录可以看到03.CustomSceneNode目录,双击CustomSceneNode_vc9.vcproj文件打开工程文件,工程文件中只有一个main.cpp文件。内容如下(去除了英文注释):#includeirrlicht.h#includedriverChoice.husingnamespaceirr;#ifdef_MSC_VER#pragmacomment(lib,Irrlicht.lib)#endifclassCSampleSceneNode:publicscene::ISceneNode{core::aabbox3df32Box;video::S3DVertexVertices[4];video::SMaterialMaterial;public:CSampleSceneNode(scene::ISceneNode*parent,scene::ISceneManager*mgr,s32id):scene::ISceneNode(parent,mgr,id){Material.Wireframe=false;Material.Lighting=false;Vertices[0]=video::S3DVertex(0,0,10,1,1,0,video::SColor(255,0,255,255),0,1);Vertices[1]=video::S3DVertex(10,0,-10,1,0,0,video::SColor(255,255,0,255),1,1);Vertices[2]=video::S3DVertex(0,20,0,0,1,1,video::SColor(255,255,255,0),1,0);Vertices[3]=video::S3DVertex(-10,0,-10,0,0,1,video::SColor(255,0,255,0),0,0);Box.reset(Vertices[0].Pos);for(s32i=1;i4;++i)Box.addInternalPoint(Vertices[i].Pos);}virtualvoidOnRegisterSceneNode(){if(IsVisible)SceneManager-registerNodeForRendering(this);ISceneNode::OnRegisterSceneNode();}virtualvoidrender(){u16indices[]={0,2,3,2,1,3,1,0,3,2,0,1};video::IVideoDriver*driver=SceneManager-getVideoDriver();driver-setMaterial(Material);driver-setTransform(video::ETS_WORLD,AbsoluteTransformation);driver-drawVertexPrimitiveList(&Vertices[0],4,&indices[0],4,video::EVT_STANDARD,scene::EPT_TRIANGLES,video::EIT_16BIT);}virtualconstcore::aabbox3df32&getBoundingBox()const{returnBox;}virtualu32getMaterialCount()const{return1;}virtualvideo::SMaterial&getMaterial(u32i){returnMaterial;}};intmain(){video::E_DRIVER_TYPEdriverType=driverChoiceConsole();if(driverType==video::EDT_COUNT)return1;IrrlichtDevice*device=createDevice(driverType,core::dimension2du32(640,480),16,false);if(device==0)return1;//couldnotcreateselecteddriver.device-setWindowCaption(LCustomSceneNode-IrrlichtEngineDemo);video::IVideoDriver*driver=device-getVideoDriver();scene::ISceneManager*smgr=device-getSceneManager();smgr-addCameraSceneNode(0,core::vector3df(0,-40,0),core::vector3df(0,0,0));CSampleSceneNode*myNode=newCSampleSceneNode(smgr-getRootSceneNode(),smgr,666);scene::ISceneNodeAnimator*anim=smgr-createRotationAnimator(core::vector3df(0.8f,0,0.8f));if(anim){myNode-addAnimator(anim);anim-drop();anim=0;}myNode-drop();myNode=0;u32frames=0;while(device-run()){driver-beginScene(true,true,video::SColor(0,100,100,100));smgr-drawAll();driver-endScene();if(++frames==100){core::stringwstr=LIrrlichtEngine[;str+=driver-getName();str+=L]FPS:;str+=(s32)driver-getFPS();device-setWindowCaption(str.c_str());frames=0;}}device-drop();return0;}程序很简洁,条理也很清晰,下面开始讲解代码。首先每个使用irrlicht的程序都必须包含:#includeirrlicht.h#pragmacomment(lib,Irrlicht.lib)表示要使用irrlichtSDK程序开头就定义了一个名为CSampleSceneNode的类,这个类从ISceneNode接口(抽象类)派生,在irrlicht中,用户创建的SceneNode类都必须从ISceneNode接口派生。CSampleSceneNode类包含下面3个成员变量:core::aabbox3df32Box;video::S3DVertexVertices[4];video::SMaterialMaterial;其中Box和Material所有的SceneNode类都会包含,Vertices用于保存网格顶点,数量和格式和用户创建的网格复杂度有关,这个例子中的网格是4个顶点的四棱锥,而且是很基本的网格类型(没有多层纹理,凹凸纹理等复杂特性),所以使用S3DVertex这种简单类型。CSampleSceneNode在构造函数中建立了四棱锥。Material.Wireframe=false;Material.Lighting=false;Vertices[0]=video::S3DVertex(0,0,10,1,1,0,video::SColor(255,0,255,255),0,1);Vertices[1]=video::S3DVertex(10,0,-10,1,0,0,video::SColor(255,255,0,255),1,1);Vertices[2]=video::S3DVertex(0,20,0,0,1,1,video::SColor(255,255,255,0),1,0);Vertices[3]=video::S3DVertex(-10,0,-10,0,0,1,video::SColor(255,0,255,0),0,0);Box.reset(Vertices[0].Pos);for(s32i=1;i4;++i)Box.addInternalPoint(Vertices[i].Pos);这几行程序设置四棱锥的材质属性,4个顶点的位置,法线,颜色和纹理坐标,包围盒的尺寸。接着CSampleSceneNode类重载了virtualvoidOnRegisterSceneNode()函数,该函数每帧循环中均会被irrlichtSDK调用,该函数决定了SceneNode是否会被加入到渲染队列。CSampleSceneNode对该函数没有什么特别设计,只是简单的执行了SceneManager-registerNodeForRendering(this),表示将自己加入渲染队列。然后CSampleSceneNode类重载了virtualvoidrender()函数,该函数在每帧循环的绘图阶段会被irrlichtSDK调用,顾名思义,这个函数是执行绘图功能的。在render()函数里,包含了一下代码:u16indices[]={0,2,3,2,1,3,1,0,3,2,0,1};video::IVideoDriver*driver=SceneManager-getVideoDriver();driver-setMaterial(Material);driver-setTransform(video::ETS_WORLD,AbsoluteTransformation);driver-drawVertexPrimitiveList(&Vertices[0],4,&indices[0],4,video::EVT_STANDARD,scene::EPT_TRIANGLES,video::EIT_16BIT);indices是顶点索引表,表明了四棱锥的4个顶点按什么样顺序组成4个三角形,绘图时需要通过setMaterial函数告知irrlicht使用什么材质,通过setTransform函数告知irrlicht使用什么变换矩阵,然后可以调用driver对象中的绘图方法实现绘制,这里调用的是drawVertexPrimitiveList函数,表示以绘制三角形列表的方式绘制四棱锥。接下来的几个成员函数内容很简单,几乎所有的SceneNode都可以写成这样,这里不再详述。这样CSampleSceneNode就代表了用户创建的场景节点,用户创建自己的场景节点都可以参照这样的过程:1.从ISceneNode派生一个新类2.在构造函数里调用建立网格的函数(或者直接写)。3.重载OnRegisterSceneNode(),告知irrlicht如何将场景节点加入到渲染队列中。4.重载render(),实现绘制过程。5.实现getBoundingBox(),getMaterialCount(),getMaterial()这几个函数。接下来就可以在主程序中声明CSampleSceneNode的对象,并且像使用irrlicht自己的SceneNode一样