This tutorial will briefly show how to use the terrain renderer of Irrlicht. It will also show the terrain renderer triangle selector to be able to do collision detection with terrain.
Note that the Terrain Renderer in Irrlicht is based on Spintz' GeoMipMapSceneNode, lots of thanks go to him. DeusXL provided a new elegant simple solution for building larger area on small heightmaps -> terrain smoothing.
In the beginning there is nothing special. We include the needed header files and create an event listener to listen if the user presses a key: The 'W' key switches to wireframe mode, the 'P' key to pointcloud mode, and the 'D' key toggles between solid and detail mapped material.
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
{
public:
Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true), showDebug(false)
{
Skybox->setVisible(showBox);
Skydome->setVisible(!showBox);
}
bool OnEvent(
const SEvent& event)
{
{
{
Terrain->setMaterialFlag(video::EMF_WIREFRAME,
!Terrain->getMaterial(0).Wireframe);
Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false);
return true;
Terrain->setMaterialFlag(video::EMF_POINTCLOUD,
!Terrain->getMaterial(0).PointCloud);
Terrain->setMaterialFlag(video::EMF_WIREFRAME, false);
return true;
Terrain->setMaterialType(
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
video::EMT_DETAIL_MAP : video::EMT_SOLID);
return true;
showBox=!showBox;
Skybox->setVisible(showBox);
Skydome->setVisible(!showBox);
return true;
showDebug=!showDebug;
Terrain->setDebugDataVisible(showDebug?scene::EDS_BBOX_ALL:scene::EDS_OFF);
return true;
default:
break;
}
}
return false;
}
private:
bool showBox;
bool showDebug;
};
Interface of an object which can receive events.
Main header file of the irrlicht, the only file needed to include.
Everything in the Irrlicht Engine can be found in this namespace.
@ EET_KEY_INPUT_EVENT
A key input event.
SEvents hold information about an event. See irr::IEventReceiver for details on event handling.
struct SKeyInput KeyInput
The start of the main function starts like in most other example. We ask the user for the desired renderer and start it up. This time with the advanced parameter handling.
int main()
{
if (driverType==video::EDT_COUNT)
return 1;
if (device == 0)
return 1;
The Irrlicht device. You can create it with createDevice() or createDeviceEx().
Axis aligned bounding box in 3d dimensional space.
E_DRIVER_TYPE
An enum for all types of drivers the Irrlicht Engine supports.
Structure for holding Irrlicht Device creation parameters.
core::dimension2d< u32 > WindowSize
Size of the window or the video mode in fullscreen mode. Default: 800x600.
video::E_DRIVER_TYPE DriverType
Type of video driver used to render graphics.
First, we add standard stuff to the scene: A nice irrlicht engine logo, a small help text, a user controlled camera, and we disable the mouse cursor.
L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome",
virtual gui::ICursorControl * getCursorControl()=0
Provides access to the cursor control.
virtual scene::ISceneManager * getSceneManager()=0
Provides access to the scene manager.
virtual video::IVideoDriver * getVideoDriver()=0
Provides access to the video driver for drawing 3d and 2d geometry.
virtual gui::IGUIEnvironment * getGUIEnvironment()=0
Provides access to the 2d user interface environment.
virtual void setVisible(bool visible)=0
Changes the visible state of the mouse cursor.
GUI Environment. Used as factory and manager of all other GUI elements.
virtual IGUIImage * addImage(video::ITexture *image, core::position2d< s32 > pos, bool useAlphaChannel=true, IGUIElement *parent=0, s32 id=-1, const wchar_t *text=0)=0
Adds an image element.
virtual IGUIFont * getFont(const io::path &filename)=0
Returns pointer to the font with the specified filename.
virtual IGUIStaticText * addStaticText(const wchar_t *text, const core::rect< s32 > &rectangle, bool border=false, bool wordWrap=true, IGUIElement *parent=0, s32 id=-1, bool fillBackground=false)=0
Adds a static text.
virtual IGUISkin * getSkin() const =0
Returns pointer to the current gui skin.
virtual void setFont(IGUIFont *font, EGUI_DEFAULT_FONT which=EGDF_DEFAULT)=0
sets a default font
Scene Node which is a (controlable) camera.
virtual void setTarget(const core::vector3df &pos)=0
Sets the look at target of the camera.
virtual void setFarValue(f32 zf)=0
Sets the value of the far clipping plane (default: 2000.0f)
The Scene Manager manages scene nodes, mesh recources, cameras and all the other stuff.
virtual ICameraSceneNode * addCameraSceneNodeFPS(ISceneNode *parent=0, f32 rotateSpeed=100.0f, f32 moveSpeed=0.5f, s32 id=-1, SKeyMap *keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, f32 jumpSpeed=0.f, bool invertMouse=false, bool makeActive=true)=0
Adds a camera scene node with an animator which provides mouse and keyboard control appropriate for f...
virtual void setPosition(const core::vector3df &newpos)
Sets the position of the node relative to its parent.
Interface to driver which is able to perform 2d and 3d graphics functions.
virtual ITexture * getTexture(const io::path &filename)=0
Get access to a named texture.
virtual void setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled=true)=0
Enables or disables a texture creation flag.
Here comes the terrain renderer scene node: We add it just like any other scene node to the scene using ISceneManager::addTerrainSceneNode(). The only parameter we use is a file name to the heightmap we use. A heightmap is simply a gray scale texture. The terrain renderer loads it and creates the 3D terrain from it.
To make the terrain look more big, we change the scale factor of it to (40, 4.4, 40). Because we don't have any dynamic lights in the scene, we switch off the lighting, and we set the file terrain-texture.jpg as texture for the terrain and detailmap3.jpg as second texture, called detail map. At last, we set the scale values for the texture: The first texture will be repeated only one time over the whole terrain, and the second one (detail map) 20 times.
"../../media/terrain-heightmap.bmp",
0,
-1,
5,
scene::ETPS_17,
4
);
driver->
getTexture(
"../../media/terrain-texture.jpg"));
driver->
getTexture(
"../../media/detailmap3.jpg"));
virtual ITerrainSceneNode * addTerrainSceneNode(const io::path &heightMapFileName, ISceneNode *parent=0, s32 id=-1, const core::vector3df &position=core::vector3df(0.0f, 0.0f, 0.0f), const core::vector3df &rotation=core::vector3df(0.0f, 0.0f, 0.0f), const core::vector3df &scale=core::vector3df(1.0f, 1.0f, 1.0f), video::SColor vertexColor=video::SColor(255, 255, 255, 255), s32 maxLOD=5, E_TERRAIN_PATCH_SIZE patchSize=ETPS_17, s32 smoothFactor=0, bool addAlsoIfHeightmapEmpty=false)=0
Adds a terrain scene node to the scene graph.
void setMaterialTexture(u32 textureLayer, video::ITexture *texture)
Sets the texture of the specified layer in all materials of this scene node to the new texture.
void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
Sets all material flags at once to a new value.
void setMaterialType(video::E_MATERIAL_TYPE newType)
Sets the material type of all materials in this scene node to a new material type.
A scene node for displaying terrain using the geo mip map algorithm.
virtual void scaleTexture(f32 scale=1.0f, f32 scale2=0.0f)=0
Scales the base texture, similar to makePlanarTextureMapping.
Class representing a 32 bit ARGB color.
To be able to do collision with the terrain, we create a triangle selector. If you want to know what triangle selectors do, just take a look into the collision tutorial. The terrain triangle selector works together with the terrain. To demonstrate this, we create a collision response animator and attach it to the camera, so that the camera will not be able to fly through the terrain.
bool drop() const
Drops the object. Decrements the reference counter by one.
virtual ITriangleSelector * createTerrainTriangleSelector(ITerrainSceneNode *node, s32 LOD=0)=0
Creates a triangle selector which can select triangles from a terrain scene node.
virtual ISceneNodeAnimatorCollisionResponse * createCollisionResponseAnimator(ITriangleSelector *world, ISceneNode *sceneNode, const core::vector3df &ellipsoidRadius=core::vector3df(30, 60, 30), const core::vector3df &gravityPerSecond=core::vector3df(0,-10.0f, 0), const core::vector3df &ellipsoidTranslation=core::vector3df(0, 0, 0), f32 slidingValue=0.0005f)=0
Creates a special scene node animator for doing automatic collision detection and response.
Animates a scene node. Can animate position, rotation, material, and so on.
virtual void addAnimator(ISceneNodeAnimator *animator)
Adds an animator which should animate this node.
virtual void setTriangleSelector(ITriangleSelector *selector)
Sets the triangle selector of the scene node.
Interface to return triangles with specific properties.
If you need access to the terrain data you can also do this directly via the following code fragment.
virtual IVertexBuffer & getVertexBuffer() const
virtual void getMeshBufferForLOD(IDynamicMeshBuffer &mb, s32 LOD=0) const =0
Gets the meshbuffer data based on a specified level of detail.
virtual void * getData()=0
Vertex with two texture coordinates.
To make the user be able to switch between normal and wireframe mode, we create an instance of the event receiver from above and let Irrlicht know about it. In addition, we add the skybox which we already used in lots of Irrlicht examples and a skydome, which is shown mutually exclusive with the skybox by pressing 'S'.
driver->
getTexture(
"../../media/irrlicht2_up.jpg"),
driver->
getTexture(
"../../media/irrlicht2_dn.jpg"),
driver->
getTexture(
"../../media/irrlicht2_lf.jpg"),
driver->
getTexture(
"../../media/irrlicht2_rt.jpg"),
driver->
getTexture(
"../../media/irrlicht2_ft.jpg"),
driver->
getTexture(
"../../media/irrlicht2_bk.jpg"));
MyEventReceiver receiver(terrain, skybox, skydome);
virtual void setEventReceiver(IEventReceiver *receiver)=0
Sets a new user event receiver which will receive events from the engine.
virtual ISceneNode * addSkyBoxSceneNode(video::ITexture *top, video::ITexture *bottom, video::ITexture *left, video::ITexture *right, video::ITexture *front, video::ITexture *back, ISceneNode *parent=0, s32 id=-1)=0
Adds a skybox scene node to the scene graph.
virtual ISceneNode * addSkyDomeSceneNode(video::ITexture *texture, u32 horiRes=16, u32 vertRes=8, f32 texturePercentage=0.9, f32 spherePercentage=2.0, f32 radius=1000.f, ISceneNode *parent=0, s32 id=-1)=0
Adds a skydome scene node to the scene graph.
That's it, draw everything.
int lastFPS = -1;
{
if (lastFPS != fps)
{
str += "] FPS:";
str += fps;
str += " Height: ";
lastFPS = fps;
}
}
return 0;
}
virtual bool run()=0
Runs the device.
virtual void setWindowCaption(const wchar_t *text)=0
Sets the caption of the window.
virtual bool isWindowActive() const =0
Returns if the window is active.
T X
X coordinate of the vector.
T Z
Z coordinate of the vector.
virtual void drawAll()=0
Draws all gui elements by traversing the GUI environment starting at the root node.
virtual void drawAll()=0
Draws all the scene nodes.
virtual core::vector3df getAbsolutePosition() const
Gets the absolute position of the node in world coordinates.
virtual f32 getHeight(f32 x, f32 y) const =0
Get height of a point of the terrain.
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.
virtual s32 getFPS() const =0
Returns current frames per second value.
virtual const wchar_t * getName() const =0
Gets name of this video driver.
virtual bool endScene()=0
Presents the rendered image to the screen.
Now you know how to use terrain in Irrlicht.