首先,我包含那头文件,使用irr命名空间,和连接要使用的*.lib文件。
#include <irrlicht.h>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
|
这里是本教程最复杂的部份:我们制定一个自定义场景节点类。为了简单,我们的场景节点既不是基于入口的室内渲染也不是地形场景节点,而是一个简单的四面体。
为了使自定义的场景节点在IrrLicht引擎中使用,我们需要创建继承自ISceneNode的类并重载一些方法。
class CSampleSceneNode : public scene::ISceneNode {
|
首先,我们定义一些成员变量,保存四面体的数据:四面体的包围体,四个顶点和材质。
core::aabbox3d<f32> Box; video::S3DVertex Vertices[4]; video::SMaterial Material;
|
构造函数的参数要指定父场景节点,场景管理器指针和场景节点的编号(ID)。在构造函数里,我们调用了父类的构造函数,并设置四面体的材质和四个顶点的属性。
public:
CSampleSceneNode(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
: 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);
|
IrrLicht引擎需要知道场景节点的包围体。包围体用于自动剪裁和其它。因此我们需要根据四个顶点创建包围体。如果你不想引擎使用包围体进行自动剪裁,或者不想创建包围体,你可以这样写 AutomaticCullingEnabled = false;.
Box.reset(Vertices[0].Pos); for (s32 i=1; i<4; ++i) Box.addInternalPoint(Vertices[i].Pos);
}
|
在绘制之前,场景管理器会调用每一个场景节点的OnRegisterSceneNode()方法。如果场景节点希望绘制自己,可以把类的this指针注册到场景管理器里。这是必要的告诉场景节点调用合适的::render方法。例如一个个地渲染普通场景节点的内容时,模板缓存阴影会在其它场景节点后渲染。而摄像机或灯光场景节点会在其它场景节点前渲染。 因此这里简单地注册场景节点来渲染。如果想好似摄像机或灯光那样渲染场景节点,我们也可以调用SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA); 然后,我们可以调用基于ISceneNode类的OnRegisterSceneNode方法,转而调用子类的方法注册自己。
virtual void OnRegisterSceneNode() { if (IsVisible) SceneManager->registerNodeForRendering(this);
ISceneNode::OnPreRender();
}
|
Render()方法用于渲染场景节点自己。我们重载这个方法来绘制四面体。
virtual void render() { u16 indices[] = { 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->drawIndexedTriangleList(&Vertices[0], 4, &indices[0], 4);
}
|
最后,我们为自定义的场景节点添加三个方法。GetBoundingBox()返回场景节点的包围体, GetMaterialCount()返回场景节点的材质数(这个四面体只有一个材质),和getMaterial()指定索引的材质。这里只有一个材质,而getMaterial方法的参数要求为大于0的索引。
virtual const core::aabbox3d<f32>& getBoundingBox() const { return Box; }
virtual s32 getMaterialCount()
{
return 1;
}
virtual video::SMaterial& getMaterial(s32 i)
{
return Material;
}
};
|
这样就完成的场景节点的定义。现在要在引擎中创建这种场景节点和摄像机并观看结果。
int main() {
IrrlichtDevice *device =
createDevice(video::EDT_OPENGL, core::dimension2d<s32>(640, 480), 16, false);
device->setWindowCaption(L"Custom Scene Node - Irrlicht Engine Demo");
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
smgr->addCameraSceneNode(0, core::vector3df(0,-40,0), core::vector3df(0,0,0));
|
创建一个自定义场景节点对象。注意,我们会在创建后立即销毁(->drop())这个对象。这样做是因为这个对象由场景管理器接管了。这不是必需的,对象也可以在程序结束时销毁。
CSampleSceneNode *myNode = new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
myNode->drop();
|
要使只有一个四面体的场景活动,可以像引擎中的其它节点那样添加一个使场景节点活动的动画。
scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));
myNode->addAnimator(anim);
anim->drop();
|
实现开始绘制和结束程序。
while(device->run()) { driver->beginScene(true, true, video::SColor(0,100,100,100));
smgr->drawAll();
driver->endScene();
}
device->drop();
return 0;
}
|
就这样,编译和演示一下这程序吧。
|