Hlavní navigace

Open Inventor: Vesmírná scéna (2)

12. 9. 2003
Doba čtení: 7 minut

Sdílet

V tomto dílu pokročíme o kousek dál s naší vesmírnou scénou. V prvé řadě zavítáme do tématu osvětlování scény a všeho, co se toho týká. A pak načneme téma rendrování trojúhelníků.

Dnes rozlouskneme otázku materiálů, světel a barev ve scéně. Open Inventor používá identický koncept osvětlování scény jako OpenGL, kdo tedy zná, bude mít ulehčenou práci. Dále rozebereme pojem „field“ (čti: fíld) jakožto nepostradatelnou věc v Inventoru a také nakousneme téma rendrování trojúhelníků.

Tabulka č. 487
2.3 – Solar Light Sluneční světlo
2.4 – Wire Box Drátěná krabice

Ty, kteří by zde očekávali matematické rovnice a popis výpočtu intenzity odraženého světla podle úhlu pohledu atd., možná trochu zklamu. Používání světel a barev mi připadlo docela intuitivní i bez těchto znalostí a ti, kteří dospějí k potřebě rozumět všem těmto věcem, je najdou v jedné z mnoha knih o OpenGL nebo grafice vůbec.

Příklad 2.3: Solar Light (Sluneční světlo)

V tomto příkladu si budeme vyprávět o tom, jak se dnes provádí osvětlování scén. Určitě tušíme, že scéna bude mít tendenci být tmavá, pokud do ní neumístíme světla. Abych navodil komplexnost celého problému, řeknu ještě, že barva objektu se nespecifikuje jen jednou barevnou složkou, ale hned čtyřmi.

Nejjednodušší bude začít u nodu SoMaterial. Pokud si ho nechcete hledat v dokumentaci, tak vězte, že má šest datových položek. V tomhle okamžiku už ale přestává být vhodné schovávat za slovy „datová položka“ velké slovo field [čte se anglicky: fíld]. Datové položky v nodech tedy nejsou klasické int, float nebo enum známé z jazyka C, místo toho jsou tyto jednoduché typy zapouzdřeny ve třídách odvozených od SoField. Někdo by mohl říci, že je to plýtvání pamětí, zapouzdřovat takovéto jednoduché proměnné, avšak SoField nám k dané datové položce přidá pouze 12 byte (ukazatel na VMT, integer a pointer). Za tuto cenu získáme funkce jako automatické ukládání a načítání fieldu ze streamu, připojování jednoho fieldu na druhý nebo na výstup SoEngine (příklad 1.2), můžeme připojovat sensory pro detekci změny hodnoty a samozřejmě mnoho vnitřních funkcí by bez tohoto zapouzdření nemohlo existovat. Jako příklad si můžeme uvést kus grafu scény, který je uložený v render-cache. Jakmile tento graf někdo modifikuje, Inventor detekuje modifikaci a automaticky zneplatňuje tuto cache.

Fields jsou tedy v Inventoru nezbytné. Obecně je můžeme rozdělit do dvou kategorií. První jsou fieldy, které uchovávají pouze jedinou hodnotu, a pak ty pro více hodnot. Jednohodnotová je například SoSFInt32 (předpona SoSF) a vícehodnotová SoMFFloat (předpona SoMF). K čemu nám ale ty vícehodnotové jsou? Například pro uložení souřadnic jednoho trojúhelníku potřebujeme tři body, jinak řečeno tři vektory. Pro triangle-strip (proužek trojúhelníků) je jich potřeba mnohem více. Toto vše nám obslouží SoMFVec3f, kde těchto vektorů můžeme uložit libovolné množství. SoMFVec3f je totiž třída pro ukládání vektorů složených ze třech floatů. Pro více informací o kterékoliv ze zmíněných tříd doporučuji nahlédnout do dokumentace (link na ni byl ve druhém dílu tohoto seriálu).

Když se tedy vrátíme k našemu nodu SoMaterial, tak v dokumentaci najdeme tyto položky:

SoMFColor ambientColor
SoMFColor diffuseColor
SoMFColor specularColor
SoMFColor emissiveColor
SoMFFloat shininess
SoMFFloat transparency

Může nám být divné, že se používají vícehodnotové fieldy místo očekávaných jednohodnotových. V tom je však skrytý úmysl, který si ukážeme později. Nám zatím bude stačit, že do těchto fieldů budeme ukládat jen jednu hodnotu.

Pojďme ale změnit téma a vrhněme se na barvy a modely osvětlování scén. Jak jsme si řekli, začneme od SoMaterial. Ten obsahuje fieldy dokonce pro čtyři různé barvy, dále lesklost (shininess) a transparentnost.

Znalci OpenGL už možná vidí, že celý koncept barev přesně odpovídá OpenGL. Těm méně zasvěceným se může zdát divné, že to, co by mělo mít jednu barvu, má zde barvy čtyři.

Vše nám objasní následující obrázek, který na určitých místech zvýrazňuje efekt jednotlivých barev. Jedná se o screenshot z tohoto příkladu. Vidíme Slunce a dvě planety – Merkur a Venuši. Jen byly pro účely demonstrace trochu pozměněny barvy (kdo kdy viděl, aby se planeta leskla).


Detailní význam všech položek SoMaterial uvádí následující tabulka:

Tabulka č. 488
ambientColor barva objektu při osvětlení pouze barvou okolí (nastavuje se nodem SoEnvironment)
diffuseColor barva při osvětlení světlem (třídy odvozené od SoLight)
specularColor barva způsobující lesk materiálu; koeficient lesklosti se udává ve fieldu shininess
emissiveColor barva, kterou má objekt sám, aniž by ho kdokoliv osvětloval
shininess lesklost materiálu; Platný rozsah je od 0.0 (matný povrch) po 1.0 (lesklý povrch).
transparency průhlednost materiálu; 0.0 značí naprosto neprůhledný materiál, 1.0 zase úplně průhledný.

Všechny čtyři barvy se počítájí odděleně svým vlastním postupem, pak se to všechno sečte a máme výslednou barevnou intenzitu pro daný bod. Na tu je ještě aplikována transparentnost v případě, že je nenulová, a barva výsledného pixelu je zanesena na obrazovku.

Další nody, které budeme potřebovat pro naše osvětlování scény, jsou SoEnvironment a světla. SoEnvironment (environment = prostředí) se používá především ke dvěma věcem: nastavení ambientního světla a mlhy. Ač je to triviální, nastavit mlhu, tak to tentokrát zkoušet nebudeme (do vesmíru se to moc nehodí). Pokud byste chtěli sami experimentovat, vězte, že na stejnou barvu, na jakou nastavujete mlhu, je vhodné nastavit i pozadí (SoQtRenderAre­a::setBackgrou­ndColor()). Pak vše vypadá perfektně.

Naše ambientní světlo nastavíme tímto způsobem:

  // Nastavíme vlastnosti prostředí,
  // ambientColor necháme na bílou, ale intenzitu
  // nastavíme na 0.25.
  SoEnvironment *envir = new SoEnvironment;
  envir->ambientIntensity.setValue(0.25f);
  root->addChild(envir);

Field ambientColor nastavovat nemusíme, protože implicitně obsahuje bílou barvu.

Tím bychom skončili se SoEnvironment a dostáváme se do finále, neboť jsou na řadě světla, a pak už budeme kompilovat náš příklad. Začneme trochu netradičně od diagramu dědičnosti:

Nás v tuto chvíli zajímají pouze třídy od SoLight dolů (plánuju jednou připravit kompletní diagam všech tříd Open Inventoru). Jak vidíme na diagramu, máme tři druhy světel: bodové (SoPointLight), směrové (SoDirectional­Light) a reflektorové (SoSpotLight). Bodové světlo nám svítí z jednoho bodu všemi směry. Příkladem může být žárovka či plamen svíčky. Směrové světlo nám do scény přichází z jednoho směru, například od velmi vzdáleného zdroje. Příkladem může být Slunce svítící na Zemi a na nás. Zvláštností tohoto světla je, že není příliš náročné na hardware v porovnání s ostatními dvěma. SpotLight je světlo nejlépe známé snad z divadel, kde nám z reflektoru vychází kužel světla.

Už z rozdílné povahy jednotlivých světel můžeme tušit, že budou mít fieldy různých významů. To, co mají společného, je ukryto v jejich rodičovské třídě SoLight:

Tabulka č. 489
SoSFBool on zapíná a vypíná světlo
SoSFFloat intensity intenzita světla
SoSFColor color barva světla; standardně nastaveno na bílou

A nyní k jednotlivým třídám:

Tabulka č. 490
SoPointLight  
SoSFVec3f location pozice světla
SoDirectionalLight  
SoSFVec3f direction směr světelného toku
SoSpotLight  
SoSFVec3f location
SoSFVec3f direction
SoSFFloat dropOffRate
SoSFFloat cutOffAngle
pozice světla
směr
úbytek světla od přímého směru
úhel, za kterým je již intenzita světla nulová

Pokud by snad někdo trval na detailnějším popisu tříd, je zde dokumentace, která je i při mé práci stálým a nenahraditelným zdrojem informací.

Náš příklad je ke stažení zde (Linux, Windows). V kódu, který je velmi podobný minulému příkladu, si můžeme všimnout několika podstatných míst:

  • Materiál planety je realizován ambientní a difuzní barvou.
  • Slunce je realizováno materiálem s dominující emisní složkou. Osvětlení okolních planet Sluncem je dáno bodovým světlem (SoPointLight), které je umístěno ve středu Slunce.
  • Implicitní světlo vieweru (které se umísťuje do pozice pozorovatele) je vypnuto, poněvadž scéna je správně osvětlená a toto světlo by rušilo (příkaz viewer->setHeadlight(FAL­SE)).

A můj screenshot, kterým uzavřeme tento příklad:


Příklad 2.4: Wire Box (Drátěná krabice)

Další příklad už dnes celý nestihneme. Přesto, abych vás o něj neošidil úplně, si ho můžete stáhnout (Linux, Windows).

V tomto příkladu si příště řekneme, jak rendrovat trojúhelníky. S jejich pomocí pak vytvoříme hvězdné pozadí. Fígl je v tom, že celou scénu zabalíme do krychle, na jejíž stěny naneseme textury, a vše to pak vypadá jako efektní pozadí.

My zde budeme rendrovat zatím jen drátěný model, jak je ukázáno na obrázku:


Po spuštění vás však může překvapit jedna věc – jiné ovládání. SoExaminerViewer byl totiž nahrazen SoFlyViewerem, takže nyní můžete skrz scénu létat. Ovládání rozhodně není tak intuitivní jako v Quake3 a podobně, nicméně scénu si s tím můžeme prohlédnout velmi dobře. Pravým tlačítkem přidáváme rychlost, prostředním tlačítkem ubíráme (prostřední je dnes bohužel většinou realizováno stiskem kolečka na myši). Dole na obrazovce máme rychloměr. Pokud se pohybujeme, FlyViewer zatáčí směrem, kam míří myš. „s“ i „q“ fungují obvyklým způsobem. Navíc je zde Ctrl, který zastaví pohyb, a můžete kameru namířit novým směrem. Tlačítko Home pomůže vždy, když se v prostoru ztratíme.

UX DAy - tip 2

Na tento příklad tedy navážeme příště detailnějším rozborem.

Závěr

Příště si detailněji osvětlíme rendrování trojúhelníků, jsou totiž dva způsoby, jak to provádět. Poté otexturujeme planety a snad dokončíme i hvězdné pozadí.

Byl pro vás článek přínosný?