Tutorial 12: Render To Texture
Přeložil: Martin Zima alias "RedDragCZ"
V tomto tutoriálu si ukážeme, jak renderovat scénu do textury. Render to texture (neboli RTT) je technologie často využívaná pro tvorbu různých speciálních efektů, využívá se například také při post-processingu obrazu. Jako bonus se také naučíme jak aktivovat spekulární highlighty (volně přeloženo “zrcadlové odrazy”).
|
| Lets start! |
Na začátku jako obvykle includneme hlavičkové soubory Irrlichtu, vytvoříme renderovací zařízení, atd.:
#include <irrlicht.h>
#include <iostream>
using namespace irr;
#pragma comment(lib, "Irrlicht.lib")
int main()
{
// nechme uživatele vybrat video driver
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; }
// vytvoříme Irrlicht zařízení a v případě neúspěchu ukončíme program
IrrlichtDevice *device =
createDevice(driverType, core::dimension2d(640, 480),
16, false, false);
if (device == 0)
return 1; // zařízení nemohlo být vytvořeno.
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager* smgr = device->getSceneManager();
gui::IGUIEnvironment* env = device->getGUIEnvironment(); |
Nyní načteme animovaný model faerie a vytvoříme mu scénový uzel. Novinkou je nastavení lesklosti materiálu na jinou hodnotu, než je 0 (což je výchozí nastavení). To aktivuje ty již zmíněné spekulární odrazy. Co stojí také za povšimnutí je, že zapínáme dynamické nasvětlování modelu, bez něj by nebyly žádné tyto světelné efekty možné.
// load and display animated fairy mesh
scene::IAnimatedMeshSceneNode* fairy = smgr->addAnimatedMeshSceneNode(
smgr->getMesh("../../media/faerie.md2"));
if (fairy)
{
fairy->setMaterialTexture(0, driver->getTexture("../../media/faerie2.bmp")); // nastavíme difuzní texturu
fairy->setMaterialFlag(video::EMF_LIGHTING, true); // povolíme dynamické nasvětlování
fairy->getMaterial(0).Shininess = 20.0f; // nastavíme velikost spekulárních odrazů
fairy->setPosition(core::vector3df(-10,0,-100));
} |
Nyní musíme nastavit světla. Jedno přidáme přímo do blízkosti uzlu samotného a aby nebyl model celkově příliš tmavý (= tedy pro vykompenzování toho, že jsme na něm povolili dynamické nasvětlování), aktivujeme ambientní světlo scény. Ambientní světla nemají žádnou pevně danou pozici ani směr a ovlivňují rovnoměrně všechny objekty ve scéně.
// přidáme bílé světlo
scene::ILightSceneNode* light = smgr->addLightSceneNode(0,
core::vector3df(-15,5,-105), video::SColorf(1.0f, 1.0f, 1.0f));
// nastavíme ambientní světlo
driver->setAmbientLight(video::SColor(0,60,60,60)); |
Dalším bodem v kódu jsou Vám již jistě dobře známé standardní úkony – přidání uživatelsky kontrolované kamery, vypnutí zobrazování kurzoru myši a přidání testovací krychle, kterou necháme pro oživení rotovat.
// přidáme FPS-style kameru
scene::ICameraSceneNode* fpsCamera = smgr->addCameraSceneNodeFPS();
fpsCamera->setPosition(core::vector3df(-50,50,-150));
// zakážeme kurzor myši
device->getCursorControl()->setVisible(false);
// vytvoříme testovací krychli
scene::ISceneNode* test = smgr->addCubeSceneNode(60);
// vytvoříme rotační animátor krychle a zakážeme u ní dynamická světla
scene::ISceneNodeAnimator* anim = smgr->createRotationAnimator(
core::vector3df(0.3f, 0.3f,0));
test->setPosition(core::vector3df(-100,0,-100));
test->setMaterialFlag(video::EMF_LIGHTING, false); // disable dynamic lighting
test->addAnimator(anim);
anim->drop();
// nastavíme titulek okna
device->setWindowCaption( L"Irrlicht Engine - Render to Texture and Specular Highlights example"); |
Pro otestování RTT potřebujeme nejdříve vytvořit speciální render target texturu. Ta není jako jiné, klasické textury, potřebujeme ji nejdříve ručně vytvořit. To uděláme zavoláním metody IvideoDriver::createRenderTargetTexture() a specifikováním jejích rozměrů. Vzhledem k tomu, že RTT sdílí ZBuffer s Vaším normálním video driverem, nepoužívejte rozměry větší, než má Váš aktuální frame buffer. (Pozn.: Pokud byste chtěli využívat větších RTT, existuje pro Irrlicht patch, který to umožňuje – pak hledejte na oficiálním fóru v Code Snippets.)
Protože nechceme renderovat do textury ze stejné pozice, jako má uživatel, přidáme další kameru, tentokrát již s fixní pozicí. Ještě před provedením těchto všech kroků ale pro jistotu ověříme, zda-li současný video driver podporuje RTT a pokud ne, zobrazíme varování.
// create render target
video::ITexture* rt = 0;
scene::ICameraSceneNode* fixedCam = 0;
if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET))
{
rt = driver->createRenderTargetTexture(core::dimension2d(256,256));
test->setMaterialTexture(0, rt); // přiřadíme testovací krychli render target texturu
// přidáme fixní kameru
fixedCam = smgr->addCameraSceneNode(0, core::vector3df(10,10,-80),
core::vector3df(-10,10,-100));
}
else
{
// vytvoříme varování v případě chyby
gui::IGUISkin* skin = env->getSkin();
gui::IGUIFont* font = env->getFont("../../media/fonthaettenschweiler.bmp");
if (font)
skin->setFont(font);
gui::IGUIStaticText* text = env->addStaticText(
L"Your hardware or this renderer is not able to use the "\
L"render to texture feature. RTT Disabled.",
core::rect(150,20,470,60));
text->setOverrideColor(video::SColor(100,255,255,255));
} |
Téměř hotovo. Nyní musíme vše vykreslit. Každý snímek budeme renderovat scénu dvakrát – jednou do textury, podruhé tak jak to běžně známe, přímo do okna naší aplikace. Před RTT renderováním ovšem nejdříve zakážeme viditelnost naší testovací krychle, protože sama má na sobě výslednou renderovací texturu.
while(device->run())
if (device->isWindowActive())
{
driver->beginScene(true, true, 0);
if (rt)
{
// vykreslíme scénu do RTT
// nastavíme render target na naší texturu
driver->setRenderTarget(rt, true, true, video::SColor(0,0,0,255));
// zneviditelníme krychli a přepneme kameru
test->setVisible(false);
smgr->setActiveCamera(fixedCam);
// vykreslíme celou scénu do render bufferu
smgr->drawAll();
// nastavíme původní render target
driver->setRenderTarget(0);
// zviditelníme krychli a přepneme kameru zpět
test->setVisible(true);
smgr->setActiveCamera(fpsCamera);
}
// vykreslíme scénu normálním způsobem
smgr->drawAll();
env->drawAll();
driver->endScene();
}
if (rt)
rt->drop(); // dropneme RTT protože // jsem ji vytvořili pomocí create() metody
device->drop(); // dropneme Irrlicht zařízení
return 0;
}
|
A to je pro dnešek vše - nyní už víte, jak používat RTT v Irrlichtu. :-)
|
|