教程 3.CustomSceneNode
|
本教程的难度将会提高,所以如果你还没有相关的知识的话,请先阅读前面的教程。本教程将演示如何创建一个自定义的场景节点,以及如何在引擎中使用它。如果你想实现Irrlicht引擎目前不支持的渲染技术的话,自定义场景节点是必要的。例如,你可以自己写一个基于室内的的渲染器或一个先进的地形场景节点。创建自定义场景节点,你可以很容易地扩展Irrlicht引擎,并使其适应您的需求。
我会继续让本教程简单易懂些:讲解尽可能简单明了些,尽可能写在一个cpp文件,并在所有其他的教程里将像这里一样使用引擎。在本教程结束后,结果将如下图所示。这个看起来不是很美观,但它提供了一个完整的定制场景节点并且作为创建你自己的场景节点是一个不错的开始。
|
首先,我包含头文件,使用IRR命名空间,并告诉链接器链接lib文件。
#include <irrlicht.h> using namespace irr; #pragma comment(lib, "Irrlicht.lib")
class CSampleSceneNode : public scene::ISceneNode
{
首先,我们声明一些成员变量,用来保存四面体的数据:包围盒,4个顶点,四面体的材质。
core::aabbox3d<f32> Box; video::S3DVertex Vertices[4]; video::SMaterial Material;
构造函数的参数包含了父场景节点,场景管理的指针,和场景节点的ID。在构造函数本身,我们调用父类的构造函数,设置我们用来绘制场景节点所使用的材质,并创建我们等下要画出来的4个顶点。
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引擎需要知道你的场景节点的包围盒。它会用它做自动裁剪和其他东西。因此,我们需要通过4个顶点创建包围盒。如果你不想引擎使用自动裁剪,或者你不想创建包围盒,你也可以这样写
AutomaticCullingEnabled = false;.
Box.reset(Vertices[0].Pos); for (s32 i=1; i<4; ++i) Box.addInternalPoint(Vertices[i].Pos); }
在画出之前,场景管理器调用在场景中的每个场景节点的方法OnPreRender() 。如果场景节点想要把自己画出来,那么我们应该在场景管理器调用::render 方法之前,先在场景管理器当中注册一下,。 一般的场景节点都是一个一个的把它们的内容渲染出来,而后开始渲染模板缓冲阴影,并且相机或灯光场景节点需要在所有之前被渲染。这里我们只简单的注册下用来只提供一般的渲染,如果我们希望它像相机或灯光一样被渲染出来,我们可以这样写SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA);
在此之后,我们调用基类ISceneNode的OnPreRender方法,这样就让所有的子场景节点注册一下了。
virtual void OnPreRender() { 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()返回指定索引的材质。因为我们只有一个材质,我们可以返回只有一个,如果不只一个的话,我们可以通过索引来指定哪个。
virtual const core::aabbox3d<f32>& getBoundingBox() const { return Box; } virtual u32 getMaterialCount() { return 1; } virtual video::SMaterial& getMaterial(u32 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; }
好了,编译并试下这个程序。