Tutorial 12: Rendering de Terreno.
Este tutorial mostrara brevemente como usar el renderer de terreno de Irrlicht. Este también mostrara como usar el selector de triángulos de terreno para poder hacer detección de colisiones con el terreno.
El programa descrito aquí se vera como este:

Empecemos!
Al comienzo no hay nada de especial. Incluimos los archivos de cabecera necesarios y creamos un event listener para escuchar si el usuario presiona la tecla tecla 'W' así cambiamos al modo wireframe.
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(scene::ISceneNode* terrain)
{
// Guardamos el puntero al terreno asi podemos cambiar su modo de dibujo.
Terrain = terrain;
}
bool OnEvent(SEvent event)
{
// verificamos si se presiono la tecla 'W'
if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
event.KeyInput.Key == irr::KEY_KEY_W && !event.KeyInput.PressedDown)
{
// cambiamos a modo wire frame
Terrain->setMaterialFlag(video::EMF_WIREFRAME,
!Terrain->getMaterial(0).Wireframe);
return true;
}
return false;
}
private:
scene::ISceneNode* Terrain;
};
|
El comienzo de la función main comienza como en la mayoría de los otros ejemplos. Preguntamos al usuario por el renderizador deseado y comenzamos.
int main()
{
// dejamos que el usuario elija el driver
video::E_DRIVER_TYPE driverType = video::EDT_DIRECTX9;
printf("Please select the driver you want for this example:\n"\
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.2\n"\
" (d) Software Renderer\n (e) NullDevice\n (otherKey) exit\n\n");
char i;
std::cin >> i;
switch(i)
{
case 'a': driverType = video::EDT_DIRECTX9; break;
case 'b': driverType = video::EDT_DIRECTX8; break;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_NULL; break;
default: return 0;
}
// crea el dispositivo
IrrlichtDevice* device = createDevice(driverType, core::dimension2d<s32>(640, 480));
if (device == 0)
return 1; // podria no crearse el driver seleccionado.
|
Primero, agregamos todos los elementos estándar a la escena: Un lindo logo de Irrlicht, un pequeño texto de ayuda, una cámara controlada por el usuario y deshabilitamos el cursor del mouse.
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();
driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
// agregamos el logo de irrlicht
env->addImage(driver->getTexture("../../media/irrlichtlogoalpha.tga"),
core::position2d<s32>(10,10));
// agregamos algo de texto de ayuda
gui::IGUIStaticText* text = env->addStaticText(
L"Press 'W' to change wireframe mode",
core::rect<s32>(10,465,200,475), true);
text->setOverrideColor(video::SColor(100,255,255,255));
// agregamos la camara
scene::ICameraSceneNode* camera =
smgr->addCameraSceneNodeFPS(0,100.0f,1200.0f);
camera->setPosition(core::vector3df(1900*2,255*2,3700*2));
camera->setTarget(core::vector3df(2397*2,343*2,2700*2));
camera->setFarValue(12000.0f);
// desactivamos el cursor del mouse
device->getCursorControl()->setVisible(false);
|
Aquí viene el nodo de escena del terrain renderer (renderizador de terreno): Lo agregamos a la escena como a cualquier otro nodo de escena usando ISceneManager::addTerrainSceneNode(). El único parámetro que usamos es el nombre del archivo heightmap que usamos. Un heightmap es simplemente una textura en escala de grises. El terrain renderer lo carga y crea el terreno a partir de esta.
Para hacer que el terreno se vea más grande, cambiamos el factor de escala del mismo a (40, 4.4, 40). Debido a que no tenemos ninguna luz dinámica en la escena desactivamos la iluminación, y por ultimo seteamos el archivo terrain-texture.jpg como textura para el terreno. En este ejemplo, la textura no es repetida sobre todo el terreno. Pero si lo quieres puedes llamar a ITerrainSceneNode::scaleTexture() y hacer un escalamiento de textura.
// agregamos el nodo de escena del terreno
scene::ITerrainSceneNode* terrain = smgr->addTerrainSceneNode(
"../../media/terrain-heightmap.bmp");
terrain->setScale(core::vector3df(40, 4.4f, 40));
terrain->setMaterialFlag(video::EMF_LIGHTING, false);
terrain->setMaterialTexture(0, driver->getTexture(
"../../media/terrain-texture.jpg"));
//terrain->scaleTexture(1.0f);
|
Para poder hacer colisión con el terreno, creamos un selector de triángulos. Si quieres saber lo que hace un selector de triángulos mira el tutorial de colisiones (disponible muy pronto). El selector de triángulos del terreno trabaja junto con el terreno. Para demostrar esto, creamos un "collision response animator" (animador de respuesta a colisión) y lo adjuntamos a la cámara, de esta forma la cámara no podrá volar a través del terreno.
// creamos un selector de triangulos para el terreno
scene::ITriangleSelector* selector =
smgr->createTerrainTriangleSelector(terrain, 0);
terrain->setTriangleSelector(selector);
selector->drop();
// creamos un collision response animator y lo adjuntamos a la camara.
scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator(
selector, camera, core::vector3df(60,100,60),
core::vector3df(0,0,0),
core::vector3df(0,50,0));
camera->addAnimator(anim);
anim->drop();
|
Para hacer que el usuario pueda cambiar entre modo normal y wireframe, creamos una instancia de un event receiver (receptor de eventos) de más arriba y dejamos que Irrlicht sepa de esta. Además agregamos el skybox. La cual ya usamos en un montón de ejemplos de Irrlicht (disponibles muy pronto).
// creamos el receptor de eventos
MyEventReceiver receiver(terrain);
device->setEventReceiver(&receiver);
// crea la skybox
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
smgr->addSkyBoxSceneNode(
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"));
driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
|
Eso es todo, dibujalo todo. Ahora ya sabes como usar terrenos en Irrlicht.
int lastFPS = -1;
while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, 0 );
smgr->drawAll();
env->drawAll();
driver->endScene();
// muestra los frames por segundo en el titulo de la ventana
int fps = driver->getFPS();
if (lastFPS != fps)
{
core::stringw str = L"Terrain Renderer - Irrlicht Engine [";
str += driver->getName();
str += "] FPS:";
str += fps;
device->setWindowCaption(str.c_str());
lastFPS = fps;
}
}
device->drop();
return 0;
}
|
