1
/** Example 012 Terrain Rendering
3
This tutorial will briefly show how to use the terrain renderer of Irrlicht. It
4
will also show the terrain renderer triangle selector to be able to do
5
collision detection with terrain.
7
Note that the Terrain Renderer in Irrlicht is based on Spintz'
8
GeoMipMapSceneNode, lots of thanks go to him. DeusXL provided a new elegant
9
simple solution for building larger area on small heightmaps -> terrain
12
In the beginning there is nothing special. We include the needed header files
13
and create an event listener to listen if the user presses a key: The 'W' key
14
switches to wireframe mode, the 'P' key to pointcloud mode, and the 'D' key
15
toggles between solid and detail mapped material.
18
#include "driverChoice.h"
23
#pragma comment(lib, "Irrlicht.lib")
27
class MyEventReceiver : public IEventReceiver
31
MyEventReceiver(scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) :
32
Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true), showDebug(false)
34
Skybox->setVisible(showBox);
35
Skydome->setVisible(!showBox);
38
bool OnEvent(const SEvent& event)
40
// check if user presses the key 'W' or 'D'
41
if (event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
43
switch (event.KeyInput.Key)
45
case irr::KEY_KEY_W: // switch wire frame mode
46
Terrain->setMaterialFlag(video::EMF_WIREFRAME,
47
!Terrain->getMaterial(0).Wireframe);
48
Terrain->setMaterialFlag(video::EMF_POINTCLOUD, false);
50
case irr::KEY_KEY_P: // switch wire frame mode
51
Terrain->setMaterialFlag(video::EMF_POINTCLOUD,
52
!Terrain->getMaterial(0).PointCloud);
53
Terrain->setMaterialFlag(video::EMF_WIREFRAME, false);
55
case irr::KEY_KEY_D: // toggle detail map
56
Terrain->setMaterialType(
57
Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ?
58
video::EMT_DETAIL_MAP : video::EMT_SOLID);
60
case irr::KEY_KEY_S: // toggle skies
62
Skybox->setVisible(showBox);
63
Skydome->setVisible(!showBox);
65
case irr::KEY_KEY_X: // toggle debug information
67
Terrain->setDebugDataVisible(showDebug?scene::EDS_BBOX_ALL:scene::EDS_OFF);
78
scene::ISceneNode* Terrain;
79
scene::ISceneNode* Skybox;
80
scene::ISceneNode* Skydome;
87
The start of the main function starts like in most other example. We ask the
88
user for the desired renderer and start it up. This time with the advanced
93
// ask user for driver
94
video::E_DRIVER_TYPE driverType=driverChoiceConsole();
95
if (driverType==video::EDT_COUNT)
98
// create device with full flexibility over creation parameters
99
// you can add more parameters if desired, check irr::SIrrlichtCreationParameters
100
irr::SIrrlichtCreationParameters params;
101
params.DriverType=driverType;
102
params.WindowSize=core::dimension2d<u32>(640, 480);
103
IrrlichtDevice* device = createDeviceEx(params);
106
return 1; // could not create selected driver.
110
First, we add standard stuff to the scene: A nice irrlicht engine
111
logo, a small help text, a user controlled camera, and we disable
115
video::IVideoDriver* driver = device->getVideoDriver();
116
scene::ISceneManager* smgr = device->getSceneManager();
117
gui::IGUIEnvironment* env = device->getGUIEnvironment();
119
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
122
env->addImage(driver->getTexture("../../media/irrlichtlogo2.png"),
123
core::position2d<s32>(10,10));
126
env->getSkin()->setFont(env->getFont("../../media/fontlucida.png"));
128
// add some help text
130
L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome",
131
core::rect<s32>(10,421,250,475), true, true, 0, -1, true);
134
scene::ICameraSceneNode* camera =
135
smgr->addCameraSceneNodeFPS(0,100.0f,1.2f);
137
camera->setPosition(core::vector3df(2700*2,255*2,2600*2));
138
camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
139
camera->setFarValue(42000.0f);
141
// disable mouse cursor
142
device->getCursorControl()->setVisible(false);
145
Here comes the terrain renderer scene node: We add it just like any
146
other scene node to the scene using
147
ISceneManager::addTerrainSceneNode(). The only parameter we use is a
148
file name to the heightmap we use. A heightmap is simply a gray scale
149
texture. The terrain renderer loads it and creates the 3D terrain from
152
To make the terrain look more big, we change the scale factor of
153
it to (40, 4.4, 40). Because we don't have any dynamic lights in the
154
scene, we switch off the lighting, and we set the file
155
terrain-texture.jpg as texture for the terrain and detailmap3.jpg as
156
second texture, called detail map. At last, we set the scale values for
157
the texture: The first texture will be repeated only one time over the
158
whole terrain, and the second one (detail map) 20 times.
161
// add terrain scene node
162
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
163
"../../media/terrain-heightmap.bmp",
166
core::vector3df(0.f, 0.f, 0.f), // position
167
core::vector3df(0.f, 0.f, 0.f), // rotation
168
core::vector3df(40.f, 4.4f, 40.f), // scale
169
video::SColor ( 255, 255, 255, 255 ), // vertexColor
171
scene::ETPS_17, // patchSize
175
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
177
terrain->setMaterialTexture(0,
178
driver->getTexture("../../media/terrain-texture.jpg"));
179
terrain->setMaterialTexture(1,
180
driver->getTexture("../../media/detailmap3.jpg"));
182
terrain->setMaterialType(video::EMT_DETAIL_MAP);
184
terrain->scaleTexture(1.0f, 20.0f);
187
To be able to do collision with the terrain, we create a triangle selector.
188
If you want to know what triangle selectors do, just take a look into the
189
collision tutorial. The terrain triangle selector works together with the
190
terrain. To demonstrate this, we create a collision response animator
191
and attach it to the camera, so that the camera will not be able to fly
195
// create triangle selector for the terrain
196
scene::ITriangleSelector* selector
197
= smgr->createTerrainTriangleSelector(terrain, 0);
198
terrain->setTriangleSelector(selector);
200
// create collision response animator and attach it to the camera
201
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
202
selector, camera, core::vector3df(60,100,60),
203
core::vector3df(0,0,0),
204
core::vector3df(0,50,0));
206
camera->addAnimator(anim);
209
/* If you need access to the terrain data you can also do this directly via the following code fragment.
211
scene::CDynamicMeshBuffer* buffer = new scene::CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
212
terrain->getMeshBufferForLOD(*buffer, 0);
213
video::S3DVertex2TCoords* data = (video::S3DVertex2TCoords*)buffer->getVertexBuffer().getData();
214
// Work on data or get the IndexBuffer with a similar call.
215
buffer->drop(); // When done drop the buffer again.
218
To make the user be able to switch between normal and wireframe mode,
219
we create an instance of the event reciever from above and let Irrlicht
220
know about it. In addition, we add the skybox which we already used in
221
lots of Irrlicht examples and a skydome, which is shown mutually
222
exclusive with the skybox by pressing 'S'.
225
// create skybox and skydome
226
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
228
scene::ISceneNode* skybox=smgr->addSkyBoxSceneNode(
229
driver->getTexture("../../media/irrlicht2_up.jpg"),
230
driver->getTexture("../../media/irrlicht2_dn.jpg"),
231
driver->getTexture("../../media/irrlicht2_lf.jpg"),
232
driver->getTexture("../../media/irrlicht2_rt.jpg"),
233
driver->getTexture("../../media/irrlicht2_ft.jpg"),
234
driver->getTexture("../../media/irrlicht2_bk.jpg"));
235
scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture("../../media/skydome.jpg"),16,8,0.95f,2.0f);
237
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
239
// create event receiver
240
MyEventReceiver receiver(terrain, skybox, skydome);
241
device->setEventReceiver(&receiver);
244
That's it, draw everything.
250
if (device->isWindowActive())
252
driver->beginScene(true, true, 0 );
259
// display frames per second in window title
260
int fps = driver->getFPS();
263
core::stringw str = L"Terrain Renderer - Irrlicht Engine [";
264
str += driver->getName();
267
// Also print terrain height of current camera position
268
// We can use camera position because terrain is located at coordinate origin
270
str += terrain->getHeight(camera->getAbsolutePosition().X,
271
camera->getAbsolutePosition().Z);
273
device->setWindowCaption(str.c_str());
284
Now you know how to use terrain in Irrlicht.