Hlavní navigace

Open Inventor: Jednoduché příklady

Jan Pečiva 29. 8. 2003

Ve třetím díle našeho seriálu si ukážeme pár jednoduchých příkladů, které nás rychle uvedou do možností, jenž nám Open Inventor nabízí.

Minule jsme jednoduchou aplikací HelloCone zahájili první sérii příkladů, které nás mají uvést do inventorského světa. Dnes na HelloCone navážeme dalšími třemi příklady:

Tabulka č. 477
1.2 – Cone and Engine engine jako motor pro pohyb ve scéně
1.3 – Cone with Manipulator manipulátory pro manipulaci s objekty
1.4 – Cone and Viewer pohyb pozorovatele ve scéně

Nebudeme tedy otálet a přejdeme hned k prvnímu příkladu.

Příklad 1.2: Cone and Engine (Kužel a engine)

Open Inventor umožňuje ukládat do grafu scény i chování objektů. K tomu slouží množina tříd odvozených ze SoEngine (engine = motor). Cílem tohoto příkladu tedy bude rotující kužel, jak je ukázáno na obrázku:


Graf scény, který budeme vytvářet, je oproti minulému příkladu HelloCone obohacen o nod SoRotationXYZ a engine typu SoElapsedTime. SoRotationXYZ provádí rotaci podle jedné ze souřadných os. Pro pochopení celého principu se musíme nodu SoRotationXYZ podívat blíže na zoubek.

SoRotationXYZ obsahuje dvě datové položky: axis a angle. Axis říká, podle které osy budeme rotovat, a angle o kolik. Podíváme-li se blíže, zjistíme, že axis není prostý c-čkovský enum s možnostmi X,Y a Z, nýbrž objekt typu SoSFEnum a angle není float, ale SoSFFloat. Proč takové složitosti? Tyto třídy totiž umožňují Open Inventoru provádět mnoho kouzel. Jednou z nich je například připojení jedné datové položky na jinou. A právě to provedeme my v našem přikladu.

SoElapsedTime je engine pracující s časem. Má několik vstupů, kterými můžeme ovlivnit její funkčnost. Pro nás však bude nejdůležitější její výstup zvaný „timeOut“, tedy výstup času. Ten obsahuje hodnotu, která se s časem zvětšuje. Pokud neměníme vstup speed, je rychlost shodná s plynutím času, tj. zvýší se o jedničku za sekundu.

Graf scény, který budeme konstruovat, vypadá takto:

Vidíme, že graf scény je velmi podobný s příkladem HelloCone. Navíc přibývá pouze kód vytvoření SoRotationXYZ a SoElapsedTime:

  SoRotationXYZ *rotXYZ = new SoRotationXYZ;
 rotXYZ->axis = SoRotationXYZ::X;
  root->addChild(rotXYZ);

Kód pro SoElapsedEngine a její připojení na SoRotationXYZ::an­gle:

  SoElapsedTime *counter = new SoElapsedTime;
  rotXYZ->angle.connectFrom(&counter->timeOut);

Zde je kód celého příkladu:

//
// Příklad 1.2 - Cone And Engine
//


#include <Inventor/Qt/SoQt.h>
#include <Inventor/Qt/SoQtRenderArea.h>
#include <Inventor/nodes/SoCone.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Inventor/nodes/SoRotationXYZ.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/engines/SoElapsedTime.h>


int main(int , char **argv)
{
  // Inicializuj Inventor
  QWidget *window = SoQt::init(argv[0]);
  if (window == NULL) exit(1);

  // Vytvoř kořen scény
  SoSeparator *root = new SoSeparator;
  root->ref();

  // Vlož kameru do scény
  SoPerspectiveCamera *camera = new SoPerspectiveCamera;
  root->addChild(camera);

  // Světlo
  root->addChild(new SoDirectionalLight);

  // Materiál
  SoMaterial *material = new SoMaterial;
  material->diffuseColor.setValue(1.0, 0.0, 0.0);
  root->addChild(material);

  // Rotační node
  SoRotationXYZ *rotXYZ = new SoRotationXYZ;
  rotXYZ->axis = SoRotationXYZ::X;
  root->addChild(rotXYZ);

  // Připojení engine na vstup rotačního node
  SoElapsedTime *counter = new SoElapsedTime;
  rotXYZ->angle.connectFrom(&counter->timeOut);

  // Kužel
  root->addChild(new SoCone);

  // Vytvoř renderovací okno
  SoQtRenderArea *renderArea = new SoQtRenderArea(window);

  // Nastav parametry kamery
  camera->viewAll(root, renderArea->getViewportRegion());

  // Nastav renderovací okno
  renderArea->setSceneGraph(root);
  renderArea->setTitle("Engine Spin");
  renderArea->show();

  // Zobraz okna a rozjeď renderovací smyčku
  SoQt::show(window);
  SoQt::mainLoop();

  // Uvolni paměť
  delete renderArea;
  root->unref();

  return 0;
}

Příklad je k dispozici ke stažení opět ve dvou verzích – pro Linux a Windows.

Vše je myslím vcelku jasné, neboť většina kódu pochází z prvního příkladu. Pozorný programátor se snad jen může ptát, kde se v našem příkladu uvolňují objekty, které vytváříme při konstrukci scény. Odpověď je, že ve volání root->unref() na závěr našeho příkladu. Open Inventor totiž používá techniku „reference counting“, přeložitelnou snad jako počítání referencí. Každý objekt scény má počítadlo referencí a pokud toto počítadlo klesne na nulu, objekt je uvolněn z paměti. V příkladu vidíme sice „zareferencování“ a „odreferencování“ pouze jediného objektu – root, ve skutečnosti však referencování provádí Inventor vnitřně kdykoliv je to potřeba. Například pokud vytvoříme objekt a přidáme jej jako syna jiného nodu, tento syn je automaticky zareferencován jeho otcem. Když pak v závěru příkladu odreferencováváme root, klesne jeho počítadlo referencí na nulu a objekt je uvolněn z paměti. Během tohoto procesu on odreferencuje své syny. A protože synové nejsou nikým jiným referencováni, klesnou jejich počítadla také na nulu a celá scéna je tímto způsobem uvolněna. To se týká nejen všech našich nodů, ale i engine, která je součástí naší scény a která je zareferencována díky jejímu připojení na SoRotationXYZ::an­gle.

Příklad 1.3: Cone with Manipulator (Kužel s manipulátorem)

Manipulátory slouží k jednoduché manipulaci s objekty scény. My v našem příkladu použijeme trackballový manipulátor – SoTrackballManip. Ten slouží k „rotační“ manipulaci – objekt můžeme zrotovat do polohy, jaké chceme. Neslouží tedy k přemísťování objektů. Pro tento účel bychom museli použít jiné manipulátory, například SoHandleBoxManip nebo SoTransformBox­Manip.

Zkonstruujeme tedy graf scény v této podobě:

Kód tedy zůstává skoro stejný, až na vytvoření manipulátoru:

  SoTrackballManip *manip = new SoTrackballManip;
  root->addChild(manip);

Zdrojáky si můžete stáhnout pro Linux a Windows.

Výsledný screenshot:


Ovládání trackballového manipulátoru je vcelku jednoduché. Pokud chytnete za jeden ze tří prstenců, můžete s objektem podle osy tohoto prstence rotovat. Pokud manipulátor chytnete kdekoliv jinde, vyberou se všechny tři prstence a můžeme si užít pravé trackballové manipulace.

Pokud chcete zkusit jiný druh manipulátoru, stačí jen nahradit všechny výskyty SoTrackballManip za jiný manipulátor.

Příklad 1.4: Cone and Viewer (Kužel a prohlížeč)

Až dosud jsme si „užívali“ jen velmi jednoduchých scén, ve které jsme se navíc ani nemohli pohybovat. První nedostatek odstraníme až příště, ale pohybovat se ve scéně se naučíme už nyní.

Základní operace pro manipulaci s pohledem pozorovatele do scény jsou zapouzdřeny ve třídě SoQtViewer (na Windows SoWinViewer) a tříd od ní odvozených. Jen pro dokreslení skutečnosti: SoQtViewer je odvozena od SoQtRenderArea, kterou jsme používali až dosud pro zobrazování scény. A od SoQtViewer se odvozují další třídy, mezi které patří i SoQtExaminer­Viewer, kterou budeme v tomto příkladu používat.

Kód příkladu je velmi podobný našemu HelloCone. Nahrazení SoQtRenderArea za SoQtExaminerViewer je málem provedeno pouhou záměnou. Zde je odpovídající kód:

  // Vytvoř okno prohlížeče
  SoQtExaminerViewer *viewer = new SoQtExaminerViewer(window);
  viewer->setSceneGraph(root);
  viewer->setTitle("Examiner Viewer");
  viewer->show();

  // Zobraz okna a rozjeď renderovací smyčku
  SoQt::show(window);
  SoQt::mainLoop();

  // Uvolni paměť
  delete viewer;
  root->unref();

Další změna v kódu je při samotné konstrukci scény – zmizela nám kamera a světlo. Důvod je v tom, že všichni potomci třídy SoQtViewer, tedy i náš SoQtExaminerViewer, obslouží tyto věci za nás. Pokud scéna neobsahuje kameru, SoQtViewer ji přidá automaticky. Mnoho scén také neobsahuje žádná světla, proto SoQtViewer jedno umístí do pozice pozorovatele. Tato kamera a světlo se nepřidávají přímo do naší scény, což by mohlo mít nežádoucí efekty, ale do skryté scény SoQtVieweru, takže naše scéna zůstává nedotčená. Zde je kód konstrukce scény:

  // Vytvoř kořen scény
  SoSeparator *root = new SoSeparator;
  root->ref();

  // Materiál
  SoMaterial *material = new SoMaterial;
  material->diffuseColor.setValue(1.0, 0.0, 0.0);
  root->addChild(material);

  // Kužel
  root->addChild(new SoCone);

Můžeme si stáhnout kód pro Linux a Windows.

Po spuštění se nám naskytne pohled podobný následujícímu obrázku:

Vidíme, že nám na okrajích okna přibyly ovládací prvky a kolečka pro ovládání pohledu do scény. ExaminerViewer je určen k prohlížení modelů, proto nečekejme chování kamery podobné těm ve 3D hrách. Pro to je mnohem vhodnější SoQtFlyViewer, se kterým se seznámíme v přespříštím díle.

Nyní k tomu, co všechno ExaminerViewer umí. Myší můžeme manipulovat s modelem, dokonce ho můžeme i roztočit. Kolečkama rotujeme a přibližujeme se k němu. Nejzajímavější bude asi použití menu, do kterého se dostaneme pravým tlačítkem. V něm vybereme Draw Styles → Still Drawstile → a vybereme wireframe nebo hidden line a naskytne se nám pohled na tzv. drátěný model. Někdy je to docela zajímavá podívaná, hlavně u složitějších modelů.

Z dalších tlačítek, které se nám mohou hodit, je „s“ pro „seek mode“ – tedy posunutí. Klikneme někde na kužel a kamera „přiletí“ k tomuto místu. Jedno upozornění: Vrchol kužele není jediné místo, které je zajímavé :-) . Pokud se při „seekování“ nechtěně ztratíte někde v prostoru, je zde tlačítko home, které nás vrátí do výchozí pozice kamery. Poslední tlačítko, které si uvedeme, je „q“ pro ukončení aplikace.

Závěr

Přeji mnoho zábavy s příklady a těším se na příští díl, kdy si ukážeme už něco ze složitějších a zábavnějších scén, se kterými stvoříme naši sluneční soustavu.

Našli jste v článku chybu?

29. 8. 2003 22:49

David Brodsky (neregistrovaný)

Ono je taky vhodne zkusit delat neco sam a nejen priklady (nebo mit cil). Vzhledem k tomu, ze zde popisovane priklady jsou presne popsany v Inventor Mentor (v predminule diskuzi byl i odkaz), tak neni problem postoupit i trochu dal. Dalsi pomerne dobry pomocnik je dokumentace ze zdrojaku.
Ja jsem s open inventorem zacal delat az teprve pote, co se objevil prvni clanek. Stahl jsem i Inventor Mentor a dnes uz mam udelanou scenu, ve ktere se pohybuji stylem nekterych 3d her (sipky + mys) a umim po…

29. 8. 2003 17:06

PCJohn (neregistrovaný)

Diky,
budu se snazit :-)


Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

DigiZone.cz: Česká televize mění schéma ČT :D

Česká televize mění schéma ČT :D

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Vitalia.cz: „Připluly“ z Německa a možná obsahují jed

„Připluly“ z Německa a možná obsahují jed

Lupa.cz: Google měl výpadek, nejel Gmail ani YouTube

Google měl výpadek, nejel Gmail ani YouTube

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí

Podnikatel.cz: 1. den EET? Problémy s pokladnami

1. den EET? Problémy s pokladnami

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

DigiZone.cz: NG natáčí v Praze seriál o Einsteinovi

NG natáčí v Praze seriál o Einsteinovi

Vitalia.cz: Chtějí si léčit kvasinky. Lék je jen v Německu

Chtějí si léčit kvasinky. Lék je jen v Německu

Měšec.cz: Jak vymáhat výživné zadarmo?

Jak vymáhat výživné zadarmo?

Lupa.cz: Babiš: E-shopů se EET možná nebude týkat

Babiš: E-shopů se EET možná nebude týkat

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

Vitalia.cz: Paštiky plné masa ho zatím neuživí

Paštiky plné masa ho zatím neuživí

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

120na80.cz: Bojíte se encefalitidy?

Bojíte se encefalitidy?

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?