Loading...
Searching...
No Matches
Tutorial 3: Custom SceneNode

This Tutorial is more advanced than the previous ones. If you are currently just playing around with the Irrlicht engine, you may want to look at other examples first. This tutorials shows how to create a custom scene node and how to use it in the engine. A custom scene node is needed if you want to implement a render technique the Irrlicht Engine currently does not support. For example, you can write an indoor portal based renderer or an advanced terrain scene node with it. By creating custom scene nodes, you can easily extend the Irrlicht Engine and adapt it to your own needs.

I will keep the tutorial simple: Keep everything very short, everything in one .cpp file, and I'll use the engine here as in all other tutorials.

To start, I include the header files, use the irr namespace, and tell the linker to link with the .lib file.

#include <irrlicht.h>
#include "driverChoice.h"
using namespace irr;
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
driverChoice.h
irrlicht.h
Main header file of the irrlicht, the only file needed to include.
irr
Everything in the Irrlicht Engine can be found in this namespace.
Definition aabbox3d.h:13

Here comes the more sophisticated part of this tutorial: The class of our very own custom scene node. To keep it simple, our scene node will not be an indoor portal renderer nor a terrain scene node, but a simple tetraeder, a 3d object consisting of 4 connected vertices, which only draws itself and does nothing more. Note that this scenario does not require a custom scene node in Irrlicht. Instead one would create a mesh from the geometry and pass it to a irr::scene::IMeshSceneNode. This example just illustrates creation of a custom scene node in a very simple setting.

To let our scene node be able to be inserted into the Irrlicht Engine scene, the class we create needs to be derived from the irr::scene::ISceneNode class and has to override some methods.

class CSampleSceneNode : public scene::ISceneNode
{
irr::scene::ISceneNode
Scene node interface.
Definition ISceneNode.h:41

First, we declare some member variables: The bounding box, 4 vertices, and the material of the tetraeder.

core::aabbox3d<f32> Box;
video::S3DVertex Vertices[4];
video::SMaterial Material;
irr::core::aabbox3d
Axis aligned bounding box in 3d dimensional space.
Definition aabbox3d.h:22
irr::video::SMaterial
Struct for holding parameters for a material renderer.
Definition SMaterial.h:227
irr::video::S3DVertex
standard vertex used by the Irrlicht engine.
Definition S3DVertex.h:43

The parameters of the constructor specify the parent of the scene node, a pointer to the scene manager, and an id of the scene node. In the constructor we call the parent class' constructor, set some properties of the material, and create the 4 vertices of the tetraeder we will draw later.

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);
irr::scene::ISceneManager
The Scene Manager manages scene nodes, mesh recources, cameras and all the other stuff.
Definition ISceneManager.h:151
irr::video::SColor
Class representing a 32 bit ARGB color.
Definition SColor.h:202
irr::video::SMaterial::Wireframe
bool Wireframe
Draw as wireframe or filled triangles? Default: false.
Definition SMaterial.h:407
irr::video::SMaterial::Lighting
bool Lighting
Will this material be lighted? Default: true.
Definition SMaterial.h:416
irr::scene
All scene management can be found in this namespace: Mesh loading, special scene nodes like octrees a...
Definition CDynamicMeshBuffer.h:16
irr::s32
signed int s32
32 bit signed variable.
Definition irrTypes.h:66

The Irrlicht Engine needs to know the bounding box of a scene node. It will use it for automatic culling and other things. Hence, we need to create a bounding box from the 4 vertices we use. If you do not want the engine to use the box for automatic culling, and/or don't want to create the box, you could also call irr::scene::ISceneNode::setAutomaticCulling() with irr::scene::EAC_OFF.

Box.reset(Vertices[0].Pos);
for (s32 i=1; i<4; ++i)
Box.addInternalPoint(Vertices[i].Pos);
}
irr::core::aabbox3d::addInternalPoint
void addInternalPoint(const vector3d< T > &p)
Adds a point to the bounding box.
Definition aabbox3d.h:74
irr::core::aabbox3d::reset
void reset(T x, T y, T z)
Resets the bounding box to a one-point box.
Definition aabbox3d.h:50

Before it is drawn, the irr::scene::ISceneNode::OnRegisterSceneNode() method of every scene node in the scene is called by the scene manager. If the scene node wishes to draw itself, it may register itself in the scene manager to be drawn. This is necessary to tell the scene manager when it should call irr::scene::ISceneNode::render(). For example, normal scene nodes render their content one after another, while stencil buffer shadows would like to be drawn after all other scene nodes. And camera or light scene nodes need to be rendered before all other scene nodes (if at all). So here we simply register the scene node to render normally. If we would like to let it be rendered like cameras or light, we would have to call SceneManager->registerNodeForRendering(this, SNRT_LIGHT_AND_CAMERA); After this, we call the actual irr::scene::ISceneNode::OnRegisterSceneNode() method of the base class, which simply lets also all the child scene nodes of this node register themselves.

virtual void OnRegisterSceneNode()
{
if (IsVisible)
SceneManager->registerNodeForRendering(this);
ISceneNode::OnRegisterSceneNode();
}

In the render() method most of the interesting stuff happens: The Scene node renders itself. We override this method and draw the tetraeder.

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->drawVertexPrimitiveList(&Vertices[0], 4, &indices[0], 4, video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
}
irr::video::IVideoDriver
Interface to driver which is able to perform 2d and 3d graphics functions.
Definition IVideoDriver.h:257
irr::video::IVideoDriver::setMaterial
virtual void setMaterial(const SMaterial &material)=0
Sets a material.
irr::video::IVideoDriver::setTransform
virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4 &mat)=0
Sets transformation matrices.
irr::video::IVideoDriver::drawVertexPrimitiveList
virtual void drawVertexPrimitiveList(const void *vertices, u32 vertexCount, const void *indexList, u32 primCount, E_VERTEX_TYPE vType=EVT_STANDARD, scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, E_INDEX_TYPE iType=EIT_16BIT)=0
Draws a vertex primitive list.
irr::scene::EPT_TRIANGLES
@ EPT_TRIANGLES
Explicitly set all vertices for each triangle.
Definition EPrimitiveTypes.h:37
irr::video::EVT_STANDARD
@ EVT_STANDARD
Standard vertex type used by the Irrlicht engine, video::S3DVertex.
Definition S3DVertex.h:21
irr::video::ETS_WORLD
@ ETS_WORLD
World transformation.
Definition IVideoDriver.h:57
irr::video::EIT_16BIT
@ EIT_16BIT
Definition SVertexIndex.h:17
irr::u16
unsigned short u16
16 bit unsigned variable.
Definition irrTypes.h:40

And finally we create three small additional methods. irr::scene::ISceneNode::getBoundingBox() returns the bounding box of this scene node, irr::scene::ISceneNode::getMaterialCount() returns the amount of materials in this scene node (our tetraeder only has one material), and irr::scene::ISceneNode::getMaterial() returns the material at an index. Because we have only one material here, we can return the only one material, assuming that no one ever calls getMaterial() with an index greater than 0.

virtual const core::aabbox3d<f32>& getBoundingBox() const
{
return Box;
}
virtual u32 getMaterialCount() const
{
return 1;
}
virtual video::SMaterial& getMaterial(u32 i)
{
return Material;
}
};
irr::u32
unsigned int u32
32 bit unsigned variable.
Definition irrTypes.h:58

That's it. The Scene node is done. Now we simply have to start the engine, create the scene node and a camera, and look at the result.

int main()
{
// ask user for driver
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
if (driverType==video::EDT_COUNT)
return 1;
// create device
IrrlichtDevice *device = createDevice(driverType,
core::dimension2d<u32>(640, 480), 16, false);
if (device == 0)
return 1; // could not create selected driver.
// create engine and camera
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));
irr::IrrlichtDevice
The Irrlicht device. You can create it with createDevice() or createDeviceEx().
Definition IrrlichtDevice.h:44
irr::IrrlichtDevice::setWindowCaption
virtual void setWindowCaption(const wchar_t *text)=0
Sets the caption of the window.
irr::IrrlichtDevice::getSceneManager
virtual scene::ISceneManager * getSceneManager()=0
Provides access to the scene manager.
irr::IrrlichtDevice::getVideoDriver
virtual video::IVideoDriver * getVideoDriver()=0
Provides access to the video driver for drawing 3d and 2d geometry.
irr::core::dimension2d
Specifies a 2 dimensional size.
Definition dimension2d.h:21
irr::scene::ISceneManager::addCameraSceneNode
virtual ICameraSceneNode * addCameraSceneNode(ISceneNode *parent=0, const core::vector3df &position=core::vector3df(0, 0, 0), const core::vector3df &lookat=core::vector3df(0, 0, 100), s32 id=-1, bool makeActive=true)=0
Adds a camera scene node to the scene graph and sets it as active camera.
irr::core::vector3df
vector3d< f32 > vector3df
Typedef for a f32 3d vector.
Definition vector3d.h:445
irr::video::E_DRIVER_TYPE
E_DRIVER_TYPE
An enum for all types of drivers the Irrlicht Engine supports.
Definition EDriverTypes.h:15
irr::video::EDT_COUNT
@ EDT_COUNT
No driver, just for counting the elements.
Definition EDriverTypes.h:56
irr::createDevice
IRRLICHT_API IrrlichtDevice *IRRCALLCONV createDevice(video::E_DRIVER_TYPE deviceType=video::EDT_SOFTWARE, const core::dimension2d< u32 > &windowSize=(core::dimension2d< u32 >(640, 480)), u32 bits=16, bool fullscreen=false, bool stencilbuffer=false, bool vsync=false, IEventReceiver *receiver=0)
Creates an Irrlicht device. The Irrlicht device is the root object for using the engine.

Create our scene node. I don't check the result of calling new, as it should throw an exception rather than returning 0 on failure. Because the new node will create itself with a reference count of 1, and then will have another reference added by its parent scene node when it is added to the scene, I need to drop my reference to it. Best practice is to drop it only after I have finished using it, regardless of what the reference count of the object is after creation.

CSampleSceneNode *myNode =
new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);
irr::scene::ISceneManager::getRootSceneNode
virtual ISceneNode * getRootSceneNode()=0
Gets the root scene node.

To animate something in this boring scene consisting only of one tetraeder, and to show that you now can use your scene node like any other scene node in the engine, we add an animator to the scene node, which rotates the node a little bit. irr::scene::ISceneManager::createRotationAnimator() could return 0, so should be checked.

scene::ISceneNodeAnimator* anim =
smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));
if(anim)
{
myNode->addAnimator(anim);
irr::scene::ISceneManager::createRotationAnimator
virtual ISceneNodeAnimator * createRotationAnimator(const core::vector3df &rotationSpeed)=0
Creates a rotation animator, which rotates the attached scene node around itself.
irr::scene::ISceneNodeAnimator
Animates a scene node. Can animate position, rotation, material, and so on.
Definition ISceneNodeAnimator.h:31

I'm done referring to anim, so must irr::IReferenceCounted::drop() this reference now because it was produced by a createFoo() function. As I shouldn't refer to it again, ensure that I can't by setting to 0.

anim->drop();
anim = 0;
}
irr::IReferenceCounted::drop
bool drop() const
Drops the object. Decrements the reference counter by one.
Definition IReferenceCounted.h:116

I'm done with my CSampleSceneNode object, and so must drop my reference. This won't delete the object, yet, because it is still attached to the scene graph, which prevents the deletion until the graph is deleted or the custom scene node is removed from it.

myNode->drop();
myNode = 0; // As I shouldn't refer to it again, ensure that I can't

Now draw everything and finish.

u32 frames=0;
while(device->run())
{
driver->beginScene(true, true, video::SColor(0,100,100,100));
smgr->drawAll();
driver->endScene();
if (++frames==100)
{
core::stringw str = L"Irrlicht Engine [";
str += driver->getName();
str += L"] FPS: ";
str += (s32)driver->getFPS();
device->setWindowCaption(str.c_str());
frames=0;
}
}
device->drop();
return 0;
}
irr::IrrlichtDevice::run
virtual bool run()=0
Runs the device.
irr::core::string::c_str
const T * c_str() const
Returns character string.
Definition irrString.h:495
irr::scene::ISceneManager::drawAll
virtual void drawAll()=0
Draws all the scene nodes.
irr::video::IVideoDriver::beginScene
virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, SColor color=SColor(255, 0, 0, 0), const SExposedVideoData &videoData=SExposedVideoData(), core::rect< s32 > *sourceRect=0)=0
Applications must call this method before performing any rendering.
irr::video::IVideoDriver::getFPS
virtual s32 getFPS() const =0
Returns current frames per second value.
irr::video::IVideoDriver::getName
virtual const wchar_t * getName() const =0
Gets name of this video driver.
irr::video::IVideoDriver::endScene
virtual bool endScene()=0
Presents the rendered image to the screen.
irr::core::stringw
string< wchar_t > stringw
Typedef for wide character strings.
Definition irrString.h:1361

That's it. Compile and play around with the program.

- Irrlicht Engine Documentation © 2003-2012 by Nikolaus Gebhardt. Generated on for Irrlicht 3D Engine by Doxygen 1.15.0