J3DT_1 - Začínáme

Cíle kapitoly

Po přečtení této kapitoly budeme:

Java 3D API je rozhraní pro psaní programů k zobrazení a interakci s trojrozměrnou grafikou. Java 3D je standardní rozšíření Java 2 SDK. API poskytuje kolekci vysokoúrovňových konstrukcí pro tvorbu a manipulaci 3D geometrie a vykreslování této geometrie. Java 3D poskytuje funkce pro tvorbu obrázků, vizualizací, animací a interaktivních 3D aplikací a programů.

1.1 Co je to Java 3D API ?

Java 3D API je hierarchie Java tříd které slouží jako rozhraní pro sofistikované trojrozměrné grafické vykreslování a prostorové ozvučení. Programátor pracuje s vysokoúrovňovými konstrukcemi pro tvorbu a manipulaci 3D geometrických objektů. Tyto geometrické objekty jsou umístěny ve virtuální vesmíru, který je následně vykreslován. API je flexibilně navrženo pro tvorbu přesných virtuálních vesmírů široké škály velikostí, od astronomických po subatomární.

Přes všechnu funkcionalitu je stále jednoduché API používat. Detaily vykreslování jsou obsluhovány automaticky. Díky výhodě jakou je práce s Java vlákny, je Java 3D jádro (renderer) schopno vykreslovat paralelně. Jádro také provádí automatickou optimalizaci která zvyšuje vykreslovací výkon.

Java 3D program vytváří instance Java 3D objektů a umisťuje je do datové struktury graf scény. Graf scény je uspořádáním 3D objektů ve stromové struktuře která kompletně specifikuje obsah virtuálního vesmíru, a to jak bude vykreslován.

Java 3D programy mohou být psány jako samostatné aplikace stejně jako applety do prohlížečů které mají rozšíření podporující Java 3D, nebo obojí.

1.2 Java 3D API

Každý Java 3D program je sestaven z objektů z hierarchie tříd Java 3D. Tato kolekce objektů popisuje virtuální vesmír který se má vykreslit. API definuje přes 100 tříd přítomných v balíčku javax.media.j3d. Tyto třídy se obecně nazývají třídy jádra Java 3D.

Ve třídách Java 3D API existují stovky rozhraní a metod. Avšak jednoduchý virtuální vesmír který obsahuje animaci může být postaven jen z pár tříd. Tato kapitola popisuje minimální sadu objektů a jejich interakcí k vykreslení jednoduchého virtuálního vesmíru.

Tato kapitola zahrnuje vývoj jednoho ale kompletního Java 3D programu s názvem HelloJava3D, který zobrazuje otáčející se krychli. Program je vyvíjen postupně a je přítomen ve více verzích, aby demonstroval každou část procesu programování v Java 3D. Všechny programy obsažené v tomto tutoriálu jsou dostupné v elektronické podobě.

V programování s balíčkem Java 3D se používají i další balíčky. Jedním takovým balíčkem je com.sun.j3d.utils který se obecně nazývá pomocným balíčkem pro Java 3D. Balíček obsahující třídy jádra zahrnuje pouze třídy nejnižší úrovně nezbytné pro programování v Java 3D. Třídy v pomocném balíčku jsou silným přídavkem k jádru.

Pomocné třídy spadají do čtyř hlavních kategorií: pro načítání obsahu, pomocné třídy pro vytváření grafu scény, geometrické třídy a pomocné třídy. Budoucí funkční doplňky, jako NURBS budou přidány jako třídy utilit, ne do balíčku jádra Java 3D. Některé třídy utilit mohou být přestěhovány do balíčku jádra v budoucích verzích Java 3D API.

Používání pomocných tříd značně redukuje počet řádků kódu v Java 3D programu. Kromě balíčků jádra a pomocných balíčků Java 3D s třídami používá každý Java 3D program třídy z balíčku java.awt a javax.vecmath. Balíček java.awt obsahuje Abstract Windowing Toolkit – AWT. Třídy AWT vytváří okno k zobrazení vykreslování. Balíček javax.vecmath obsahuje vektorové matematické třídy pro body, vektory, matice a ostatní matematické objekty.

Ve zbytku textu bude termín vizuální objekt představovat „objekt v grafu scény“ (např. krychli nebo kouli). Termín objekt představuje instanci třídy. Termín obsah je použit jako název pro vizuální objekty v grafu scény jako celku.

1.3 Stavíme Graf Scény

Java 3D virtuální vesmír je vytvořen z grafu scény. Graf scény se vytvoří použitím instancí tříd Java 3D. Graf scény je sestaven z objektů definujících geometrii, zvuk, světla, umístění, orientace a vzhledu vizuálních a audio objektů.

Obecná definice grafu je, že jde o datovou strukturu složenou z uzlů a referencí. Uzel je datový prvek a reference je vztah mezi datovými prvky. Uzly v grafu scény jsou instance tříd Java 3D. Reference představují dva druhy vztahů mezi Java 3D instancemi.

Nejběžnějším vztahem je vztah rodič-dítě. Skupina uzel může mít jakýkoliv počet dětí, ale jen jednoho rodiče. List uzlu může mít jednoho rodiče a žádné dítě. Jiným vztahem je odkaz (reference). Odkaz spojuje objekt NodeComponent s grafem scény Node. Objekty NodeComponent definují geometrické a vzhledové atributy použité k vykreslení vizuálních objektů.

Graf scény v Java 3D je zkonstruován z objektů Node v rodičovsko-dětských vztazích vytvářejících stromovou strukturu. Ve stromové struktuře je jeden z uzlů kořenem. Ostatní uzly jsou přístupné přes reference z kořene. Reference stromu nevytváří žádné cykly. Graf scény je tvořen ze stromů které mají kořeny v objektech Locale. NodeComponents a odkazy a nejsou součástí stromu grafu scény.

Od kořene stromu existuje jen jedna cesta ke každému z listů; takže existuje jedna cesta z kořene grafu scény ke každému uzlu listu. Cesta z kořene grafu scény ke konkrétnímu uzlu listu je cesta grafu scény uzlu listu. Jestliže cesta grafu scény vede přesně k jednomu listu, pak existuje jedna cesta grafu scény pro každý list v grafu scény. Každá cesta grafu scény v Java 3D grafu scény kompletně specifikuje informaci o stavu svého listu. Informace o stavu zahrnuje umístění, orientaci a velikost vizuálního objektu. Z toho vyplývá že vizuální vlastnosti každého vizuálního objektu závisí jen na cestě grafu scény daného objektu. Vykreslovací jádro Java 3D těží z tohoto faktu a vykresluje listy v pořadí které si samo určí jako nejefektivnější. Programátor v Java 3D normálně nemá kontrolu nad pořadím vykreslování objektů. Jedinou kontrolu nad pořadím vykreslování má programátor pomocí třídy OrderedGroup. Tato třída není v tomto tutoriálu popsána. Viz Java 3D API specifikace.

Grafické reprezentace grafu scény mohou sloužit jako návrhové / dokumentační nástroje pro Java 3D programy. Grafy scény se kreslí standardními grafickými symboly jako na obrázku 1-1. Java 3D programy mohou mít mnohem více objektů než v tomto grafu scény.

K navrhování Java 3D virtuálního vesmíru se graf scény kreslí pomocí standardní sady symbolů. Poté co je návrh kompletní, ten samý graf je zkrácenou reprezentací programu (za předpokladu že byl vytvořen podle specifikace). Graf scény nakreslený dle existujícího programu dokumentuje graf scény který program vytváří.

Obrázek 1-1: Symboly představující objekty v grafech scén

Každý ze symbolů na levé straně obrázku 1-1 reprezentuje samotný objekt použitý v grafu scény. První dva symboly reprezentují objekty dvou konkrétních tříd: VirtualUniverse a Locale. Další tři symboly vlevo objekty třídy Group, Leaf a NodeComponent. Tyto tři symboly jsou často komentovány - indikují podtřídu určitého objektu. Poslední symbol vlevo se používá jako reprezentace pro jakýkoli jiný objekt.

Plná šipka představuje vztah rodič-dítě mezi dvěma objekty. Čárkovaná šipka je odkaz na jiný objekt. Odkazované objekty mohou být sdíleny mezi různými větvemi grafu scény. Příklad jednoduchého grafu scény je na obrázku 1-2.

Obrázek 1-2: Příklad prvního grafu scény

Je možné vytvořit neplatný graf scény. Příklad neplatného grafu scény je na obrázku 1-3. Graf scény na obrázku 1-3 je neplatný protože narušuje vlastnosti pro DAG. Jediný problém je v tom, že dva objekty TransformGroup mají jako dítě jeden objekt Shape3D který tvoří list. Pamatujme že objekt Leaf může mít jen jednoho rodiče. Jinými slovy, může existovat jen jedna cesta z objektu Locale k listu (nebo jedna cesta z listu k Locale).

Pozn. překladatele – DAG je zkratka pro Directed Acyclic Graph, čili směrovaný acyklický (nevytvářející cyklickou strukturu) graf. Je to datová struktura sestavená z prvků směrovaných referencí (ne ve smyslu odkazů na objekt) které netvoří žádné cykly. Ve světě Java 3D jsou prvky DAG objekty Group a Leaf a odkazy jsou ve vztazích rodič – dítě mezi těmito objekty. Vytvoření acyklické struktury znamená že žádný prvek nemůže být zároveň svým vlastním rodičem.

Může to vypadat tak, že struktura na obrázku 1-3 definuje tři vizuální objekty ve virtuálním vesmíru. Zdá se že graf scény definuje dva vizuální objekty skrze znovupoužití vizuálního, Shape3D objektu na pravé polovině obrázku. Každý z objektů TransformGroup je rodičem sdílené instance Shape3D může umístit obrázek vizuálního objektu jinam. Avšak je to neplatný graf scény protože reference rodič-dítě netvoří strom. V tomto případě je výsledkem to že objekt Shape3D má více než jednoho rodiče.

Diskuse kolem stromu v DAG strukturách jsou správné. Java 3D runtime systém hlásí chybu pokud narazí na neplatný vztah rodič-dítě. Jedním z důsledků stromové struktury je, že každý objekt Shape3D je omezen na jednoho rodiče. Na obrázku 1-4 je oprava grafu scény kde má každý objekt Shape3D svého rodiče.

Obrázek 1-3: Příklad neplatného grafu scény

Java 3D program který obsahuje neplatný graf scény se může přeložit, ale nevykresluje. Když Java 3D program který definuje neplatný graf scény běží, Java 3D systém detekuje problém. Když je problém detekován, Java 3D systém vyvolá výjimku. Program může pořád běžet dokud ho nevypneme, avšak nevykreslí se žádný obrázek.

Obrázek 1-4: Jedna z možných oprav neplatného grafu scény z obrázku 1-3

Každý graf scény má jeden objekt VirtualUniverse. Objekt VirtualUniverse má seznam objektů Locale. Objekt Locale poskytuje referenční bod ve virtuálním vesmíru. Představme si objekt Locale jako značku určující umístění vizuálních objektů ve virtuálním vesmíru.

Technicky je možné mít v Java 3D programu více než jeden objekt VirtualUniverse, takže definuje více než jeden virtuální vesmír. Ale není zde žádný dědičný vztah ke komunikaci mezi virtuálními vesmíry. A co víc, objekt grafu scény nemůže existovat ve více virtuálních vesmírech současně. Velmi se doporučuje mít jednu a pouze jednu instanci VirtualUniverse v každém Java 3D programu. I když může objekt VirtualUniverse odkazovat na více objektů Locale, většina Java 3D programů má jen jeden objekt Locale. Každý objekt Locale může sloužit jako kořen více subgrafů grafu scény. Podívejte se zpět na obrázek 1-2 kde je příklad grafu scény se dvěmi větvemi subgrafů z objektu Locale.

Objekt BranchGroup je kořen subgrafu nebo grafu větve. Existují dva druhy subgrafu scény: vizuální větev grafu a obsahová větev grafu. Obsahová větev grafu specifikuje obsah virtuálního vesmíru – geometrii, vzhled, chování, umístění, zvuky a světla. Vizuální větev grafu specifikuje pohledové parametry, jako umístění a směr pohledu. Dohromady dvě větve specifikují většinu práce kterou musí jádro vykreslit.

1.3.1 Hierarchie tříd vysokoúrovňového Java 3D API

Přehled prvních tří úrovní hierarchie Java 3D API je na obrázku 1-5. V této části hierarchie jsou třídy VirtualUniverse, Locale, Group a Leaf. Kromě objektů VirualUniverse a Locale je zbytek grafu scény složen z objektů SceneGraphObject. SceneGraphObject je nadtřídou pro každou Java 3D třídu z balíčku jádra a pomocného balíčku.

SceneGraphObject má dvě podtřídy: Node a NodeComponent. Podtřídy Node poskytují většinu objektů v grafu scény. Objekt Node je také objekt uzlu Group nebo Leaf. Group a Leaf jsou nadtřídy mnoha podtříd. Podívejme se letmo na třídu Node, její dvě podtřídy a třídu NodeComponent. Poté co je probereme si ukážeme příklad Java 3D programu.

Třída Node

Třída Node je abstraktní nadtřídou tříd Group a Leaf. Třída Node definuje některé obecně důležité metody pro svoje podtřídy. Informace o konkrétních metodách si ukážeme později poté co se dozvíme další podrobné informace. Podtřídy Node tvoří grafy scén.

Třída Group

Třída Group je nadtřída používaná k upřesnění polohy a orientace vizuálních objektů ve virtuálním vesmíru. Podtřídami třídy Group jsou třídy BranchGroup a TransformGroup. V grafické reprezentaci grafu scény jsou symboly Group (kroužky) často označeny s BG pro BranchGroups, TG pro TransformGroups atd. Viz obrázek 1-2.

Třída Leaf

Třída Leaf je nadtřídou používanou ke specifikaci tvaru, zvuku a chování vizuálních objektů ve virtuálním vesmíru. Některé z jejích podtříd jsou Shape3D, Light, Behavior a Sound. Tyto objekty nemají žádné děti ale mohou odkazovat na NodeComponents.

Třída NodeComponent

Třída NodeComponent je nadtřída používaná ke specifikaci geometrie, vzhledu, textury a vlastností materiálu uzlu Shape3D. NodeComponent není součástí grafu scény, ale je jím odkazována. NodeComponent může být odkazována více než jedním objektem Shape3D.

Obrázek 1-5: Přehled hierarchie tříd Java 3D API

1.4 Recept pro psaní Java 3D programů

Podtřídy třídy SceneGraphObject jsou stavebními kameny které jsou sestaveny do grafu scény. Základní šablona vývoje Java 3D programu sestává ze sedmi kroků (na kterou se odkazujeme jako na recept v Java 3D specifikaci) která je na uvedena níže. Tento recept může být použit k sestavení mnoha užitečných programů v Java 3D.

  1. vytvořte objekt Canvas3D
  2. Vytvořte objekt VirtualUniverse
  3. Vytvořte objekt Locale a připojte ho k objektu VirtualUniverse
  4. zkonstruujte graf vizuální větve:
    1. vytvořte objekt View
    2. vytvořte objekt ViewPlatform
    3. vytvořte objekt PhysicalBody
    4. vytvořte objekt PhysicalEnvironment
    5. připojte objekty ViewPlatform, PhysicalBody, PhysicalEnvironment a Shape3D k objektu View
  5. zkonstruujte graf(y) obsahové větve
  6. přeložte graf(y) větve
  7. vložte subgrafy do Locale

Tento recept ignoruje některé detaily ale ilustruje základní koncept celého Java 3D programování: vytvoření grafu každé větve grafu scény je většina programování. Další sekce vysvětluje lehčí cestu ke zkonstruování velmi podobného grafu scény s menším úsilím.

1.4.1 Jednoduchý recept pro psaní Java 3D programů

Java 3D programy napsané pomocí základního receptu mají grafy vizuální větve s identickou strukturou. Souměrnost struktury grafu vizuální větve je také v pomocné třídě SimpleUniverse. Instance třídy SimpleUniverse provádí kroky 2, 3 a 4 ze základního receptu. Použitím třídy SimpleUniverse lze značně redukovat čas a úsilí potřebné k vytvoření grafu vizuální větve v Java 3D programování. Programátor se tedy může více soustředit na obsah. A o tom je programování v Java 3D.

SimpleUniverse je dobrým začátkem programování v Java 3D, protože dovoluje programátorovi na chvíli zapomenout na grafy vizuální větve. Avšak použitím třídy SimpleUniverse neumožňuje mít více pohledů ve virtuálním vesmíru.

Třída SimpleUniverse je použita ve všech příkladech tohoto tutoriálu. Programátoři kteří potřebují více informací o třídách View, ViewPlatform, PhysicalBody a PhysicalEnvironment budou odkazováni na příslušné zdroje v Příloze B.

Třída SimpleUniverse

Konstruktor třídy SimpleUniverse vytváří graf scény včetně objektů VirtualUniverse a Locale a kompletní graf vizuální větve. Graf vizuální scény vytvořený třídou SimpleUniverse v tomto případě používá instance ViewingPlatform a Viewer místo tříd jádra. Všimněte si že SimpleUniverse jen nepřímo používá tříd View a ViewPlatform jádra Java 3D. Objekt SimpleUniverse zastupuje funkcionalitu všech objektů uvnitř rámečku na obrázku 1-7.

Obrázek 1-7: Objekt SimpleUniverse poskytuje minimalistický virtuální vesmír ohraničený čárkovanou čarou

Použití objektu SimpleUniverse nám zásadně zjednoduší základní recept. Seznam představuje jednoduchý recept, který je vlastně upraveným základním receptem s použitím objektu SimpleUniverse. Kroky 2, 3 a 4 ze základního receptu jsou nahrazeny krokem dva zjednodušeného receptu.

  1. vytvoříme objekt Canvas3D
  2. vytvoříme objekt SimpleUniverse který odkazuje na dříve vytvořený objekt Canvas3D
    1. upravíme si objekt SimpleUniverse dle našich představ
  3. zkonstruujeme obsahovou větev
  4. přeložíme graf obsahové větve
  5. vložíme graf obsahové větve do Locale v SimpleUniverse

Následující ohraničený text je první příklad referenčního bloku v tomto tutoriálu. Referenční blok obsahuje seznam konstruktorů, metod nebo rozhraní třídy. Referenční bloky mají za účel čtenáři umožnit naučit se základy Java 3D API bez toho aniž by museli mít po ruce nějakou jinou příručku. Referenční bloky v tomto tutoriálu neobsahují všechny konstruktory nebo metody třídy. Na druhou stranu je zde také ale několik tříd které nejsou zmíněny v žádném referenčním bloku v tomto tutoriálu. Takže tento tutoriál nenahrazuje Java 3D specifikaci. Avšak o těch konstruktorech, metodách a rozhraních které jsou uvedeny v referenčním bloku je zde více detailních informací než poskytuje Java 3D specifikace.


Konstruktory třídy SimpleUniverse

Balíček: com.sun.j3d.utils.universe

Tato třída nastavuje minimální uživatelské prostředí k rychlému a lehkému sestavení a spuštění Java 3D programu. Tato pomocná třída vytváří všechny nezbytné objekty pro graf vizuální větve. Přesněji, tato třída vytváří objekty Locale, VirtualUniverse, ViewingPlatform a Viewer (s jejich implicitními hodnotami). Všechny objekty mají příslušné vztahy aby mohly vytvořit graf vizuální větve.

SimpleUniverse poskytuje plnou funkcionalitu nezbytnou pro mnoho základních Java 3D programů. Třídy Viewer a ViewingPlatform jsou pomocné třídy. Tyto třídy používají třídy jádra View a ViewPlatform.

SimpleUniverse()

Zkonstruuje jednoduchý virtuální vesmír

SimpleUniverse(Canvas3D canvas3D)

Zkonstruuje také jednoduchý virtuální vesmír ale s odkazem na objekt Canvas3D


Objekt SimpleUniverse vytváří kompletní graf vizuální větve virtuálního vesmíru. Graf vizuální větve zahrnuje obrazovou rovinu. Rovina obrazu je obdélník na který se promítá obsah ve formě vykresleného obrázku. Objekt Canvas3D, který poskytuje obrázek v okně na našem monitoru může být takovou obrazovou rovinou.

Na obrázku 1-9 je nakreslen vztah mezi obrazovou rovinou, pozicí kamery (oka) a virtuálním vesmírem. Kamera je za obrazovou rovinou. Vizuální objekty před obrazovou rovinou jsou vykreslovány na obrazovou rovinu. Vykreslování je vlastně projekce vizuálních objektů na obrazovou rovinu. Tato myšlenka je ilustrována 4 projektory v obrázku (čárkované čáry).

Obrázek 1-9: koncept obrazové roviny a pozice oka pozorovatele ve virtuálním vesmíru

Implicitně je obrazová rovina umístěna v počátku SimpleUniverse. Osa Z roste směrem k pozici kamery. Osa X je horizontální úsečka v obrazové rovině jejíž hodnoty narůstají směrem doprava. Osa Y je vertikální úsečka v obrazové rovině jejíž hodnoty rostou směrem nahoru. Bod na souřadnicích (0, 0, 0) je centrem obrazové roviny.

Typický program v Java 3D posune pohled zpět (k pozitivním hodnotám na ose Z) aby byly objekty na nebo blízko počátku pohledu. Třída SimpleUnverse má členský objekt třídy ViewingPlatform. Třída ViewingPlatform má metodu setNominalViewingTransform() která umisťuje pozici oka na (0, 0, 2.41) vzhledem k počátku.


Metoda setNominalViewingTransform třídy ViewingPlatform

Balíček: com.sun.j3d.utils.universe

Třída ViewingPlatform se používá k nastavení grafu vizuální větve Java 3D grafu scény v objektu SimpleUniverse. Tato metoda se normálně používá ve spojení s metodou getViewingPlatform třídy SimpleUniverse.

void setNominalViewingTransform()

Nastaví hodnotu vzdálenosti na přibližně 2.41 metru v SimpleUniverse. Při téhle pohledové vzdálenosti a běžně velkém zorném poli objekty o výšce a šířce 2 metry vyplňují obrazovou rovinu.

Po vytvoření objektů Canvas3D a SimpleUniverse je dalším krokem vytvoření grafu obsahové větve. Souměrnost struktury v grafu vizuální větve neexistuje pro graf obsahové větve. Graf obsahové větve se liší program od programu a proto je nemožné poskytnout jakékoliv detailní informace o jeho vytváření. Také to znamená, že neexistuje nějaký „jednoduchý obsah“ pro jakýkoliv vesmír který můžeme chtít vybudovat.

Vytváření grafu obsahové větve je předmětem částí 1.6, 1.7 a 1.9 tohoto tutoriálu. Přeložení grafu obsahové větve je předmětem části 1.8 tohoto tutoriálu. Jestli se nemůžete dočkat až uvidíte nějakou část kódu, podívejte se na první ukázku kódu který ukazuje použití třídy SimpleUniverse.

Po vytvoření grafu obsahové větve jej vložíme do vesmíru pomocí metody addBranchGraph třídy SimpleUniverse. Metoda addBranchGraph má jediný parametr a tím je instance třídy BranchGroup. Objekt BranchGroup je přidán jako potomek objektu Locale vytvořeného třídou SimpleUniverse.

Metody třídy SimpleUniverse (částečný seznam)

Balíček: com.sun.j3d.utils.universe

void addBranchGraph(BranchGroup bg)

Používá se k přidání objektů třídy Node do objektu Locale grafu scény vytvořeného SimpleUniverse. Zde je použita k přidání grafu obsahové větve do virtuálního vesmíru.

ViewingPlatform getViewingPlatform()

Používá se k získání objektu ViewingPlatform který instanciovala SimpleUniverse. Tato metoda je použita s metodou setNominalViewingTransform() třídy ViewingPlatform k nastavení pozice pohledu.


1.5 Java 3D terminologie

Předtím než se přesuneme k tématu vytváření grafu obsahové větve, si vysvětlíme dva pojmy v Java 3D. Pojmy živý a přeložený.

Vložení grafu větve do Locale jej učiní živým a tím pádem se i ostatní objekty v grafu větve stanou živými. Jsou zde ještě nějaké souvislosti s tím když se objekt stane živým. Živé objekty jsou určeny k vykreslování. Parametry živých objektů nemohou být modifikovány dokud nebyla přímo nastavena příslušná schopnost předtím než se objekt stane živým. Schopnosti jsou vysvětleny v sekci 1.8.2.

Objekty BranchGroup mohou být přeloženy. Přeložením BranchGroup převedeme objekt BranchGroup a všechny jeho potomky na více efektivní formu pro vykreslovací jádro. Překládání objektů BranchGroup je doporučené jako poslední krok předtím než je učiníme živými. Je nejlepší překládat jen ty objekty BranchGroup, které byly vloženy do objektů Locale. Přeložení je více diskutováno v sekcích 1.8 a 1.8.1.


Metoda compile() třídy BranchGroup

void compile()

Překládá zdroj BranchGroup asociovaný s tímto objektem vytvořením a uložením do paměti přeložený graf scény.


Koncepty přeložených a živých jsou implementovány ve třídě SceneGraphObject. Dvě metody třídy SceneGraphObject které souvisí s tímto konceptem najdete níže.


Metody třídy SceneGraphObject (částečný seznam)

Třída SceneGraphObject je nadtřídou každé třídy která vytváří graf scény včetně Group, Leaf a NodeComponent. Třída SceneGraphObject poskytuje množství běžných metod a atributů pro svoje podtřídy; dvě z nich najdete zde. Metody třídy SceneGraphObject jsou asociovány s „překladem“ a jsou zahrnuty v sekci 1.8 Schopnosti a Výkon.

boolean isCompiled()

Vrací hodnotu která indikuje zda je uzel částí přeloženého grafu scény.

boolean isLive()

Vrací hodnotu indikující zda je uzel částí živého grafu scény.


Všimněte si, že zde není krok pojmenovaný jako „zapnutí vykreslovacího jádra“, ani v základním ani v jednoduchém receptu. Java3D vykreslovací jádro běží v nekonečném cyklu dokud graf větve obsahující instance třídy View je živým ve virtuálním vesmíru. Když jádro běží, provádí následující operace.

	while(true) {
		Proveď vstup
		if (požadavek k ukončení) break
			Operace s objekty Behavior
			Projdi graf scény a vykresli vizuální objekty
	}
	Ukliď a ukonči vykreslování 

Předchozí sekce vysvětlily konstrukci jednoduchého virtuálního vesmíru bez grafu obsahové větve. Vytvoření grafu obsahové větve je předmětem několika dalších sekcí. Vytváření obsahuje je diskutováno během ukázkových programů.

1.6 Příklad jednoduchého receptu: HelloJava3Da

Typický program v Java3D začíná definicí nové třídy rozšiřující třídu Applet. V příkladu HelloJava3Da.java který najdeme v adresáři examples/hello_java_3d/, třída HelloJava3Da rozšiřuje třídu Applet. Některé programy v Java 3D jsou napsané jako aplikace, ale použití třídy Applet nám dává i možnost jednoduše vytvořit aplikaci v okně.

Hlavní třída Java3D programu typicky definuje metodu která sestaví graf obsahu větve. V příkladu HelloJava3Da je taková metoda pojmenována jako createSceneGraph().

Všechny kroky jednoduchého receptu jsou implementovány v konstruktoru třídy HelloJava3Da. Krok 1, vytvořit objekt třídy Canvas3D je na řádcích 4 až 6. Krok 2, vytvořit objekt třídy SimpleUniverse je na řádku 13. Krok 2a, přizpůsobit objekt SimpleUniverse je proveden na řádku 17. Krok 3, konstrukce obsahu větve je uskutečněno voláním metody createSceneGraph(). Krok 4, přeložení grafu obsahu větve je na řádku 10. Konečně, krok 5, vložení grafu obsahu větve do objektu Locale v SimpleUniverse je na řádku 19.

1. public class HelloJava3Da extends Applet {
2.	public HelloJava3D() {
3.		setLayout(new BorderLayout());
4.		GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); 
5.		Canvas3D canvas3D = new Canvas3D(config);
6.		add(„Center“, canvas3D);
7.		BranchGroup scene = createSceneGraph();
8.		scene.compile();
9.		SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
10.		simpleU.getViewingPlatform().setNominalViewingTransform();
11.		simpleU.addBranchGraph(scene);
12.	}

Krok 3 jednoduchého receptu je vytvořit graf obsahu větve. Obsah grafu větve je vytvořen v ukázce kódu níže. Prozatím je to nejjednodušší možný obsah grafu větve. Obsahová větev vytvořená v této ukázce obsahuje jeden statický objekt – ColorCube. Objekt ColorCube se nachází na počátku souřadnic virtuálního světa. S danou pozicí a orientací pohledu a kostky, se kostka jeví jako čtverec když ji vykreslíme. Po všech ukázkách kódu najdete obrázek z programu.

14.	public BranchGroup createSceneGraph() {
15.		// Vytvoříme kořen grafu větve
16.		BranchGroup objRoot = new BranchGroup();
17.		// Vytvoříme jednoduchý tvar v listu uzlu a přidáme jej do grafu scény
18.		objRoot.addChild(new ColorCube(0.4));
19.		return objRoot;
20.	}

Třída HelloJava3Da je potomkem třídy Applet, ale program může běžet také jako aplikace když použijeme třídu MainFrame. Třída Applet se používá jako základ pokud chceme psát jednoduše programy v Java3D které běží i v okně. MainFrame poskytuje okno aplikace AWT pro applet a zároveň mu dovoluje běžet jako aplikace. Velikost okna výsledné aplikace je určena v třídě MainFrame. Následující kód ukazuje použití třídy MainFrame v HelloJava3Da.java.


Konstruktor třídy MainFrame (částečný seznam)

Balíček: com.sun.j3d.utils.applet

Třída MainFrame umožňuje přetvořit applet v aplikaci. Třída odvozená z appletu může mít metodu main() která volá konstruktor třídy MainFrame. MainFrame rozšiřuje java.awt.Frame a implementuje rozhraní java.lang.Runnable, java.applet.AppletStub a java.applet.AppletContext. Třída MainFrame je chráněná copyrightem.

MainFrame(java.applet.Applet applet, int width, int height)

Tento konstruktor vytváří objekt MainFrame který spustí applet jako aplikaci.

Parametry:

applet – konstruktor třídy odvozené od appletu. Třída MainFrame poskytuje okno AWT pro tento applet

width – šířka okna v pixelech

height – výška okna v pixelech


22.	public static void main(String[] args) {
23.		Frame frame = new MainFrame(new HelloJava3Da(), 256, 256);
24.	}

Tří předchozí ukázky kódu tvoří kompletní Java3D program spolu se správnými příkazy import. Následující třídy z knihoven jsou nutné ke správnému přeložení třídy HelloJava3Da. Nejpoužívanější třídy v programech Java3D jsou v balíčcích javax.media.j3d nebo javax.vecmath. V tomto příkladu je použita jen jedna třída z balíčku com.sun.j3d.utils.geometry a to sice ColorCube.

import java.applet.Applet;
import java.awt.Borderlayout;
import java.awt.Frame;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.*;
import javax.vecmath.*;

V ukázkovém příkladu HelloJava3Da.java je umístěn jeden grafický objekt u místěný v jednom Locale. Výsledný graf scény je na obrázku 1-11.

fig 1-11

Čtyři předchozí ukázky kódu tvoří kompletní HelloJava3Da.java program. Můžete ho najít v adresáři examples/HelloJava3D/. Po přeložení a spuštění uvidíme následující obrázek:

fig 1-12

I když není vysvětlena každá řádka kódu ukázkového příkladu HelloJava3Da, základní body konstrukce programu by měly být po jeho přečtení jasné. Následující sekce doplňuje některé mezery uvedením tříd které program používá.

1.6.1 Třídy Java 3D použité v HelloJava3Da

Abychom lépe porozuměli Java 3D API a ukázkovému příkladu HelloJava3Da, podívejme se na výpis použitých tříd.

Třída BranchGroup

Objekty tohoto typu se používají k tvorbě grafů scény. Instance BranchGroup jsou kořenem subgrafů. Objekty BranchGroup jsou jedinými objekty které mohou být dětmi objektů Locale. Objekty BranchGroup můžou mít mnoho dětí. Děti objektu BranchGroup mohou být objekty Group nebo Leaf.


Základní konstruktor třídy BranchGroup

BranchGroup()

Instance BranchGroup slouží jako kořeny větví grafu scény; Objekty BranchGroup jsou jedinými objekty které mohou být vloženy do sady objektů Locale.


Třída Canvas3D

Třída Canvas3D je odvozena od třídy Canvas z AWT (Abstract Windowing Toolkit). Nejméně jeden objekt Canvas3D musí být odkazován z pohledového grafu větve.


Konstruktor třídy Canvas3D

Canvas3D(GraphicsConfiguration graphicsConfig)

Vytváří a inicializuje nový objekt Canvas3D který může Java 3D vykreslit pokud je mu předán platný objekt GraphicsConfiguration. Je rozšířením třídy Canvas z AWT. Více informací o objekt GraphicsConfiguration můžete najít ve specifikaci Java 2D


Třída Transform3D

Objekty Transform3D představují transformace 3D geometrických objektů jako je posun nebo rotace. Tyto objekty se typicky používají pouze při vytváření objektu TransformGroup. Prvně se vytvoří objekt Transform3D, je možné ho vytvořit i z více objektů Transform3D. Poté se vytvoří objekt TransformGroup použitím objektu Transfrom3D.


Základní konstruktor třídy Transform3D

Zobecněný objekt transformace je interně reprezentován jako matice 4x4 s dvojitou přesností v plovoucí desetinné tečce. The mathematical representation is row major. Objekt Transform3D není použit v grafu scény. Je použit ke určení transformace objektu TransformGroup.

Transform3D()

Vytváří objekt Transform3D který představuje nulovou matici (žádná transformace)


Objekt Transform3D může představovat posun, rotaci, změnu velikosti nebo kombinace těchto možností. Když upřesňujeme rotaci, úhle je vyjádřen v radiánech. Jedná plná otočka je 2 PI radiánů. Jeden způsob je použít k vyjádření úhlů konstantu Math.PI. Jiný způsob je zadat hodnotu přímo. Tady jsou nějaké přepočty: 45 stupňů je 0.785, 90 stupňů je 1.57 a 180 stupňů je 3.14


Metody třídy Transform3D (částečný seznam)

Objekty Transform3D představují transformace jako rotace, posun a změna velikosti. Třída Transform3D jednou z mála těch co se nepoužívají v žádném grafu scény. Transformace objektem Transform3D se používají k vytvoření objektů TransformGroup které se používají v grafu scény.

void rotX(double angle)

Nastavuje hodnotu transformace proti směru hodinových ručiček kolem osy x. Úhel se zadává v radiánech.

void rotY(double angle)

Nastavuje hodnotu transformace proti směru hodinových ručiček kolem osy y. Úhel se zadává v radiánech.

void rotZ(double angle) Nastavuje hodnotu transformace proti směru hodinových ručiček kolem osy z. Úhel se zadává v radiánech.

void set(Vector3f translate)

Nastavuje hodnotu posunu této matice na hodnoty parametru Vector3f, a nastavuje ostatní složky matice jako by to byla nulová matice.


Třída TransformGroup

Jako podtřída třídy Group, instance TransformGroup se používají pro vytvoření grafů scény a mají kolekci of child node objects. Objekty TransformGroup drží transformace jako posun nebo rotace. Transformace je typicky vytvořena objektem Transform3D, který není objektem grafu scény.


Konstruktory třídy TransformGroup

Objekty TransformGroup jsou držiteli transformací v grafu scény.

TransformGroup()

Vytváří a inicializuje TransformGroup pomocí nulové transformace.

TransformGroup(Transform3D t3D)

Vytváří a inicializuje TransformGroup z předaného objektu Transform3D.

Parametry:

t3D – objekt Transform3D


Transformace z objektu Transform3D je zkopírována do objektu TransformGroup nezávisle na tom jestli je vytvořen objekt TransformGroup nebo pomocí metody setTransform().


Metoda setTransform() třídy TransformGroup

void setTransform(Transform3D t3D)

Nastavuje transformační složku tohoto objektu TransformGroup na hodnotu předané transformace.

Parametry:

t3D – transformace která se má zkopírovat


Třída Vector3f

Vector3f je matematická třída kterou můžeme najít v balíčku javax.vecmath pro specifikování vektoru použitím tří hodnot s plovoucí desetinnou tečkou. Objekty vektoru se často používají k určení posunu. Objekty Vector3f se přímo nepoužívají pro konstrukci grafu scény. Používají se k určení posunu, povrchových normál nebo jiných operací.


Konstruktory třídy Vector3f

Třísložkový vektor který je reprezentován souřadnicemi x, y a z s jednoduchou přesností v plovoucí desetinné tečce.

Vector3f()

Vytváří a inicializuje Vector3f na hodnoty (0, 0, 0).

Vector3f(float x, float y, float z)

Vytváří a inicializuje Vector3f určený zadanými souřadnicemi x, y a z.


Třída ColorCube

Třída ColorCube je pomocná třída z balíčku com.sun.j3d.utils.geometry který definuje geometrický tvar a barvy kostky umístěné ve středu systému souřadnic s různými barvami každé ze svých stran. Základní objekt ColorCube je kostka která je 2 metry vysoká, široká a hluboká. Jestliže umístíme tuto kostku bez transformace do středu systému souřadnic (jako v příkladu HelloJava3Da), měla by být vidět z daného pohledu její červená strana. Ostatní barvy jsou modrá, magenta, žlutá, zelená a cyan.


Konstruktory třídy ColorCube

Balíček: com.sun.j3d.utils.geometry

ColorCube je jednoduchý vizuální objekt se základními barvami z sestavený z vertexů (geometrických vrcholů) s jinou barvou na každé straně. ColorCube rozšiřuje třídu Shape3D; takže je uzlem Leaf. ColorCube se dá lehce použít při konstrukci virtuálního vesmíru.

ColorCube()

Vytváří barevnou kostku základní velikosti. Normálně je roh kostky umístěn 1 metr podél každé z os v počátku systému souřadnic, čili kostka je vystředěna na počátku souřadnic a je 2 metry vysoká, široká a hluboká.

ColorCube(double scale)

Vytváří barevnou kostku která je zvětšena zadanou hodnotou. Normální velikost hrany jsou 2 metry, čili objekt ColorCube má rohy na souřadnicích (scale, scale, scale) a (-scale, -scale, -scale).


1.7 Rotující kostka

Abychom viděli i ostatní stěny kostky, můžeme ji jednoduše rotovat. První krok je vytvoření požadované transformace pomocí objektu Transform3D.

Ukázka kódu obsahuje objekt TransformGroup v grafu scény k rotaci kostky kolem osy x. Rotace je tvořena pomocí objektu Transform3D pojmenovaného rotate. Tento objekt je vytvořen na řádku 6. Rotace je určena pomocí metody rotX() na řádku 8. Poté je vytvořen objekt TransformGroup který drží danou transformaci na řádku 10.

Rotaci určují dva parametry: osa kolem které bude objekt rotovat, a úhel rotace. Osu určíme výběrem příslušné metody. Úhel rotace je hodnota argumentu předaného metodě. Úhel rotace je dán v radiánech, čili hodnota PI/4 je 1/8 plné otočky, neboli 45 stupňů. Po vytvoření objektu rotate třídy Transform3D je tento objekt použit k vytvoření objektu objRotate třídy TransformGroup (řádek 10). Objekt Transform3D je použit v grafu scény. Objekt objRotate potom udělá objekt ColorCube svým dítětem (řádek 11). Poté objekt objRoot udělá objekt objRotate svým dítětem (řádek 12). Metody rotX(), rotY() a rotZ() třídy Transform3D jsou uvedeny v referenčních blocích v předchozí sekci.

	public BranchGroup createSceneGraph() {
		// vytvoříme kořen grafu větve
		BranchGroup objRoot = new BranchGroup();
		// vytvoříme objekt pro transformaci (rotace)
		Transform3D rotate = new Transform3D();
		rotate.rotX(Math.PI / 4.0d);
		TransformGroup objRotate = new TransformGroup(rotate);
		objRotate.addChild(new ColorCube(0.4));
		objRoot.addChild(objRotate);
		return objRoot;
	}

Obsah grafu větve nyní zahrnuje objekt TransformGroup v cestě grafu scény k objektu ColorCube. Každý z objektů v grafu scény je nutný. Objekt BranchGroup je jediný který může být dítětem Locale. Objekt TransformGroup je jediný který může změnit umístění, orientaci nebo velikost vizuálního objektu. V tomto případě, objekt TransformGroup mění orientaci. Samozřejmě je objekt ColorCube je nezbytný k reprezentaci vizuálního objektu.

fig 1-13

Předchozí ukázka kódu není zahrnuta v žádném z příkladů. Je to pouze ukázka mezistupně k větším a zajímavějším programům. Větším problémem který budeme řešit dále je kombinace dvou transformací v jednom objektu TransformGroup.

1.7.1 Příklad kombinace transformací: HelloJava3Db

Celkem často je vizuální objekt posunován a rotován kolem jedné nebo dvou os. V každém případě, musíme určit dvě odlišné transformace pro jediný vizuální objekt. Dvě transformace mohou být kombinovány v jednu transformační matici která je uložena v jednom objektu TransformGroup. Jako příklad nám poslouží následující ukázka kódu.

V programu HelloJava3Db jsou kombinovány dvě rotace. Vytvoření dvou rotací současně vyžaduje kombinaci dvou objektů Transform3D. Ukázkový program rotuje kostku jak kolem osy x, tak i osy y. Na řádcích 6 a 7 jsou vytvořeny dva objekty Transform3D, každý pro jednu rotaci. Rotace samotné jsou specifikovány dvěma objekty TransformGroup (řádky 9 a 10). Poté jsou kombinovány násobením objektů Transform3D (řádek 11). Kombinace těchto dvou transformací je uložena objektu TransformGroup (řádek 12).

	public BranchGroup createSceneGraph() {
		// Vytvoříme kořen grafu větve
		BranchGroup objRoot = new BranchGroup();
		// Vytvoříme objekty pro transformace
		Transform3D rotate = new Transform3D();
		Transform3D tempRotate = new Tranform3D();
		rotate.rotX(Math.PI / 4.0d)
		tempRotate.rotY(Math.PI / 5.0d);
		rotate.mul(tempRotate);
		TransformGroup objRotate = new TransformGroup(rotate);
		objRotate.addChild(new ColorCube(0.4));
		objRoot.addChild(objRotate);
		return objRoot;
	}

Obě předchozí ukázky kódu mohou nahradit metodu createSceneGraph() z příkladu HelloJava3Da. Kompletní program můžeme najít v adresáři examples/Hellojava3D/.

Na následujícím obrázku můžeme najít graf scény . Pohledový graf větve je stejný jako v příkladu HelloJava3Da, který je konstruován třídou SimpleUniverse a reprezentován velkou hvězdou. Obsah grafu větve nyní zahrnuje objekt TransformGroup v cestě grafu scény k objektu ColorCube.

fig 1-14 fig 1-15

1.8 Schopnosti a Výkon

Graf scény vytvořený programem Java 3D může být použit přímo pro vykreslování. Ale jeho reprezentace není příliš efektivní. Flexibilita zabudovaná v každém objektu grafu scény (což není předmětem diskuse v tomto tutoriálu) vytváří volitelnou reprezentaci virtuálního vesmíru. Ke zvýšení výkonu vykreslování virtuálního vesmíru je potřeba jeho efektivnější reprezentace.

Java 3D má vnitřní reprezentaci virtuálního vesmíru a metody pro provedení této konverze. Existují dva způsoby jak tuto konverzi do vnitřní reprezentace systému Java 3D provést. Jedním je přeložit každý graf větve . Druhý způsob je vložit graf větve do virtuálního vesmíru a učinit ho tak živým. Přeložení grafu větve je předmětem další sekce. Efekt konverze do vnitřní reprezentace je diskutován v sekci 1.8.2.

1.8.1 Přeložení obsahů

Objekt BranchGroup má metodu compile(). Volání této metody převede celý graf větve pod skupinou větvě do vnitřní reprezentace grafu větve systému Java 3D. Navíc tato interní reprezentace může být optimalizována mnoha způsoby.

Možné optimalizace nejsou specifikovány v Java 3D API. Nicméně efektivita může být zvýšena mnoha způsoby. Jednou z možných optimalizací je kombinování objektů TransformGroup podél cest grafu scény (čili je-li více těchto objektů v grafu pod sebou). Například, jestliže graf scény obsahuje dva objekty TransformGroup v rodičovském vztahu, mohou být reprezentovány jedním objektem TransformGroup. Jinou možností je kombinování objektů Shape3D které mají statický fyzický vztah (čili jsou spolu „napevno“ spojeny). Tyto způsoby optimalizování jsou možné když nejsou nastaveny schopnosti. Ostatní optimalizace jsou však stejně dobře možné.

Následující obrázek představuje koncept konverze na efektivnější reprezentaci. Graf scény na levé straně je přeložen a transformován do vnitřní reprezentace která je zobrazena na pravé straně obrázku. Obrázek pouze představuje koncept vnitřní reprezentace, ne jak ji Java 3D momentálně vykonává.

fig 1-16

1.8.2 Schopnosti

Je-li graf větve už jednou živý nebo přeložený , Java 3D vykreslovací systém převede graf větve do efektivnější vnitřní reprezentace. Důležitějším efektem převedení grafu scény do vnitřní reprezentace je zvýšení výkonu vykreslování.

Převod do interní reprezentace má také jiné efekty. Jedním efektem je uložení hodnot transformací a ostatních objektů grafu scény. Přestože jsou poskytovány přesně pro program, program nemá schopnost měnit hodnoty objektů grafu scény po tom co jsou živé.

Existují případy kdy program potřebuje mít schopnost měnit hodnoty v objektu grafu scény potom co se stane živým. Například, změna hodnoty objektu TransformGroup vytváří animace. Aby to bylo možné, transformace musí být schopná se měnit potom co se stane živou. Seznam parametrů ke kterým můžeme přistupovat a jakým způsobem, se nazývají schopnostmi objektu.

Každý objekt SceneGraphObject má sadu schopností. Jejich hodnoty určují jaké schopnosti existují pro daný objekt poté co je přeložen nebo je živý. Sada schopností se liší objekt od objektu.


Metody třídy SceneGraphObject (částečný seznam)

Třída SceneGraphObject je nadtřídou téměř každé třídy která se používá k vytvoření grafu scény včetně třídy Group, Leaf a NodeComponent. Sekce 1.5 představuje i jiné metody objektu SceneGraphObject.

void clearCapability(int bit)

Vynuluje specifikovanou schopnost.

void getCapability(int bit)

Vrátí specifikovanou schopnost.

void setCapability(int bit)

Nastaví specifikovanou schopnost.


Abychom byli schopni získat hodnotu transformace reprezentované objektem TransformGroup, pak tato schopnost musí být nastavena před tím než je přeložena nebo se stane živou. Podobně, chceme-li změnit hodnotu transformace v objektu TransformGroup, musíme nastavit schopnost zapisovat předtím než se stane živým nebo jej přeložíme. Následující referenční blok ukazuje schopnosti nezděděné třídy TransformGroup. Pokus učinit změnu v živém nebo přeloženém objektu pro který není nastavena příslušná schopnost skončí výjimkou.

V další sekci vytvoříme animace pomocí časově proměnné rotace. Abychom byli schopni toto učinit, objekt TransformGroup musí mít nastavenu schopnost pomocí konstanty ALLOW_TRANSFORM_WRITE předtím než je přeložen nebo se stane živým.


Vlastnosti TransformGroup (částečný seznam)

Dvě vlastnosti uvedené v seznamu jsou jedinými definovanými třídou TransformGroup. TransformGroup dědí mnoho vlastností od svých předků: Group a Node. Vlastnosti se dají nastavit, resetovat nebo získat pomocí metod definovaných ve třídě SceneGraphObject.

ALLOW_TRANSFORM_READ

Umožňuje čtení hodnoty transformace objektu TransformGroup.

ALLOW_TRANSFORM_WRITE

Umožňuje zápis hodnoty transformace objektu TransformGroup.


Vlastnosti kontrolují přístup k ostatním aspektům objektu TransformGroup. Objekt TransformGroup dědí vlastnosti nastavení od svých předků: Group a Node. Některé vlastnosti objektu Group jsou uvedeny v následujícím referenčním bloku.


Vlastnosti Group

TransformGroup dědí mnoho vlastností od svých předků.

ALLOW_CHILDREN_EXTEND

Nastavuje vlastnost přidat děti do uzlu Group poté co je přeložen nebo učiněn živým.

ALLOW_CHILDREN_READ

Nastavuje vlastnost odkazů na děti uzlu Group číst poté co jsou přeloženy nebo učiněny živými.

ALLOW_CHILDREN_WRITE

Nastavuje vlastnost odkazů na děti uzlu Group zapisovat poté co jsou přeloženy nebo učiněny živými.


1.9 Animace

V Java 3D existuje třída Behavior pro specifikování animací nebo interakcí s vizuálními objekty. Chování může virtuálně změnit jakýkoli atribut vizuálního objektu. Programátor může použít mnoho předdefinovaných chování nebo vytvořit své vlastní. Poté co je jednou chování specifikováno pro daný vizuální objekt, Java 3D systém automaticky aktualizuje jeho pozici, orientaci, barvu nebo ostatní atributy.

Rozdíl mezi animací a interakcí je, jestliže je chování aktivováno časovou odezvou nebo jako odezva na uživatelskou aktivitu.

Každý vizuální objekt ve virtuálním vesmíru může mít své předdefinované chování. Vlastně vizuální objekt může mít mnoho způsobů chování. Ke specifikování nějakého chování pro vizuální objekt programátor vytvoří objekty které specifikují chování, přidá vizuální objekt do grafu scény a vytvoří příslušné reference mezi objekty grafu scény a objekty chování.

Ve virtuálním vesmíru kde je definováno mnoho vzorů chování může být vyžadováno mnoho výpočetní síly jen pro výpočet těchto vzorů. Pokud vykreslovací jádro a chování používají ten samý procesor(y), je možné že bude vyžadována výpočetní síla pro chování která může degradovat výkon vykreslovacího jádra. Zde hrají roli speciální grafické procesory (GPU) v závislosti na hardwarovém prostředí a implementaci Java 3D. Přesto je možné mít mnoho vzorů chování ve virtuálním vesmíru a rychle vykreslovat.

Java 3D dovoluje programátorovi zvládnout tento problém stanovením prostorového rozmezí pro dané chování. Toto rozmezí je nazýváno plánovací region. Chování není aktivní dokud se neprotne aktivační objem objektu ViewPlatform s plánovacím regionem objektu Behavior. Jinými slovy, jestliže není nikdo v lese kdo by měl vidět spadnout strom, pak tento strom nespadne. Možnost plánovacího regionu dělá Java 3D efektivnější ve vykreslování virtuálního vesmíru s mnoha vzory chování.

Třída Interpolator je jednou z předdefinovaných tříd v balíčku Java 3D, které jsou podtřídami třídy Behavior. Založen na funkci času, objekt třídy Interpolator mění parametry objektu grafu scény. Například RotationInterpolator mění parametry rotace objektu TransformGroup aby ovlivnil rotaci vizuálních objektů které jsou předky TransformGroup.

Následující seznam vyjmenovává kroky potřebné pro specifikování animace pomocí objektu Interpolator.

  1. vytvořit cílový objekt TransformGroup
  2. nastavit vlastnost ALLOW_TRANSFORM_WRITE
  3. vytvořit objekt třídy Alpha
  4. specifikovat časové údaje pro objekt Alpha
  5. vytvořit objekt třídy Interpolator
  6. předat odkazy mezi objekty Alpha a TransformGroup
  7. uzpůsobit parametry chování/li>
  8. určit plánovací region
  9. nastavit plánovací region pro chování
  10. učinit vzor chování dítětem TransformGroup

1.9.1 Specifikace chování animace

Akce chování může znamenat změnu v umístění (PositionInterpolator), orientaci (RotationInterpolator), velikosti (ScaleInterpolator), barvě (ColorInterpolator) nebo průhlednosti (TransparencyInterpolator) vizuálního objektu. Jak jsme se zmínili dříve, interpolátory jsou předdefinované třídy chování. Všechny zmíněné vzory chování je možné provést bez použití interpolace; avšak interpolátory velmi usnadňují tvoření vzoru chování. Třídy interpolátorů jsou schopny provádět i jiné akce, včetně jejich kombinací. Detaily jsou prezentovány v sekci 5.2 a můžeme je najít také v API specifikaci. V následujícím příkladě je použita třída RotationInterpolator.

Třída RotationInterpolator

Tato třída je určena k vytvoření rotace vizuálního objektu nebo skupiny vizuálních objektů. Objekt RotationInterpolator mění objekt TransformGroup na danou rotaci v závislosti na hodnotě objektu Alpha. Protože se hodnota objektu Alpha v čase mění, mění se také rotace. Pro objekt RotationInterpolator lze nastavit osu rotace, počáteční úhel a koncový úhel.

Pro jednoduché neměnné rotace má objekt RotationInterpolator následující konstruktor:


Konstruktor třídy RotationInterpolator (částečný seznam)

Tato třída definuje vzor chování který mění rotační složku jeho cílového objektu TransformGroup pomocí lineární interpolace (LERP – LinEar inteRPolation) mezi zadanou dvojicí úhlů (použitím hodnoty generované daným objektem Alpha). Interpolovaný úhel je použit ke generování rotace.

RotationInterpolator(Alpha alpha, TransformGroup target)

Tento konstruktor používá základní hodnoty některých parametrů pro interpolátor k vytvoření plné rotace okolo osy y ke které použije cílový objekt TransformGroup.

Parametry:

alpha – odkaz na časově proměnnou funkci

target – cílový objekt TransformGroup který chceme modifikovat


Cílový objekt interpolátoru musí mít nastavenu schopnost zapisování. Informace o schopnostech jsou v sekci 1.8

1.9.2 Časově proměnné funkce: Chování v závislosti na čase

Chování v závislosti na čase můžeme určit pomocí objektu Alpha. Nastavení objektu Alpha může být velmi komplexní. Projdeme si některé základní informace.

Třída Alpha

Objekty třídy Alpha se používají vytvoření časově proměnných funkcí. Třída Alpha produkuje hodnotu mezi nulou a jednou celou včetně. Hodnota kterou produkuje závisí na čase a parametrech objektu Alpha. Objekty Alpha se běžně používají s objektem chování třídy Interpolator k vytvoření animace vizuálních objektů.

Existuje deset parametrů pro objekt Alpha, což dává programátorovi obrovskou flexibilitu. Bez nějaké detailní znalosti každého parametru víme, že instance třídy Alpha může být jednoduše spojena s chováním aby vytvořili jednoduchou rotaci, kmity kyvadla, a jednorázové události jak je otevření dveří nebo start rakety.


Konstruktor třídy Alpha

Třída Alpha poskytuje objekty pro konverzi času na hodnotu alfa (hodnota v rozmezí 0 a 1). Objekt Alpha je efektivní funkcí času která generuje hodnoty v rozmezí nuly a jedné celé včetně. Objekt Alpha se používá pro poskytnutí hodnot objektu chování Interpolator. Funkce f(t) a charakteristiky objektu Alpha jsou definovány uživatelem:

Alpha()

Spojitá smyčka s periodou jedné sekundy.

Alpha(int loopCount, long increasingAlphaDuration)

Tento konstruktor přebírá jako parametry počet smyček a počet milisekund pro jednu smyčku a ostatním hodnotám přiřazuje základní hodnoty. Výsledný objekt Alpha produkuje hodnoty začínající hodnotou nula a vzrůstající směrem k hodnotě jedna celá. To se opakuje v počtu zadaném parametrem loopCount. Jestliže je loopCount roven –1, opakuje se smyčka donekonečna. Čas který je potřebný k růstu z hodnoty nula na hodnotu jedna je určen druhým parametrem který je v řádu milisekund.

Parametry:

loopCount – počet opakování Alpha objektu; hodnota –1 určuje nekonečnou smyčku

increasingAlphaDuration – čas v milisekundách v průběhu kterého hodnota alfa vzroste z nuly na jedna


1.9.3 Plánovací region

Jak jsme se zmínili dříve v sekci 1.9, každé chování má plánovací region. Plánovací region pro chování se nastavuje pomocí metody setSchedulingBounds() třídy Behavior.

Existuje mnoho způsobů jak nastavit plánovací region, nejjednodušším z nich je vytvořit objekt BoundingSphere. Ostatní volby zahrnují kromě koule také box a polytop. Níže jsou informace o třídě BoundingSphere. Informace o třídách BoundingBox a BoundingPolytop nalezneme v API specifikaci.


Metoda setSchedulingBounds() třídy Behavior

void setSchedulingBounds(Bounds region)

Nastavuje plánovací region třídy Behavior do zadaného rozmezí

Parametry:

region – rozmezí ve kterém se nachází plánovací region třídy Behavior


Třída BoundingSphere

Vytváří kulovitý region kolem objektu, který je určen středem koule a jejím poloměrem. Základní nastavení koule má střed na souřadnicích (0, 0, 0). Poté se vybere poloměr dostatečně velký na to aby koule obsáhla vizuální objekt, včetně všech možných umístění objektu (koule se pohybuje s objektem?).


Konstruktory třídy BoundingSphere (částečný seznam)

Tato třída definuje kulovitý region který obklopuje vizuální objekt a je definován svým středem a poloměrem.

BoundingSphere()

Tento konstruktor vytváří kouli obklopující vizuální objekt na souřadnicích (0, 0, 0) s poloměrem 1.

BoundingSphere(Point3d center, double radius)

Vytváří a inicializuje objekt BoundingSphere na daném místě a o dané velikosti


1.9.4 Příklad použití třídy Behavior: HelloJava3Dc

Ukázka kódu níže je kompletním příkladem použití jedné z tříd interpolátorů k vytvoření animace. Animace vytvořená tímto kódem je spojitou rotací s celkovým trváním čtyři sekundy.

Krokem jedna receptu je vytvoření objektu TransformGroup měnitelného za běhu. Cílový objekt TransformGroup interpolátoru musí mít nastavenou schopnost zápisu. Na řádce 7 je tento objekt pojmenovaný objSpin vytvořen. Schopnost objektu objSpin je nastavena na řádku 8.

Krokem 2 je vytvořit objekt alfa k řízení interpolátoru. V našem příkladě je objekt Alpha pojmenovaný rotationAlpha použit k definování spojité rotace. Dva parametry specifikované na řádku 16 jsou počet smyček a čas trvání pro jednu smyčku. Hodnota –1 znamená nekonečnou smyčku. Čas je určen v milisekundách. Hodnota 4000 znamená tedy 4000 milisekund, což jsou 4 sekundy. Z toho vyplývá že jedna otočka trvá čtyři sekundy.

Krok 3 receptu je vytvořit interpolátor. Objekt RotationInterpolator je vytvořen na řádcích 21 a 22. Interpolátor musí mít odkazy na cílový objekt transformace a objekt alfa. To je splněno už v konstruktoru. V tomto příkladu používáme základní chování objektu RotationInterpolator, což znamená že se bude otáčet kolem osy y.

Krok 4 je určení plánovacího regionu. V příkladu používáme objekt BoundingSphere se základními hodnotami. Objekt BoundingSphere je vytvořen na řádku 25. Koule je nastavena jako rozmezí pro chování na řádku 26.

Poslední krok, krok 5 učiní chování dítětem TransformGroup. To je splněno na řádku 27.

	public BranchGroup createSceneGraph() {
		// Vytvoříme kořen grafu větve
		BranchGroup objRoot = new BranchGroup();
		// Vytvoříme skupinu transformace a inicializujeme ji na nulu. 
		// Poté ji přidáme do kořene subgrafu
		TransformGroup objSpin = new TransformGroup();
		objSpin.setCapabaility(TransformGroup.ALLOW_TRANSFORM_WRITE);
		objRoot.addChild(objSpin);
		// Vytvoříme jednoduchý list uzlu, a přidáme jej do grafu scény
		// ColorCube je v pomocném balíčku 
		objSpin.addChild(new ColorCube(0.4));
		// Vytvoříme časově proměnnou funkci k řízení animace
		Alpha rotationAlpha = new Alpha(-1, 4000);
		// Vytvoříme nový objekt Behavior který provede požadovanou
		// operaci na určeném objektu transformace a přidáme jej do
		// grafu scény
		RotationInterpolator rotator = 
			new RotationInterpolator(rotationAlpha, objSpin);
		// Obklopující koule vymezuje region v němž je chování aktivní
		BoundingSphere bounds = new BoundingSphere();
		rotator.setSchedulingBounds(bounds);
		objSpin.addChild(rotator);
		return objRoot;
	}

Tento úsek kódu spolu s předchozími úseky tvoří ukázkový program HelloJava3Dc.java a můžeme jej najít v adresáři examples/HelloJava3D/. Běžící aplikace vykresluje ColorCube s chováním které ji rotuje jednou za čtyři sekundy.

Program HelloJava3Dc vytváří graf scény na následujícím obrázku. Objekt rotace je dítě TransformGroup objektu objSpin a má na něj i odkaz. I když se zdá že tento vztah může vyvolat zacyklení grafu scény, nevyvolává. Opětovné volání pomocí odkazu není částí grafu scény. Reference je naznačena čárkovanou křivkou z objektu Behavior do objektu TransformGroup.

fig 1-18 fig 1-19

1.9.5 Příklad kombinace transformace a chování: HelloJava3Dd

Samozřejmě můžeme kombinovat chování s transformacemi z předchozích příkladů. Tuto kombinaci můžeme najít v programu HelloJava3Dd.java. V obsahu grafu větve jsou objekty pojmenované objRotate a objSpin, které jsou rozlišeny statickou rotací spojitou rotací (chování rotace) objektu kostka.

	public BranchGroup createSceneGraph() {
		// Vytvoříme kořen grafu větve
		BranchGroup objRoot = new BranchGroup();
		// Objekt rotace posunové matice
		Transform3D rotate = new Transform3D();
		Transform3D tempRotate = new Transform3D();
		rotate.rotX(Math.PI / 4.0d);
		tempRotate.rotY(Math.PI / 5.0d);
		rotate.mul(tempRotate);
		TransformGroup objRotate = new TransformGroup(rotate);
		// Vytvoříme transformační skupinu uzlu a inicializujeme ji
		// nulovou maticí. Nastavíme schopnost TRANSFORM_WRITE takže 
		// naše chování lze měnit za běhu. Poté jej přidáme do subgrafu
		TransformGroup objSpin = new TransformGroup();
		objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		objRoot.addChild(objRotate);
		objRotate.addChild(objSPin);
		// Vytvoříme jednoduchý tvar v listu uzlu, přidáme jej do grafu scény
		// Třída ColorCube je v pomocném balíčku
		objSpin.addChild(new ColorCube(0.4));
		// Vytvoříme nový objekt chování který provede požadovanou operaci
		// se specifikovaným transformačním objektem a přidá jej do grafu
		// scény
		Transform3D yAxis = new Transform3D();
		Alpha rotationAlpha = new Alpha(-1, 4000);
		RotationInterpolator rotator = 
			new RotationInterpolator(rotationAlpha, objSpin, yAxis, 0.0f,
					(float) Math.PI * 2.0f);
		// Obklopující koule které specifikuje region chování je aktivní
		// Vytvoříme kouli vycentrovanou na počátku systému souřadnic
		// s poloměrem 1
		BoundingSphere bounds = new BoundingSphere();
		rotator.setSchedulingBounds(bounds);
		objSpin.addChild(rotator);
		return objRoot;
	}
fig 1-20 fig 1-21

1.10 Shrnutí kapitoly

Tato kapitola na začátku předpokládá že čtenář nemá žádné znalosti o Java 3D. V průběhu kapitoly jsou čtenáři představovány některé z nejdůležitějších tříd Java 3D API. Je vysvětleno jak jsou tyto třídy i třídy z jiných balíčků použity k vytvoření grafu scény. Graf scény, který popisuje virtuální vesmír a jakým způsobem bude vykreslen je také vysvětlen s jistými detaily. Třída SimpleUniverse je použita k vytvoření sady ukázkových programů které demonstrují nejjednodušší Java D program, jednoduchou transformaci, kombinaci transformací, chování a kombinaci transformací a chování. Později jsou v kapitole vysvětleny schopnosti objektů a překládání grafů větve.

1.11 Test

Zde najdete pár příkladů k procvičení a prohloubení znalostí prezentovaných v této kapitole.

1. V programu HelloJava3Db který kombinuje dvě rotace v jednom objektu TransformGroup zkuste odhadnout jaký bude rozdíl když převrátíte pořadí násobení rotace. Upravte program abyste se přesvědčili o správnosti své odpovědi. Stačí jen prohodit dvě řádky kódu.

2. Jaký bude rozdíl když v programu HelloJava3Dd přehodíte pořadí TransformNode za ColorCube v obsahu grafu větve? Upravte program abyste se přesvědčili o správnosti své odpovědi.

3. Když chcete zvětšit výkon aplikace, můžete zkusit zmenšit graf scény (výkon je přímo závislý na velikosti grafu scény. Efektivní změnou je redukovat počet objektů Shape3D v grafu scény. Více informací naleznete na http://java.sun.com/docs). Můžete kombinovat rotaci a cíl rotace do jednoho objektu TransformGroup?

4. Posuňte ColorCube o jednu jednotku na ose Y o rotujte kostku. Jako výchozí program můžete použít HelloJava3Db. Následující část kódu specifikuje posun. Zkuste tuto transformaci provést v opačném pořadí. Očekáváte nějakou změnu? Jestliže ano, proč? Jestliže ne, proč? Zkuste to a porovnejte výsledek se svými předpoklady.

	Transform3D translate = new Transform3D();
	Vector3f vector = new Vector3f(0.0f, 1.0f, 0.0f);
	translate.setTransform(vector);

5. V programu Hellojava3Dc má obklopující koule poloměr 1 metr. Je tato hodnota menší nebo větší než je třeba? Jaká je nejmenší hodnota zaručující že kostka s bude otáčet je-li v záběru? Experimentujte s programe abyste si ověřili své odpovědi. Následující řádka kódu může být použita k určení obklopující koule. Na této řádce objekt Point3D ji nastavuje na střed a určuje její poloměr.

	BoundingSphere bounds = new BoundingSphere(
				new Point3d(0.0, 0.0, 0.0), 100.0);

6. Ukázkové příklady dodávají dostatek informací pro sestavení virtuálního vesmíru s mnoha barevnými kostkami. Jak byste vytvořili takový graf scény? V jaké části kódu by se toto mělo uskutečnit?