J3DT_2 - Vytváření geometrie

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

Kapitola 1 prozkoumává základní koncepty skladby virtuálního vesmíru v Java 3D zaměřením na transformace a jednoduché formy chování. Příklady v kapitole 1 používají třídu ColorCube jako jediný vizuální objekt. Díky této třídě nemusí programátor specifikovat tvar nebo barvu vizuálního objektu. Třída ColorCube se lehce používá ale nelze ji použít k vytvoření jiných vizuálních objektů.

Existují tři hlavní způsoby jak vytvořit geometrický obsah. Jeden z nich používá pomocné geometrické třídy pro krychli, kužel, válec a kouli. Dalším způsobem je specifikovat souřadnice vertexů jednotlivých bodů, úseček anebo polygonů. Třetím způsobem je použít loader. Tato kapitola ukazuje jak vytvořit geomterický obsah prvními dvěma způsoby.

Tato kapitola je zaměřená na vytváření geometrického obsahu, tzn. tvaru vizuálních objektů. Je pokryto i pár témat týkajících se geometrie, včetně matematických tříd a tříd vzhledu. Předtím než si popíšeme jak vytvořit geometrický obsah, uvedeme více informací o systému souřadnic virtuálnícho vesmíru v sekci 2.1.

2.1 Systém souřadnic virtuálního vesmíru

Jak se diskutuje v kapitole 1, instance třídy VirtualUniverse slouží jako kořen grafu scény ve všech programech napsaných v Java 3D. Termínem virtuální vesmír se běžně označuje trojrozměrný virtuální prostor tvořený Java 3D objekty. Každý objekt Locale ve virtuálním vesmíru pak ustanovuje karteziánský systém souřadnic.

Objekt Locale slouží jako referenční bod pro vizuální objekty ve virtuálním vesmíru. S jedním objektem Locale v SimpleUniverse existuje jen jeden systém souřadnic ve virtuálním vesmíru.

Java 3D Virtuální vesmír používá pravoruký systém souřadnic. Osa x pozitivní směrem doprava, osa y je pozitivní směrem nahoru a osa z je pozitivní směrem k pozorovateli a všechny jednotky jsou udávány v metrech. Obrázek 2-1 ukazuje orientaci SimpleUniverse vzhledem k pozorovateli.

Orientace os ve virtuálním vesmíru

Základy definice vizuálního objektu

Sekce 2.2.1 představuje třídu Shape 3D. Poté následuje obecná diskuze o třídě NodeComponent v sekci 2.2.2. Po diskuzi o geometrických primitivech z pomocného balíčku se zbytek kapitoly zabývá složkami uzlu Geomtery a Appearance.

Instance Shape 3D definuje vizuální objekt

Uzel grafu Shape3D definuje vizuální objekt (Shape3D definuje nejběžnější vizuální objekt ve virtuálním vesmíru, ale existují i jiné definice). Shape3D je jednou z podtříd třídy Leaf; takže objekty Shape3D mohou být jen listy v grafu scény. Objekt Shape3D neobsahuje informace o tvaru nebo barvě vizuálního objektu. Tyto informace jsou uloženy v objektech NodeComponent na které se objekt Shape3D odkazuje. Objekt Shape3D se může odkazovat na jeden objekt Geometry a jeden objekt Appearance.

V grafech scény aplikací HelloJava3D v kapitole 1 je použit symbol obdélníku k reprezentaci objektu ColorCube. Jednoduchý graf scény na obrázku 2-2 ukazuje vizuální objekt reprezentovaný listem Shape3D (trojúhelník) a dvěma objekty NodeComponent (ovály) místo obdélníku (tento graf scény neplatí pro objekt ColorCube. Ten totiž nepoužívá ani Appearance NodeComponent. Toto je příklad typického vizuálního objektu).

img2-2

Vizuální objekt lze definovat jen za použití objektu Shape3D složky uzlu Geometry. Volitelně se může objekt Shape3D odkazovat na složku uzlu Appearance. Konstruktory třídy Shape3D (uvedené v dalším referenčním bloku) umožňují vytvoření objektu bez odkazu na složku uzlu, s odkazem na složku uzlu Geometry nebo s odkazy na oba typy složek uzlu.


Konstruktory třídy Shape3D

Shape3D()

Vytváří a inicializuje objekt Shape3D bez geometrie a vzhledu.

Shape3D(Geometry geometry)

Vytváří a inicializuje objekt Shape3D se specifikovanou geometrií bez vzhledu.

Shape3D(Geometry geometry, Appearance appearance)

Vytváří a inicializuje objekt Shape3D se specifikovanou geometrií a vzhledem.


Dokud není objekt Shape3D živý nebo přeložený, lze měnit odkazy na složky uzlu metodami uvedenými v dalším referenčním bloku. Tyto metody lze použít i na živé nebo přeložené objekty Shape3D pokud jsou prvně nastaveny příslušné vlastnosti. Další referenční blok níže obsahuje seznam vlastností Shape3D. Přečtěte si sekci "Čtěte referenční bloky". Platí pro všechny následující referenční bloky.


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

Objekt Shape3D se odkazuje na objekty Geometry anebo Appearance NodeComponent. K metodám set existují odpovídající get metody.

void setGeometry(Geometry geometry)

void setAppearance(Appearance appearance)


Čtěte referenční bloky

Referenční bloky v tomto tutoriálu neobsahují všechny konstruktory, metody ani vlastnosti každé třídy Java 3D API. Například referenční blok metod třídy Shape3D neobsahuje seznam všech metod této třídy. Dvě metody které zde schází jsou metody get. Tzn. metody getGeometry() a getAppearance(). Každá z těchto metod vrací odkaz na příslušný NodeComponent.

Protože třídy Java 3D API mají mnoho metod, ale ne všechny jsou zde uvedeny. Ty co jsou uvedeny v referenčních blocích tohoto tutoriálu souvisí s jednotlivými tématy v tutoriálu. Mnoho tříd má teké get a set metody. get metody nejsou uváděny aby se zmenšila délka referenčních bloků.

Následující referenční blok uvádí vlastnosti objektů Shape3D. Tento referenční blok používá zkrácený zápis těchto vlastností. Každý řádek referenčního bloku uvádí dvě vlastnosti místo jen jedné. Každý Shape3D objekt má vlastnosti ALLOW_GEOMETRY_READ a ALLOW_GEOMETRY_WRITE. Tyto párové vlastnosti lze najít docela často. Aby se zmenšila velikost referenčních bloků, bloky obsahující vlastnosti uvádí tyto vlastnosti ve zkrácené formě.

Kompletní seznam konstruktorů, metod a vlastností lze najít v dokumentaci k API.


Vlastnosti objektu Shape3D

Objekty Shape3D dědí vlastnosti od tříd SceneGraphObject, Node a Leaf. Tyto vlastnosti zde nejsou uvedeny. Více informací o vlastnostech najdete v sekci 1.8.2.

ALLOW_GEOMETRY_READ | WRITE

ALLOW_APPEARANCE_READ | WRITE

ALLOW_COLLISION_BOUNDS_READ | WRITE


Složky uzlu

Objekty NodeComponent obsahují přesnou specifikaci atributů vizuálního objektu. Každá z mnoha podtříd třídy NodeComponent definuje jisté vizuální atributy. Obrázek 2-3 ukazuje část hierarchie Java 3D API obsahující třídu NodeComponent a její potomky. Sekce 2.5 představuje Geometry NodeComponent. Sekce 2.6 představuje Appearance NodeComponent.

img2-3

Definice tříd vizuálních objektů

Jeden a tentýž vizuální objekt se může docela často objevovat v daném virtuálním vesmíru. Proto dává smysl definovat třídu k vytvoření vizuálního objektu místo vytváření každého jednotlivého objektu od nuly. Existuje mnoho způsobů jak navrhnout třídu vizuálního objektu.

Následující ukázka kódu obsahuje kostru třídy VisualObject jako příklad jedné z možných implementací generické třídy pro vizuální objekty. Metody jsou definovány jako prázdné. Tato třída není použita v příkladech protože není plně použitelná.

1. public class VisualObject extends Shape3D {
2.	private Geometry voGeometry;
3.	private Appearance voAppearance;
4.
5.	// vytvoří Shape3D s definovanou geometrií a vzhledem
6.	// geometrie je vytvořena v metodě createGeometry
7.	// vzhled je vytvořen v metodě createAppearance
8.	public VisualObject() {
9.		voGeometry = createGeometry();
10.		voAppearance = createAppearance();
11.		this.setGeometry(voGeometry);
12.		this.setAppearance(voAppearance);
13.	}
14.
15.	private Geometry createGeometry() {
16.		// kód k vytvoření základní geopmetrie
17.	}
18.
19.	private Appearance createAppearance() {
20.		// kód k vytvoření základního vzhledu
21.	}
22. }

Uspořádání třídy VisualObject v předchozí ukázce kódu je podobné pomocné třídě ColorCube která rozšiřuje třídu Shape3D. Třída VisualObject je doporučeným počátečním bodem pro definici vlastních tříd pro tvorbu obsahu v grafu scény. Každý progamátor v Java 3D bude jistě upravovat třídu VisualObject pro vlastní účely. Kompletní příklad uspořádání takové třídy můžete najít ve zdrojovém kódu třídy ColorCube v balíčku com.sun.j3d.utils.geometry který je distribuován spolu s Java 3D API.

Použití Shape3D jako základu pro vytvoření třídy vizuálního objektu ulehčuje programování v Java 3D. Třída vizuálního objektu může být použita stejně lehce jako třída ColorCube v příkladech HelloJava3D z kapitoly 1. Po zavolání konstruktoru lze nově vytvořený objekt vložit do Group jako jejího potomka na jedné řádce kódu. V následující jendořádkové ukázce kódu je proměnná objRoot instancí třídy Group. Tento kód vytváří VisualObject a vkládá ho do objRoot v grafu scény:

	objRoot.addChild(new VisualObject());

Konstruktor VisualObject vytváří VisualObject vytvořením objektu Shape3D který se odkazuje na NodeComponent vytvořený metodami createGeometry() a createAppearance(). Metoda createGeometry() vytváří Geometry NodeComponent který je použit ve vizuálním objektem. Metoda createAppearance() je zodpovědná za vytvoření NodeComponent která definuje Appearance (vzhled) vizuálního objektu.

Dalším možným uspořádáním vizuálního objektu je definovat obalovou třídu která není odvozena od tříd v Java 3D API. V takovém návrhu by třída vizuálního objektu obsahovala Group Node nebo Shape3D jako kořen definoveného subgrafu. Třída musí definovat metodu (nebo metody) která navrací odkaz na tento kořen. Tato technika je pracnější, ale může být srozumitelnější. Některé příklady uvedené později v této kapitole obsahují ukázky definicí tříd nezávisle vytvořených vizuálních objektů.

Třetím možným uspořádáním třídy vizuálníh objektu je podobné třídám Box, Cone, Cylinder a Sphere z balíčku com.sun.j3d.utils.geometry. Každá z těchto tříd rozšiřuje třídu Primitive a ta zase rozšiřuje třídu Group. Detaily návrhu třídy Primitive a jejích potomků nejsou v tomto tutoriálu obsažené, ale k dispozici je zdrojový kód těchto tříd distribuovaný spolu s Java 3D API. Z těchto zdrojů se tak lze naučit více o návrhu třídy Prmitive a jiných pomocných tříd.

Pomocné geometrické třídy

Tato sekce pokrývá pomocné třídy pro vytváření primitvní geometrie jako je hranol, kužel, válec a koule. Geometrická primitiva jsou druhou nejlehčí cestou jak vytvořit obsah virtuálního vesmíru. Nejlehčí cestou je použít třídu ColorCube.

Třídy primitiv poskytují programátorovi více flexibility než třída ColorCube. Vše v třídě ColorCube je neměnitelné, kromě velikosti (Objekt Geometry NodeComponent odkazovaný třídou ColorCube lze změnit, ale pak se již nejeví jako ColorCube). Velikost ColorCube lze nastavit jen při jejím vytváření.

Objekt primitiva nabízí více flexibility tím že definuje tvar bez definice jeho barvy. V pomocné třídě geometrického primitiva nemůže programátor změnit geometrii, ale může změnit jeho vzhled (stejně jako v ColorCube, lze změnit Geometry NodeComponent odkazovaný objektem primitiva, ale pak už se nejeví jako původní primitivum). Pomocné třídy primitiv umožňují programátorovi vytvářet více instancí jednoho primitiva s různým vzhledem, díky odkazu na různé Appearance NodeComponenty.

Pomocné třídy Box, Cone, Cylinder a Sphere jsou definovány v balíčku com.sun.j3d.utils.geometry. Detaily o třídách Box, Cone, Cylinder a Sphere jsou uvedeny v sekcích 2.3.12.3.4 včetně. Nadtřída těchto primitiv, Primitive, je probírána v sekci 2.3.5. Část hierarchie balíčku com.sun.j3d.utils.geometry který obsahuje třídy primitiv je ukázán na obrázku 2-4 níže.

img2-4

Třída Box

Geometrické primitivum Box vytváří 3D vizuální objekt hranolu (technicky vzato je hranol šestistranný polyhedron s pravoúhlými stranami). Základní nastavení délky, šířky a výšky jsou 2 metry, se středem v počátku se souřadnicemi rohů na (-1, -1, -1) a (1, 1, 1). Délka, šířka a výška může být určena při vytváření objektu. Samozřejmě lze ke změně pozice a orientace hranolu v grafu scény použít třídu TransformGroup, stejně jako u jiných vizuálních objektů.


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

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

Box rozšiřuje Primitive, která se nalézá ve stejném balíčku.

Box()

Vytváří základní hranol o straně 2 metry (výška, šířka, hloubka) umístěný na počátku souřadnic.

Box(float xdim, float ydim, float zdim, Appearance appearance)

Vytváří hranol daných rozměrů a vzhledu, umístěný na počátku souřadnic.


Zatímco konstruktory tříd Box, Cone a Cylinder se liší, metody mají společné. Následující referenční blok obsahuje seznam metod těchto tříd.


Metody tříd Box, Cone a Cylinder

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

Tyto metody jsou definované po každou z uvedených tříd. Tato primitiva jsou sestavena mnoha objekty třídy Shape3D.

Shape3D getShape(int id)

Vrací jednu stěnu (Shap3D) primitiva které obsahuje danou geometrii a vzhled. Objekty Box, Cone a Cylinder jsou složeny z více než jednoho Shape3D objektu z nichž každý má svou složku uzlu Geometry. Hodnota id říká kterou složku uzlu Geometry má metoda navrátit.

void setAppearance(Appearance appearance)

Nastavuje vzhled primitiva (pro všechny obsažené objekty Shape3D.


Třída Cone

Třída Cone definuje uzavřené, kuželovité objekty umístěné na počátk souřadnic se středovu osou na ose y. Základní poloměr je 1.0 a výšk 2.0 metrů. Střed kužele je spíše středem obkopujícího tělesa než střed kužele samotného.


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

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

Třída Cone rozšiřuje třídu Primitive která se nachází ve stejném balíčku.

Cone()

Vytváří základní kužel o poloměru 1.0 a výšce 2.0 metrů.

Cone(float radius, float height)

Vytváří základní kužel daného poloměru a výšky.


Třída Cylinder

Třída Cylinder vytváří uzavřený, válcovitý objekt umístěný na počátku souřadnic se středovou osou na ose y. Základní poloměr je 1.0 a výška 2.0 metry.


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

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

Třída Cylinder rozšiřuje třídu Primitive která se nachází ve stejném balíčku.

Cylinder()

Vytváří základní válec o poloměru 1.0 a výšce 2.0 metrů.

Cylinder(float radius, float height)

Vytváří válec daného poloměru a výšky.

Cylinder(float radius, float height, Appearance appearance)

Vytváří válec daného poloměru, výšky a vzhledu.


Třída Sphere

Třída Sphere vytváří kulovitý vizuální objekt umístěný na počátku souřadnic. Základní poloměr je 1.0 metru.


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

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

Třída Sphere rozšiřuje třídu Primitive která se nachází ve stejném balíčku.

Sphere()

Vytváří základní kouli o poloměru 1.0 metru.

Sphere(float radius)

Vytváří základní kouli daného poloměru.

Sphere(float radius, Appearance appearance)

Vytváří kouli o daném poloměru a vzhledu.

Metody třídy Sphere

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

Jako rozšíření třídy Primitive, třída Sphere je de fact objektem Group který má jediný objekt Shape3D.

Shape3D getShape()

Navrací objekt Shape3D který obsahuje geometrii a vzhled.

Shape3D getShape(int id)

Tato metoda je zde uvedena pro kompatibilitu s jinými podtřídami třídy Primitive: Box, Cone a Cylinder. Ale protože třída Sphere ma jen jeden Shape3D objekt, může být volána jen s id = 1.

void setAppearance(Appearance appearance)

Nastavuje vzhled koule.


Více o geometrických primitivech

Geometrie pomocné třídy primitv nedefinuje žádno barvu pro takový vizuální objekt. Geometrie která nedefinuje barvu odvozuje barvu z objektu Appearance. Bez odkazu na složku uzlu Appearance je základní definovaná barva vizuálního objektu bílá. Více o barvě je v sekci 2.4.2 a geometrii v sekci 2.5.1. Sekce 2.6 uvádí detaily o složkách uzlu Appearance.

Třída Primitive definuje základní hodnoty které jsou společné pro Box, Cone, Cylinder a Sphere. Například třída Primitive definuje základní hodnotu pro počet polygonů použitývh k reprezentaci povrchů. Sekce 2.3.8 uvádí některé detaily o třídě Primitive. Protože základní hodnoty definované v této třídě jsou vhodné pro většinu aplikací, programy v Java 3D mohou být psány bez použtí třídy Primitive. Z toho důvodu sekce která popisuje třídu Primitive je považována za pokročilé téma (které lze přeskočit).

2.3.6 ColorCube

Třída ColorCube je zde uvedena v kontrastu jiných tříd primitiv jako Box, Cone, Cylinder a Sphere. Třída ColorCube rozšiřuje jinou hierarchii tříd než tříd grafických primitiv. Je podtřídou třídy Sphape3D. Tato hierarchie je na obrázku 2-5. Kapitola 1 obsahuje příslušné referenční bloky.

img2-5

Třída ColorCube je jedinou třídou distribuovanou s Java 3D API která dovoluje programátorovi ignorovat potřebu barev a světel na scéně. Z tohot důvodu se tato třída používá pro rychlé sestavení grafů scény při testování nebo prototypování.

2.3.7 Příklad: Vytváření jednoduchého Joja ze svou kuželů

Tato sekce ukazuje jednoduchý příklad který používá třídu Cone: ConeYoYoApp.java. Úkolem programu je vykreslit jojo. K vytvoření joja jsou požity dva kužely. K pohybu joja nahoru a dolů by mohly být použity třídy chování Java 3D API, ale to je mimo rozsah této kapitoly. Program sám jojem otáčí, takže lze docenit použitou geometrii. Graf scéna na obrázku 2-6 ukazuje návrh tříd ConeYoYo a ConeYoYoApp v programu ConeYoYoApp.

Základní umístění objektu Cone s jeho obklopujícím polygonem je na počátku souřadnic. Zákadní orientace je středem joja směrem k pozorovateli, tedy se středem na ose y. Jojo jetvořeno dvěma kužely které jsou rotovány kolem osy z a posunuty na ose x tak aby se vrcholy kuželů stýkaly v počátku souřadnic.

img2-6

V grafu větve který začíná dvěma objekty BranchGroup obsahující objekty ConeYoYo, pokračuje cesta grafu scény ke každému y objektů Cone přes objekt TransformGroup který určuje posun následovaný dalším objektem TransformGroup který určuje rotaci a celá cesta grafu scény končí objektem Cone.

K reprezentaci stejného virtuálního světa lze sestavit mnoho odlišných grafů scény. Vezmeme-li tento graf scény jako příklad, pak na něm lze provést několik zřejmých změn. Jedna změna eliminuje objekt BranchGroup jehož potomkem je objekt ConeYoYo a vkládá tento objekt přímo do Locale. BranchGroup je zde pro přidávání vizuálních objektů na scénu v buducnosti. Jiná změna kombinuje dva objekty TransformGroup. V tomto příkladu jsou tyto transformace ukázány takto jednoduše pro ilustraci.

Uzly Shape3D objektů Cone se odkazují na složky uzlu Geometry. Ty jsou skryty uvnitř objektů Cone. Objekty Shape3D v objektu Cone jsou dětmi třídy Group. Protože objekty Cone dědí od Group, nelze použít jeden a ten samý objekt Cone (nebo jiný objekt Primitive) v grafu scény více než jednou. Ukázka kódu níže ukazuje příklad chybové hlášky při pokusu použít jeden objekt Cone vícekrát v jednom grafu scény. Tato chyba není součástí ukázkového programu v tomto tutoriálu.

Exception in thread "main" javax.media.j3d.MultipleParentException:
Group.addChild: child already has a parent
at javax.media.j3d.GroupRetained.addChild(GroupRetained.java:246)
at javax.media.j3d.Group.addChild(Group.java:241)
at ConeYoyoApp$ConeYoyo.(ConeYoyoApp.java:89)
at ConeYoyoApp.createSceneGraph(ConeYoyoApp.java:119)
at ConeYoyoApp.(ConeYoyoApp.java:159)
at ConeYoyoApp.main(ConeYoyoApp.java:172)
img2-8

Obrázek 2-8 ukazuje jeden z možných obrázků vykreslených programem ConeYoYo. Zdrojový kód příkladu naleznete v adresáři geometry. Třída ConeYoYo je ukázána níže.

Řádky v první pětině programu vytváří objekty které tvoří polovinu grafu scény. Řádky ve třetí pětině vytváří vztahy mezi těmito objekty. Proces se pak opakuje dále až do čtvrté pětiny programu.

public class ConeYoYo {
	private BranchGroup yoyoBG;

	public ConeYoYo() {
		yoyoBG = new BranchGroup();
		Transform3D rotate = new Transform3D();
		Transform3D translate = new Transform3D();
		Appearance yoyoAppear = new Appearance();
		rotate.rotZ(Math.PI / 2.0d);
		TransformGroup yoyoTGR1 = new TransformGroup(rotate);
		translate.set(new Vector3f(0.1f, 0.0f, 0.0f));
		TransformGroup yoyoTGT1 = new TransformGroup(translate);
		Cone cone1 = new Cone(0.6f, 0.2f);
		cone1.setAppearance(yoyoAppear);
		yoyoBG.addChild(yoyoTGT1);
		yoyoTGT1.addChild(yoyoTGR1);
		yoyoTGR1.addChild(cone1);
		translate.set(new Vector3f(-0.1f, 0.0f, 0.0f));
		TransformGroup yoyoTGT2 = new TransformGroup(translate);
		rotate.rotZ(-Math.PI / 2.0d);
		TransformGroup yoyoTGR2 = new TransformGroup(rotate);
		Cone cone2 = new Cone(0.6f, 0.2f);
		cone2.setAppearance(yoyoAppear);
		yoyoBG.addChild(yoyoTGT2);
		yoyoTGT2.addChild(yoyoTGR2);
		yoyoTGR2.addChild(cone2);
		yoyoBG.compile();
	}

	public BranchGroup getBG() {
		return yoyoBG;
	}
}

2.3.8 Pokročilé téma: třída geometrických primitiv

Hierarchie tříd na obrázku 2-4 ukazuje třídu Primitive jako nadtřídu tříd Box, Cone, Cylinder a Sphere. Ta definuje mnoho společných vlastností a metod pro tyto podtřídy, stejně jako základní hodnoty těchto vlastností.

Třída Primitive poskytuje způsob jak sdílet složky uzlu Geometry mezi instancemi primitiv stejné velikosti. Standardně sdílí všechny primitiva stejné velikosti jednu složku geometrie uzlu. Jako příklad vlastnosti definované ve třídě Primitive lze uvést celočíselnou konstantu GEOMETRY_NOT_SHARED. Tato vlastnost říká že vytvořená geometrie se nebude sdílet. Tuto vlastnost můžete nastavit abyste zabrálnili sdílení geometrie ostatními primitivy se stejnými parametry (např. mezi koulemi s poloměrem 1).

	myCone.setPrimitiveFlags(Primitive.GEOMETRY_NOT_SHARED);

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

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

Třída Primitive rozšiřuje třídu Group a je nadtřídou tříd Box, Cone, Cylinder a Sphere.

public void setNumVertices(int num)

Nastavuje celkový počet vertexů primitiva.

void setPrimitiveFlags(int fl)

Vlastnosti primitiv:

GENERATE_NORMALS - spolu s pozicemi jsou generovány normály primitiv

GENERATE_NORMALS_INWARD - normály jsou generovány pro opačnou (odvrácenou, vnitřní) stranu povrchu

GENERATE_TEXTURE_COORDS - generuje souřadnice textury

GEOMETRY_NOT_SHARED - vytvořená geometrie nebude sdílená jiným uzlem

void setAppearance(int partid, Appearance appearance)

Nastavuje vzhled části partid primitiva. Objekty Box, Cone a Cylinder jsou poskládány z více než jednoho objektu Shape3D a každý může obsahovat vlastní složku uzlu Appearance. Hodnota použitá pro partid říká která ze složek uzlu Appearance se bude nastavovat.

void setAppearance()

Nastavuje vzhled primitiva (a všech jeho částí) na bílou barvu


2.4 Matematické třídy

K vytvoření vizuálních objektů je zpotřebí třída Geometry a její podtřídy. Mnoho podtřídy třídy Geometry popisuje primitva složená z vertexů, jako body, čáry a mnohoúhelníky. Tyto podtřídy jsou diskutovány v sekci 2.5, ale předtím je potřeba probrat mnoho matematických tříd (Point*, Color*, Vector*, TexCoord*) určené ke specifikaci vertexů.

všimněte si hvězdičky použité za jako zástupný znak představující různé jména tříd. Například Tuple* se odkazuje na všechny třídy Tuple: Tuple2f, Tuple2d, Tuple3b, Tuple3f, Tuple3d, Tuple4b, Tuple4f a Tuple4d. V každém z případů číslo za názvem znamená počet prvků v řazeném seznamu (tuple) a písmeno značí datový typ prvků. "f" znamená destinné číslo s jednoduchou přeností, "d" znamená desetinné číslo s dvojitou přesností a "b" je pro typ byte. Takže Tuple3f je třída která pracuje s třemi hodnotami desteinných čísel s jednoduchou přesností.

Všechny matematické třídy lze nalézt v balíčku javax.vecmath.* Tento balíček obsahuje mnoho Tuple* tříd jako základní abtraktní nadtřídy. Jiné, užitečnější třídy jsou od těchto tříd odvozeny. Níže je uvedena hierarchie tříd jednoho z balíčků.

img2-9

Každý z vertexů vozuálního objektu může spcifikovat až čtyři objekty javax.vecmath představující souřadnice, barvy, normály povrchů a souřadnice textur. Běžně se pro to používají následující třídy:

Všimněte si že souřadnice (objekty Point*) jsou nezbytné k umístění každého vertexu. Ostatní data jsou volitelná v závislosti na tom jaké primitivum se vykresluje. Například barva (objekt Color*) může být definována pro každý vertex a barvy primitiva jsou pak interpolovány dle barev jednotlivých vertexů. Pokud je zapnuto osvětlování, jsou zapotřebí i normály povrchů (takže i objekty Vector*). Pokud je zapnuto mapování textur, pak mohou být potřeba i souřadnice textur.

Objekty Quat* představují kvaterniony, které se používají jen pro pokročilé 3D transformace matic.

Protože všechny dúležité třídy dědí od abstraktních tříd Tuple*, je důležité znát jejich konstruktory a metody které naleznete níže.


Konstruktory třídy Tuple2f

Balíček: javax.vecmath

Třídy Tuple* se typicky nepoužívají v Java 3D programech přímo, ale jsou to základní stavební jednotky pro třídy Point*, Color*, Vector* a TexCoord*. Přesněji tvoří třída Tuple2f základ tříd Point2f, Color2f a TexCoord2f. Zde uvedené konstruktory jsou těmto podtřídám přístupné. Třídy Tuple3f a Tuple4f mají podobnou sadu konstruktorů.

Tuple2f()

Vytváří a inicializuje objekt Tuple na souřadnicích (0, 0).

Tuple2f(floatx, float y)

Vytváří a inicializuje objekt Tuple na určených souřadnicích x a y.

Tuple2f(float[] t)

Vytváří a inicializuje objekt Tuple ze zadaného pole.

Tuple2f(Tuple2f t)

Vytváří a inicializuje objekt Tuple z dat jiného objektu Tuple.

Tuple2f(Tuple2d t)

Vytváří a inicializuje objekt Tuple z dat jiného objektu Tuple2d.



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

Balíček: javax.vecmath

Třídy Tuple* se typicky nepoužívají v Java 3D programech přímo, ale jsou to základní stavební jedntky pro třídy Point*, Color*, Vector* a TexCoord*. Přesněji tvoří třída Tuple2f základ tříd Point2f, Color2f a TexCoord2f. zde uvedené konstruktory jsou těmto podtřídám přístupné. Třídy Tuple3f a Tuple4f mají podobnou sadu metod.

void set(float x, float y)

Nastavuje data objektu Tuple.

void set(float[] t)

Nastavuje hodnotu na určenou polem hodnot.

boolean equals(Tuple2f t1)

Vrací hodnotu true pokud jsou data v objektu Tuple t1 rovna odpovídajícím datům v tomto objektu.

final void add(Tuple2f t1)

Nastavuje hodnotu tohoto objektu na vektorový součet svých hodnot a hodnot objektu Tuple t1

void add(Tuple2f, t1, Tuple2f t2)

Nastavuje hodnotu tohoto objektu na vekotorvý součet hodnot objektů t1 a t2.

void sub(Tuple2f t1, Tuple2f t2)

Nastavuje hodnotu tohoto objektu na rozdíl vektorů objektů t1 a t2 (this t1 - t2)

void negate()

Neguje hodnotu vektoru.

void negate(Tuple2f t1)

Nastavuje hodnotu daného objektu na negativní hodnotu objektu t1.

void absolute()

Nastavuje každý komponent tohoto objektu na jeho absolutní hodnotu.

void absolute(Tuple2f t)

Nastavuje každý komponent předávaného objektu na jeho maximální hodnotu a nahrazuje objekt stávající.


Existují jemné, ale předvídatelné rozdíly mezi konstruktory a metodami tříd Tuple* týkající se počtu argumentů a jejich datového typu. Například Tuple3d se liší od Tuple2f v konstruktoru:

	Tuple3d(double x, double y, double z);

Ten očekává tři, ne dva parametry, s dvojitou přesností.

Každá ze tříd Tuple* má veřejné členy. Pro Tuple2* jsou to x a y. Pro Tuple3* jsou to x, y a z. Pro Tuple4* jsou to x, y, z a w.

2.4.1 Třídy Point

Objekty Point* obvykle představují souřadnice vertexu, i když mohou také představovat pozici rastrového obrazu, bodový zdroj světla, prostorové umístění zvuku nebo jiná umístění. Konstruktory tříd Point* jsou podobné těm u tříd Tuple*, kromě toho že navracejí objekty Point*.


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

Baliček: javax.vecmath

Třídy Point* jsou odvozeny od tříd Tuple*. Každá instance třídy Point* představuje jeden bod se dvěmi, třemi nebo čtyřmi složkami. Třídy Point* mají navíc k metodám tříd Tuple* i jiné metody, kz nichž některé zde nejsou uvedeny.

float distance(Point3f p1)

Navrací euklidovskou vzdálenost mezi tímto bodem a bodem p1.

float distanceSquared(Point3f p1)

Navrací druhou mocninu euklidovské vzdálenosti mezi tímto bodem a bodem p1.

float distanceL1(Point3f p1)

Navrací L1 (Manhattanovu) vzdálenost mezi tímto bodem a bodem p1. Vzdálenost L1 se rovná:

	abs(x1 - x2) + abs(y1 - y2) + abs(z1 - z2)

Opět, existují zde jemné, ale předvídatelné rozdíly mezi konstrukory a metodami tříd Point*, kvůli počtu parametrů a jejich datovým typům.

Třídy Color

Objekty tříd Color* představuj barvu, což může být barva vertexu, součást vlastností materiálu, barva mlhy nebo jiného vizuálního objektu. Barvy jsou specifikovány třídami Color3* a Color4* s datovým typem byte nebo float. Objekty Color3* specifikují barvu jako kombinaci hodnot červené, zelené a modré (RGB). Objekty Color4* specifikují navíc hodnotu průhlednosti (normáoně jsou objekty Color3* neprůhledné). Pro hodnoty typu byte jsou barevné hodnoty v rozsahu 0 až 255 včetně. Pro hodnoty typu float jsou hodnoty barev v rozsahu 0.0 až 1.0 včetně.

Opět, konstruktory tříd Color* jsou podobné kontruktorům tříd Tuple*, kromě toho že navracejí objekty typu Color*. Třídy Color* nemají žádné metody navíc, tudíž se spoléhají na metody zděděné od jejich nadtříd typu Tuple*.

Občas je vhodné vytvořit konstanty pro barvy které se opakovaně používají při vytváření vizuálních objektů. Například:

	Color3f red = new Color3f(1.0f, 0.0f, 0.0f);

Na tomto řádku vytváříme objekt třídy Color3f pojmenovaný red který může být mnohokrát použit. Může pomoci i vytvořit třídu obsahující několik konstant barev. Příklad takové třídy můžete vidět níže.

import javax.vecmath.*;

class ColorConstants {
	public static final Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
	public static final Color3f green = new Color3f(0.0f, 1.0f, 0.0f);
	public static final Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);
	public static final Color3f yellow = new Color3f(1.0f, 1.0f, 0.0f);
	public static final Color3f cyan = new Color3f(0.0f, 1.0f, 1.0f);
	public static final Color3f magenta = new Color3f(1.0f, 0.0f, 1.0f);
	public static final Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
	public static final Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
}

Třídy Color*

Balíček: javax.vecmath

Třídy Color* jsou odvozeny od tříd Tuple*. Každá instance tříd Color* představuje jednu barvu sestávající ze tří (RGB) nebo čtyř složek (RGBA). Třídy Color* nepřidávají žádnou metodu k těm poskytovaným třídami Tuple*.


2.4.3 Třídy Vector

Objekty Vector* často představují povrchové normály vertexů i když mohou představovat směr světelného zdroje nebo zvuku. Opět, konstruktory tříd Vector* jsou podobné konstruktorům tříd Tuple*.


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

Balíček: javax.vecmath

Třídy Vector* jsou odvozeny od tříd Tuple*. Každá instance tříd Vector* představuje jeden vektor ve dvou, třech nebo čtyřech dimenzích. Třídy Vector* obsahují nějaké metody navíc, některé jsou na seznamu níže.

float length()

Navrací délku vektoru

float lengthSquared()

navrací odmocninu délky vektoru

void cross(Vector3f v1, Vector3f v2)

Nastaví tento vektor na výsledek součinu vektorů v1 a v2.

float dot(Vector3f v1)

Počítá a navrací skalární součin tohoto vektoru a vektoru v1

normalize()

Normalizuje vektor

void normalize(Vector3f v1)

Nastavuje hodnotu tohoto vektoru na normalizovanou hodnotu vektoru v1

float angle(Vector3f v1)

Navrací úhel v radiánech mezi tímto vektorem a vektorem předaným jako parametr. Návratová hodnota je omezena v rozsahu [0, PI].


Existují jemné ale předvídatelné rozdíly mezi konstruktory a metodami tříd vector* kvůli datovému typu nebo číslu.

2.4.4 Třídy TexCoord

Existují jen dvě třídy TexCoord* které lze použít jako sadu souřadnic textur vertexu: TexCoord2f a TexCoord3f. Třída TexCoord2f reprezentuje souřadnice jako pár (s, f), třída TexCoord3f jako trojici (s, t, r).

Konstruktory tříd TexCoord* jsou opět podobné konstruktorům tříd Tuple*. Stejně jako třídy Color*, třídy TexCoord* nemají žádné metody navíc, takže se plně spoléhají na metody zděděné od nadtříd Tuple*.

Geometrické třídy

V 3D počítačové grafice je vše od nejjednoduššího trojúhleníku až po nejsložitejší model letadla modelováno a renderováno vertexy. V Java 3D by měl každý objekt Shape3D volat svou metodu setGeometry() odkazující na jeden jediný objekt Geometry Přesněji, třída Geometry je abstraktní nadtřída, takže odkazovaný objekt je je instancí podtřídy třídy Geometry.

Podtřídy třídy Geometry spadají do tří kategorií:

Tato sekce pokrývá dvě ze zmíněných kategorií.

img2-10

2.5.1 Třída GeometryArray

Jak si lze odvodit z názvů tříd, podtřídy třídy Geometry lze použít ke specifikování bodů, úseček a plných polygonů (trojúhelníků a kvadrilaterálů). Tato vertexová primitiva jsou podtřídami abstraktní třídy GeometryArray, která naznačuje že každá třída obsahuje pole která drží data pro každý vertex.

Například pokud je objekt třídy GeometryArray určen k reprezentaci jednoho trojúhelníku, je vytvořeno pole o třech prvcích: jeden prvek pro každý z vertexů. každý prvek tohoto pole obsahuje souřadnice tohoto vertexu (který může být definován jako objekt Point* nebo podobně). navíc k poli obsahujícímu souřadnice mohou existovat tři další k uložení barvy, povrchové normály a souřadnic textur. Tato pole obsahující souřadnice, barvy, povrchové normály a souřadnice textur jsou "ta" datová pole.

Zde jsou tři kroky v životě objektu GeometryArray:

  1. Konstrukce prázdného objektu
  2. Naplnění objektu daty
  3. Spojení (odkazování se) objektu s (jedním nebo více) objekty Shape3D

Krok 1: Konstrukce prázdného objektu třídy GeometryArray

Když se konstruuje objekt GeometryArray, je potřeba definovat dvě věci:

Existuje jen jeden konstruktor třídy GeometryArray:


Konstruktor třídy GeometryArray

GeometryArray(int vertexCount, int vertexFormat)

Vytváří prázdný objekt GeometryArray se zadaným počtem vertexů a formátem vertexů. Jedna nebo více konstant mohou být logicky spojeny pomocí operátoru OR ke specifikaci formátu vertexů.

COORDINATES - vertexové pole obsahuje souřadnice. Povinné.

NORMALS - vertexové pole obsahuje povrchové normály.

COLOR_3 - vertexové pole obsahuje neprůhledné barvy.

COLOR_4 - vertexové pole obsahuje průhledné barvy.

TEXTURE_COORDINATE_2 vertexové pole obsahuje 2D souřadnice textur.

TEXTURE_COORDIANTE_3 vertexové pole obsahuje 3D souřadnice textur.

Pro každou konstantu je interně vytvořeno odpovídající pole v objektu GeometryArray. Každé z těchto polí má velikost vertexCount.


Podívejme se jak tento konstruktor pracuje, ale nezapomeňme že třída GeometryArray je abstraktní. Takže vlastně voláme konstruktor jedné z podtříd, například třídy LineArray (objekt této třídy popisuje množinu vertexů a každý ze dvou vertexů popisují jeden konec úsečky) Konstruktor a ostatní metody této třídy jsou podobné těm v nadtřídě. Třída LineArray je popsána v sekci 2.5.2).

Následující ukázka kódu obsahuje třídu Axis z programu AxisApp který používá několik objektů AxisApp k vykreslování úseček představujících osy x, y a z. Osu x tvoří objekt se dvěma vertexy (počáteční a koncový bod) specifikujícími souřadnice pozice. Objekt tvořící osu y má také dva vertexy, ale navíc umožňuje určit RGB barvu a souřadnice pozice každého vertexu. Díky tomu lze osu y vykreslit pomocí interpolace barev koncových bodů. Osa z je tvořena deseti vertexy s daty souřadnic a barev pro každý vertex. Tak lze vykreslit pět úseček s interpolací barev, z nichž každá je umístěna mezi dvěma vertexy. Všimněte si použití bitového operátoru OR ve specifikaci formátu pixelů u os y a z.

1.	//  vytvoříme objekt představující osu X
2.	LineArray axisXLines = new LineArray(2, LineArray.COORDINATES);
3.
4.	// vytvoříme objekt představující osu Y
5.	LineArray axisYLines = new LineArray(2, LineArray.COORDINATES 
6									| LineArray.COLOR_3);
7.
8.	// vytvoříme objekt představující osu Z
9.	LineArray axisZLines = new LineArray(10, LineArray.COORDINATES 
10.									 | LineArray.COLOR_3);

Buďte opatrní. Třída Axis v souboru AxisApp.java se liší od třídy Axis definované v souboru geometry/Axis.java, která používá jen jeden objekt LineArray. Ujistěte se máte tu správnou. Třída Axis definovaná v souboru Axis.java je určena pro použití ve vašich programech, zatimco AxisApp.java je ukázkový program tohoto tutoriálu. Navíc třída Axis definovaná v souboru Axis.java ukazuje použití třídy vizuálního objetu rozšiřujícího třídu Shape3D.

Krok 2: Naplnění objektu třídy GeometryArray daty

Po zkonstruování objektu GeometryArray se přiřadí hodnoty do polí dle specifikovaného vertexového formátu. Buď vertex po vertexu nebo přiřazením dat více vertexům pomocí pole v jednom volání metody. Dostupné metody jsou tyto:


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

GeometryArray je nadtřídou tříd PointArray, TriangleArray, QuadArray, GeometryStripArray a IndexedGeometryArray.

void setCoordinate(int index, float[] coordinate)

void setCoordinate(int index, double[] coordinate)

void setCoordinate(int index, Point* coordinate)

Tyto metody nastavují souřadnici vertexu na daném indexu.

void setCoordinates(int index, float[] coordinates)

void setCoordinates(int index, double[] coordinates)

void setCoordinates(int index, Point*[] coordinates)

Tyto metody nastavují souřadnice vertexů na daném indexu.

void setColor(int index, float[] color)

void setColor(int index, byte[] color)

void setColor(int index, Color* color)

Tyto metody nastavují barvu vertexu na daném indexu.

void setColors(int index, float[] colors)

void setColors(int index, byte[] colors)

void setColors(int index, Color*[] colors)

Tyto metody nastavují barvy vertexů na daném indexu.

void setNormal(int index, float[] normal)

void setNormal(int index, Vector* normal)

Tyto metody nastavují normálu vertexu na daném indexu.

void setNormals(int index, float[] normals)

void setNormals(int index, Vector*[] normals)

Tyto metody nastavují normály vertexů na daném indexu.

void setTextureCoordinate(int index, float[] texCoord)

void setTextureCoordinate(int index, Point* coordinate)

Tyto metody nastavují souřadnici textury vertexu na daném indexu.

void setTextureCoordinates(int index, float[] texCoords)

void setTextureCoordinates(int index, Point*[] texCoords)

Tyto metody nastavují souřadnice textury vertexů na daném indexu.


Následující ukázka kódu ukazuje jak použít metody třídy GeometryArray k uložení hodnot souřadnic a barev v objektech LineArray. Objekt osy x volá jen metodu setCoordinate() k uložení souřadnice pozice. Objekt osy y volá obě metody setColor() a setColors() k načtení RGB barvy a souřadnic pozice. Objekt osy z volá metodu setCoordinate() desetkrát, pro každý vertex jednou, a jednou metodu setColors() k načtení všech deseti vertexů v jediném volání metody.

1.	axisXLines.setCoordinate(0, new Point3f(-1.0f, 0.0f, 0.0f));
2.	axisXLines.setCoordinate(1, new Point3f(1.0f, 0.0f, 0.0f));
3.
4.	Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
5.	Color3f green = new Color3f(0.0f, 1.0f, 0.0f);
6.	Color3f blue = new Color3f(0.0f, 0.0f, 1.0f);
7.	axisYLines.setCoordinate(0, new Point3f(0.0f, -1.0f, 0.0f));
8.	axisYLines.setCoordinate(1, new Point3f(0.0f, 1.0f, 0.0f));
9.	axisYLines.setColor(0, green);
10.	axisYLines.setColor(1, blue);
11.
12.	axisZLines.setCoordinate(0, z1);
13.	axisZLines.setCoordinate(1, z2);
14.	axisZLines.setCoordinate(2, z2);
15.	axisZLines.setCoordinate(3, new Point3f(0.1f, 0.1f, 0.9f));
16.	axisZLines.setCoordinate(4, z2);
17.	axisZLines.setCoordinate(5, new Point3f(-0.1f, 0.1f, 0.9f));
18.	axisZLines.setCoordinate(6, z2);
19.	axisZLines.setCoordinate(7, z2);
20.	axisZLines.setCoordinate(8, z2);
21.	axisZLines.setCoordinate(9, new Point3f(-0.1f, -0.1f, 0.9f));
22
23.	Color3f colors[] = new Color3f[9];
24.	Colors[0] = new Color3f(0.0f, 1.0f, 1.0f);
25.	for (int v = 0; v < 9; v++)
26.		colors[v] = red;
27.	axisZLines.setColors(1, colors);

Základní barva vertexů objektu GeometryArray je bílá, pokud nespecifikujete COLOR_3 nebo COLOR_4 ve formátu vertexů. Pokud specifikujete buď COLOR_3 nebo COLOR_4, je základní barva vertexu černá. Pokud jsou úsečky nebo plné polygony renderovány s různými barvami vertexů, pak je barva plynule stínovaná (interpolovaná) mezi vertexy pomoci Gouraudova stínování.

Krok 3: Spojení (odkazování se) objektu s (jedním nebo více) objekty Shape3D

Konečně, ukázka kódu níže ukazuje jak jsou objekty GeometryArray odkazovány novými objekty Shape3D. Na to jsou objekty Shape3D vloženy do BranchGroup, která může být vloena kamkoli do grafu scény (narozdíl od objektů GeometryArray které jsou potomky NodeComponents, Shape3D je podtřída třídy Node, takže objekty Shape3D mohou být vloženy do grafu scény jako děti).

 1.   axisBG = new BranchGroup();
 2.
 3.   axisBG.addChild(new Shape3D(axisYLines));
 4.   axisBG.addChild(new Shape3D(axisZLines));
 

Obrázek 2-11 ukazuje část grafu scény tvořenou třídou Axis v programu AxisApp.java.

img2-11

2.5.2 Podtřídy třídy GeometryArray

Jak bylo diskutováno v předchozí sekci, třída GeometryArray je abstraktní nadtřídou pro více užitečných podtříd jako je LineArray. Obrázek 2-12 ukazuje hierarchii třídy GeometryArray a některých jejích podtříd. Hlavním rozdílem mezi těmito podtřídami je jak Java 3D renderuje jejich vertexy.

img2-12

Obrázek 2-13 ukazuje příklady čtyř podtříd třídy GeometryArray: PointArray, LineArray, TriangleArray a QuadArray (těch které také nejsou podtřídami třídy GeometryStripArray). Na tomto obrázku můžete vidět zleva tři sady šesti vertexů, první vykreslenou jako šest bodů, druhou jako tři úsečky a třetí jako dva trojúhelníky. Čtvrtá sada ukazuje čtyři vertexy tvořící čtyřúhelník. Všimněte si že vertexy nejsou sdílené: každá úsečka nebo plný polygon je vykreslována nezávisle na ostatních.

img2-13

Defaultně je vyplňování trojúhelníků a čtyřúhelníků zapnuto. Později se dozvíte jak lze pomocí atributů ovlivnit vykreslování plných primitiv.

Tyto čtyři podtřídy dědí svoje konstruktory a metody z GeometryArray. Seznam konstruktorů je níže. Seznam jejich metod naleznete výše jako metody třídy GeometryArray.


Konstruktory podtříd třídy GeometryArray

Vytváří prázdný objekt s určeným počtem vertexů a vertexovém formátu. Formát je jedna nebo více konstant spojených logickým operátorem OR a slouží k popisu typu vertexu. Tyto konstanty jsou stejné jako v nadtřídě GeometryArray.

PointArray(int vertexCount, int vertexFormat)

LineArray(int vertexCount, int vertexFormat)

TriangleArray(int vertexCount, int vertexFormat)

QuadArray(int vertexCount, int vertexFormat)


Pokud vykreslujete čtyřúhelníky, myslete na to aby vertexy netvořily konkávní, protínající nebo zakřivenou geometrii. Pokud se tak stane, nemusí být vykresleny správně.

Podtřídy třídy GeometryStripArray

Čtyři podtřídy popsané v předchozí sekci neumžoňují znovupoužít jejich vertexy. Některá geometrická uspořádání si však o to říkají, takže specializovanější třídy mohou zlepšit výkon vykreslování.

Třída GeometryStripArray je abstraktní třída od které jsou odvozena pásová primitiva (pro tvorbu spojitých čar a povrchů). GeometryStripArray je nadtřídou LineStripArray, TriangleStripArray a TriangleFanArray. Obrázek 2-14 ukazuje příklad každého typu pásu a jak jsou vertexy znovupoužity. LineStripArray renderuje spojité čáry. TriangleStripArray vykresluje trojúhelníky sdílející strany, čili znovupoužity jsou naposledy vykreslované vertexy. TriangleFanArray znovupoužívá úplně první vertex v pásu každého trojúhelníku.

img2-14

Třída GeometryStripArray má konstruktor odlišný od třídy GeometryArray Konstruktor GeometryStripArray má třetí parametr, kterým je pole s počtem vertexů na jeden pás, což umožňuje mít jeden objekt obsahující více pásů (GeometryStripArray má také pár metod jako getNumStrips() a getStripVertexCounts() které s epříliš často nepoužívají).


Konstruktory podtříd třídy GeometryStripArray

Vyvtáří prázdný objekt s určeným počtem vertexů, ve vertexovém formátu a polem s počtem vertexů na pás. Formát je jedna nebo více konstant spojených logickým operátorem OR popisujících formát vertexu. Konstanty jsou stejné jako v nadtřídě GeometryArray. je podporováno více pásů. Součet počtu vertexů všech pásů (z pole stripVertexCounts) se musí rovnat počtu všech vertexů (proměnná vtxCount).

LineStripArray(int vtxCount, int vertexFormat, int stripVertexCounts[])

TriangleStripArray(int vtxCount, int vertexFormat, int stripVertexCounts[])

TriangleFanArray(int vtxCount, int vertexFormat, int stripVertexCounts[])


Všimněte si že Java 3D nepodporuje plná primitiva s více než čtyřmi stranami. Programátor je zodpovědný za použití teselátorů k rozložení složitějších polygonů na Java 3D objekty jako jsou pásy trojúhelníků nebo vějíře. Pomocná třída Triangulator převádí složité polygony na trojúhelníky (třída Triangulator a příbuzné třídy jsou vysvětleny v kapitole 3).


Třída Triangulator

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

Používá se pro převod netrojúhelníkových polygonů na trojúhelníky vykreslované v Java 3D. Ploygony mohou být konkávní, nerovinné a mohou obsahovat díry (viz GeometryInfo.setContourCounts()). Neplanární polygony jsou promítnuty na nejbližší rovinu. Poznámka: Podívejte se do současné dokumentace na omezení. Pro více informací se podívejte do sekce 3.3 tohoto tutoriálu.

Konstruktor třídy Triangulator

Triangulator()

Vytvoří objekt triangulátoru

Metody třídy Triangulator

void triangulate(GeometryInfo ginfo)

Tato metoda převádí objekt GeometryInfo z typu POLYGON_ARRAY na typ TRIANGLE_ARRAY pomocí technik rozkladu polygonů.

Parametry:

ginfo - objekt com.sun.j3d.utils.GeometryInfo který se má triangulovat

Příklad použití:

	Triangulator tr = new Triangulator();
	tr.triangulate(ginfo); // ginfo obsahuje geometrii k triangulaci
	shape.setGeometry(ginfo.getGeometryArray()); // shape je objekt Shape3D

Kód JoJa demonstruje použití TriangleFanArray

Objekt Joja v programu YoyoApp.java ukazuje jak použít objekt TriangleFanArray k vymodelování geometrie joja. TriangleFanArray obsahuje čtyři nezávislé vějíře: dvě vnější stěny (kruhové disky) a dvě vnitřní stěny (kužely). K reprezentaci celého joja je zpoatrebí jen jeden objekt TriangleFanArray.

Obrázek 2-15 ukazuje tři modely TriangleFanArray. První model ukazuje defaultní renderování, čili bílé plné polygony. je tžké vidět nějaké detaily, hlavně polohu vertexů. Aby byly trojúhelníky léepe vidět, ostatní dva modely používaji TriangleFanArray s vertexy spojenými úsečkami. Pokud chcete vykreslit polygony jako drátěn model, podívejte se na třídu PolygonAttributes v sekci 2.6.

img2-15

V následující ukázce kódu metoda yoyoGeometry() vytváří a navrací požadovaný objekt TriangleFanArray. Řádky 15 - 18 počítají středové body pro všechny čtyři vějíře. Každý vějíř má 18 vertexů, které se počítají na řádcích 20 - 28. Řádky 30 - 32 vytváří prázdný objekt TriangleFanArray a na řádce 34 se tato vypočítaná data souřadnic (z řádků 15 - 28) ukládají do objektu.

1.	private Geometry yoyoGeometry() {
2.
3.		TriangleFanArray tfa;
4.		int N = 17;
5.		int totalN = 4 * (N + 1);
6.		Point3f coords[] = new Point3f[totalN];
7.		int stripCounts[] = {N + 1, N + 1, N + 1, N + 1};
8.		float r = 0.6f;
9.		float w = 0.4f;
10.		int n;
11.		double a;
12.		float x, y;
13.
14.		// nastavuje centrální body čtyř vějířů
15.		coords[0 * (N + 1)] = new Point3f(0.0f, 0.0f, w);
16.		coords[1 * (N + 1)] = new Point3f(0.0f, 0.0f, 0.0f);
17.		coords[2 * (N + 1)] = new Point3f(0.0f, 0.0f, 0.0f);
18.		coords[3 * (N + 1)] = new Point3f(0.0f, 0.0f, -w);
19.
20.		for (a = 0, n = 0; n < N; a = 2.0 * Math.PI / (N - 1) * ++n) {
21.			x = (float) (r * Math.cos(a));
22.			y = (float) (r * Math.sin(a));
23.
24.			coords[0 * (N + 1) + N - n] = new Point3f(x, y, w);
25.			coords[1 * (N + 1) + n + 1] = new Point3f(x, y, w);
26.			coords[2 * (N + 1) + N - n] = new Point3f(x, y, -w);
27.			coords[3 * (N + 1) + n + 1] = new Point3f(x, y, -w);
28.		}
29.
30.		tfa = new TriangleFanArray(totalN, TriangleFanArray.COORDINATES, stripCounts);
31.			
32.											
33.
34.		tfa.setCoordinates(0, coords);
35.
36.		return tfa;
37.	}

Toto bílé jojo je jen začátek. Obrázek 2-16 ukazuje podobný objekt, ale modifikovaný tak že každý vertex obsahuje informaci také o barvě. Pozměněné metoda yoyoGeometry() která přidává barvy do objektu TriangleFanArray je v následující ukázce kódu. Řákdy 23 až 26, 36 až 39 a řádek 46 určují barvu každého vertexu.

Více možností jak definovat vzhled vizuálního objektu je použití světel, textur a vlastností materiálů vizuálního objektu. Tato témata nejsou pokryta v této kapitole. Světla a textury jsou tématy kapitol 6 a 7.

1.	private Geometry yoyoGeometry() {
2.
3.		TriangleFanArray tfa;
4.		int N = 17;
5.		int totalN = 4 * (N + 1);
6.		Point3f coords[] = new Point3f[totalN];
7.		Color3f colors[] = new Color3f[totalN];
8.		Color3f red = new Color3f[totalN];
9.		Color3f yellow = new Color3f(0.7f, 0.5f, 0.0f);
10.		int stripCounts[] = {N + 1, N + 1, N + 1, N + 1};
11.		float r = 0.6f;
12.		float w = 0.4f;
13.		int n;
14.		double a;
15.		float x, y;
16.
17.		// nastaví středy pro naše čtyři vějíře
18.		coords[0 * (N + 1)] = new Point3f(0.0f, 0.0f, w);
19.		coords[1 * (N + 1)] = new Point3f(0.0f, 0.0f. 0.0f);
20.		coords[2 * (N + 1)] = new Point3f(0.0f, 0.0f. 0.0f);
21.		coords[3 * (N + 1)] = new Point3f(0.0f, 0.0f, -w);
22.
23.		colors[0 * (N + 1)] = red;
24.		colors[1 * (N + 1)] = yellow;
25.		colors[2 * (N + 1)] = yellow;
26.		colors[3 * (N + 1)] = red;
27.
28.		for (a = 0, n = 0; n < N; a = 2.0 * Math.PI / (N - 1) * ++n) {
29.			x = (float) (r * Math.cos(a));
30.			y = (float) (r * Math.sin(a));
31.			coords[0 * (N + 1) + n + 1] = new Point3f(x, y, w);
32.			coords[1 * (N + 1) + N - n] = new Point3f(x, y, w);
33. 		coords[2 * (N + 1) + n + 1] = new Point3f(x, y, -w);
34. 		coords[3 * (N + 1) + N - n] = new Point3f(x, y, -w);
35.
36. 		colors[0 * (N + 1) + N - n] = red;
37. 		colors[1 * (N + 1) + n + 1] = yellow;
38. 		colors[2 * (N + 1) + N - n] = yellow;
39. 		colors[3 * (N + 1) + n + 1] = red;
40. 	}
41. 	tfa = new TriangleFanArray (totalN, TriangleFanArray.COORDINATES | TriangleFanArray.COLOR_3,
42.		stripCounts); 
43. 
44.
45. 	tfa.setCoordinates(0, coords);
46. 	tfa.setColors(0, colors);
47.
48. 	return tfa;
49. }

Pozorný čtenář si určitě všimne rozdílů na řádcích 36 až 39. Kód je napsán tak že vystavuje přední stěnu každého trojúhelníku směrem ven z joja. Diskuze o předních a zadních stěnách trojúhelníků a proč je mezi nimi rozdíl je v sekci 2.6.4

img2-16

2.5.4 Podtřídy třídy IndexedGeometryArray

Dříve popsané podtřídy třídy GeometryArray deklarovaly vertexy neefektivně. I podtřídy třídy GeometryStripArray mají však limitovanou znovupoužitelnost vertexů. Mnoho geometrických objektů umožňuje znovupoužití vertexů. Například v definici kostky lze použít osm jejích vertexů pro tři různé čtvercové stěny. V nejhorším případě vyžaduje definice kostky 24 vertexů, i když je zapotřebí jen osm unikátních vertexů (16 z 24 vertexů je redundantních).

Objekty IndexedGeometryArray poskytují o úroveň znovupoužitelnosti více, takže se lze těmto redundatním vertexům vyhnout. Stále je zapotřebí pole informací o vertexech, ale vertexy lze ukládat v libovolném pořadí a znovupoužít lze kterýkoli z nich. Těmto polím obsahujícím souřadnice, barvy a normály povrchu a souřadnice textur říkáme datová pole.

AVšak objekty třídy IndexedGeometryArray potřebují další pole (indexovaná pole) které obsahují indexy datových polí. Existují čtyři indexovaná pole: indexy souřadnic, indexy barev, indexy normál povrchu a indexy souřadnic textur, která korespondují s datovými poli. Počet indexovaných polí ja vždy stejný jako počet datových polí. Počet prvků v každém indexovaném poli je stejný a obvykle větší než počet prvků v každém datovém poli.

Indexovaná pole mohou obsahovat vícenásobné reference na tentýž vertex v datových polích. Hodnoty v těchto indexovaných polích určují pořadí v jakém se přeistupuje k vertexovým datům během renderování. Obrázek 2-17 ukzauje vztahy mezi indexovanýmia datovými poli se souřadnicemi pro kostku.

Je vhodné se na tomto místě zmínit o ceně za znovupoužití vertexů poskytnutých indexovanými poli - tou cenou je výkon. Indexovaná geometrie více zatěžuje preces vykreslování. Pokud je výkon problém, použijte pásy kdykoli je to možné a vyhněte se indexované geometrii. Indexovaná geometrie je užitečná tam kde rychlost není kritickým faktorem a paměť rovněž ne.

img2-17

Konstruktory tříd IndexedGeometryArray, IndexedGeometryStripArray a jejich podtříd jsou podobné konstruktorům tříd GeometryArray a GeometryStripArray. Třídy s indexovanými daty mají parametr navíc který definuje kolik indexů se použije k popisu geometrie (počet prvlů v indexovaných polích).


Konstruktory třídy IndexedGeometryArray a jejích podtříd

Vytváří prázdný objekt s daným počtem vertexů, vertexovým formátem a počtem indexů v poli.

IndexedGeometryArray(int vertexCount, int vertexFormat, int indexCount)

IndexedPointArray(int vertexCount, int vertexFormat, int indexCount)

IndexedLineArray(int vertexCount, int vertexFormat, int indexCount)

IndexedTriangleArray(int vertexCount, int vertexFormat, int indexCount)

IndexedQuadArray(int vertexCount, int vertexFormat, int indexCount)

Konstruktory třídy IndexedGeometryStripArray a jejích podtříd

Vytváří prázdný objekt s daným počtem vertexů, vertexovým formátem, počtem indexů v poli a polem s počtem vertexů na pás.

IndexedGeometryStripArray(int vc, int vf, int ic, int stripVertexCounts[])

IndexedLineStripArray(int vc, int vf, int ic, int stripVertexCounts[])

IndexedTriangleStripArray(int vc, int vf, int ic, int stripVertexCounts[])

IndexedTriangleFanArray(int vc, int vf, int ic, int stripVertexCounts[])


IndexedGeometryArray, IndexedGeometryStripArray a jejich podtřídy dědí svoje metody k načtení datových polí od tříd GeometryArray a GeometryStripArray. Třídy pracující s indexovanými daty přidaly metody k načítání indexů do indexovaných polí.


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

void setCoordianteIndex(int index, int coordinateIndex)

nastavuje index souřadnic tohoto vertexu na specifický index tohoto objektu

void setCoordinateIndices(int index, int[] coordinateIndices)

nastavuje souřadnice indexů těchto vertexů začínající na daném indexu tohoto objektu

void setColorIndex(int index, int colorIndex)

nastavuje barevný index tohoto vertexu na specifický index tohoto objektu

void setColorIndices(int index, int[] colorIndices)

nastavuje barevné indexy těchto vertexů začínající na daném indexu tohoto objektu

void setNormalIndex(int index, int normalIndex)

nastavuje normálový index tohoto vertexu na specifický index tohoto objektu

void setNormalIndices(int index, int[] normalIndices)

nastavuje normálové indexy těchto vertexů začínající na daném indexu tohoto objektu

void setTextureCoordinateIndex(int index, int texCoordIndex)

nastavuje souradnice textur indexy těchto vertexů začínající na daném indexu tohoto objektu