Irrlicht Engine logo

Tutorial 12: Terrain Rendering
Přeložil: Martin Cmar

Dnes si stručně ukážeme jak používat renderování terénu s použitím irrlichtu. Spolu s tím také uděláme detekci kolizí aby se nedalo terénem procházet.

Když program dokončíme, bude vypadat takto:


Začínáme!

Na začátku není nic speciálního. Přidáme potřebné hlavičkové soubory a event receiver pro kontrolu stisku kláves. Pokud stiskneme W, zobrazíme celý terén jako síť. Další tlačítko bude měnit vzhled textury.

#include <irrlicht.h>
#include <iostream>
using namespace irr;

#pragma comment(lib, "Irrlicht.lib")

class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(scene::ISceneNode* terrain)
{
// store pointer to terrain so we can change its drawing mode
Terrain = terrain;
}

bool OnEvent(SEvent event)
{
// check if user presses the key 'W' or 'D'
if (event.EventType == irr::EET_KEY_INPUT_EVENT &&
!event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_KEY_W: // switch wire frame mode
Terrain->setMaterialFlag(video::EMF_WIREFRAME,
!Terrain->getMaterial(0).Wireframe);
return true;
case irr::KEY_KEY_D: // toggle detail map
Terrain->setMaterialType(
Terrain->getMaterial(0).MaterialType
== video::EMT_SOLID ?
video::EMT_DETAIL_MAP : video::EMT_SOLID);
return true;
}
}
return false;
}

private:
scene::ISceneNode* Terrain;
};

Na začátku main funkce tak jako v jiných příkladech necháme uživatele vybrat zda chce použít d3d, OpenGL... Poté voláme funkci createDevice se zadaným parametrem.

int main()
{
// let user select driver type

video::E_DRIVER_TYPE driverType = video::EDT_DIRECT3D9;

printf("Please select the driver you want for this example:\n"\
" (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\
" (d) Software Renderer\n (e) Apfelbaum Software Renderer\n"\
" (f) NullDevice\n (otherKey) exit\n\n");

char i;
std::cin >> i;

switch(i)
{
case 'a': driverType = video::EDT_DIRECT3D9;break;
case 'b': driverType = video::EDT_DIRECT3D8;break;
case 'c': driverType = video::EDT_OPENGL; break;
case 'd': driverType = video::EDT_SOFTWARE; break;
case 'e': driverType = video::EDT_SOFTWARE2;break;
case 'f': driverType = video::EDT_NULL; break;
default: return 1;
}

// create device
IrrlichtDevice* device = createDevice(driverType,
core::dimension2d<s32>(640, 480));

if (device == 0)
return 1; // could not create selected driver.

Jako první přidáme ukazatele, logo enginu, pomocný text, uživatelem kontrolovanou kameru a nakonec skryjeme kurzor myši.

video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment();

driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);

// add irrlicht logo
env->addImage(driver->getTexture("../../media/irrlichtlogoalpha.tga"),
core::position2d<s32>(10,10));
// add some help text
gui::IGUIStaticText* text = env->addStaticText(
L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map",
core::rect<s32>(10,453,200,475), true, true, 0, -1, true);
// add camera
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);

// disable mouse cursor
device->getCursorControl()->setVisible(false);

Nyní přichází na řadu kód na samotné vytvoření terénu. Přidáme scénový uzel použitím ISceneManager::addTerrainSceneNode(). Jediný parametr který zadáme je jméno souboru, který načteme heightmapu. Heightmapa je jednoduchá černobílá textura. 3D terén se z textury vytváří tak, že světlá místa jsou vyvýšena a tmavá naopak. Je to velice dobrý a hlavně jednoduchý způsob jak vytvořit členitý terén. Abychom udělali terén větším, změníme jeho měřítko na (40, 4.4, 40). Protože v naší scéně nemáme žádné dynamické světlo, změníme osvětlení na false. Dále nastavíme soubor terrain-texture.jpg jako první texturu pro terén a soubor detailmap3.jpg jako druhou texturu. Jako poslední nastavíme měřítko pro textury. První textura pokryje celý terén pouze jednou a druhá (detail map) 20krát. Výsledek této akce bude, že na terénu bude kamenitá textura a terén bude mít také na různých místech různé odstíny.

// add terrain scene node
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->setMaterialTexture(1, driver->getTexture(
"../../media/detailmap3.jpg"));

terrain->setMaterialType(video::EMT_DETAIL_MAP);
terrain->scaleTexture(1.0f, 20.0f);

Abychom mohli vytvořit detekci kolizí, musíme nejprve udělat triangle selector terénu. Pokud chcete vědět jak triangle selector funguje, přečtěte si tutoriál číslo 7: detekce kolizí. Triangle selector funguje stejně s terénem i Quake3 mapou. Přidáme kolizní animátor tak aby kamera nemohla procházet terénem.

// create triangle selector for the terrain	
scene::ITriangleSelector* selector =
smgr->createTerrainTriangleSelector(terrain, 0);
terrain->setTriangleSelector(selector);
selector->drop();

// create collision response animator and attach it to the camera
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();

Aby mohl uživatel měnit mezi normálním a síťovým vzhledem, vytvoříme instanci event recieveru která se o vše bude starat. Opět přidáme skybox který používáme i mnoha dalších irrlicht tutoriálech.

// create event receiver
MyEventReceiver receiver(terrain);
device->setEventReceiver(&receiver);

// create 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);

Tak a teď vše vykreslíme. V tuto chvíli by jste měli znát jak vytvářet terén pomocí irrlicht enginu.

	int lastFPS = -1;

while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, 0 );

smgr->drawAll();
env->drawAll();

driver->endScene();
// display frames per second in window title 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;
}

 

 

 

 


Kopírování obsahu bez souhlasu autorů je zakázáno.
Copyright 2007 Irrlicht3d.cz