Java 3D pro začátečníky

Úvod

Java 3D je přídavkem ke knihovnám jazyka Java a slouží k zobrazování trojrozměrné grafiky. Programy napsané v Java 3D mohou běžet na mnoha odlišných typech počítačů a přes internet.

Knihovna tříd Java 3D poskytuje rozhraní které je jednodušší než rozhraní mnoha jiných grafických knihoven, ale zároveň je dostačující k tvorbě dobrých her a animací. Java 3D staví na existujících technologiích jako je DirectX a OpenGL takže programy neběží tak pomalu jak bychom mohli čekat. Java 3D také umožňuje začlenit objekty vytvořené 3D modelovacími nástroji jako je TrueSpace nebo dokonce VRML modely.

Tento tutoriál je úvodem do knihovny Java 3D. Příklady vás provedou základními metodami tvorby 3D grafiky a animací. Nemusíte mít žádnou znalost 3D grafiky nebo samotné knihovny Java 3D, ale hodně vám pomůže pokud budete rozumět jazyku Java alespoň na základní úrovni. Programování ve třech rozměrech se může zdát komplikované kvůli množství cizích pojmů a matematiky, ale v tomto tutoriálu se budeme snažit zachovat věci co nejjednoduššími.

Instalace a spuštění Java 3D

Java 3D software je zdarma k dispozici od Sun Microsystems na j3d.java.net. Nejdříve budeme muset nainstalovat verzi Java 3D 1.3.1 a teprve poté aktuální verzi (v době překladu 1.5.0).

Po instalaci Java 3D můžete přeložit vaše programy tímto příkazem:

	javac ClassFileName.java

A spustit je:

	java ClassFileName

ClassFileName by mělo být shodné s názvem třídy definované v tomto souboru.

Začínáme - Náš první program

Následující program obsahuje základní kroky které potřebujeme k zobrazení 3D scény.

  1. Vytvoří virtuální vesmír obsahující naši scénu.
  2. Vytvoří datovou strukturu obsahující skupinu s objekty.
  3. Přidá objekt do skupiny.
  4. Umístí pozorovatele tak aby mohl vidět objekt na scéně.
  5. Přídá skupinu objektu do vesmíru.

Podívejme se na konstruktor třídy Hello3D a můžeme vidět pět řádků které dělají to co jsme si řekli. Program zobrazí kostku, přičemž pozorovatel se dívá přímo na červenou stěnu této kostky takže můžeme vidět červený čtverec na černém pozadí.

import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.Sphere;
import javax.media.j3d.BranchGroup;

public class Hello3D {

	public Hello3D() {
		SimpleUniverse universe = new SimpleUniverse();
		BranchGroup group = new BranchGroup();
		group.addChild(new ColorCube(0.3));
		universe.getViewingPlatform().setNominalViewingTransform();
		universe.addBranchGraph(group);   
	}

	public static void main(String args[]) {    
		new Hello3D();
	}
}

Příkazy import na začátku této třídy importují různé části knihovny Java 3D, takže přeložení a spuštění tohoto programu je dobrým důkazem toho že je vše v pořádku instalováno.

Posviťme si na svět

Dobře, náš první příklad byl dobrým začátkem, ale byl opravdu 3D? Pokud si myslíte že čtverec nepatří do 3D, tak si na to budeme muset v našem vesmíru posvítit. Způsob jakým světlo dopadá na objekty vytváří stíny a to nám pomáhá vidět objekty ve třech rozměrech.

Další příklad ilustruje jak zobrazit kouli osvícenou červeným světlem:

import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class Ball {
	public Ball() {
    		// Vytvoříme vesmír
		SimpleUniverse universe = new SimpleUniverse();

	    	// Vytvoříme strukturu obsahující objekty
		BranchGroup group = new BranchGroup();

	    	// Vytvoříme kouli a přidáme ji do skupiny objektů
		Sphere sphere = new Sphere(0.5f);
    		group.addChild(sphere);

	    	// Vytvoříme červené světlo svítící 100m od počátku
    		Color3f light1Color = new Color3f(1.8f, 0.1f, 0.1f);
    		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);     
		Vector3f light1Direction  = new Vector3f(4.0f, -7.0f, -12.0f);
    		DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
    		light1.setInfluencingBounds(bounds);
    		group.addChild(light1);
    
    		// Nastavíme pohled na kouli
	    	universe.getViewingPlatform().setNominalViewingTransform();

	    	// Vložíme skupinu s objekty do vesmíru
    		universe.addBranchGraph(group);
	}
  	
	public static void main(String args[]) { 
		new Ball(); 
	}
}

Koule kterou jsme vytvořili je bílá (výchozí nastavení), ale vypadá jako červená díky světlu. Protože je to směrové světlo (objekt třídy DirectionalLight), musíme také určit jak daleko bude světlo svítit a v jakém směru. V našem programu světlo svítí na vzdálenost 100 metrů směrem doprava, dolů a do obrazovky, jak je definováno vektorem (4.0 doprava, -7.0 dolů a -12.0 do obrazovky).

Také můžeme vytvořit ambientní světlo (objekt třídy AmbientLight), které vlastně nesvítí žádným směrem, nebo kruhové (lampičkové) světlo (objekt třídy SpotLight) pokud si chceme posvítit jen na určité místo na scéně. Kombinace silného směrového světla a slabšího ambientního osvětlení dává scéně přiřozený vzhled. Světla v Java 3D nevrhají stíny (ale je možné je nastavit).

Rozmísťování objektů

Dosud jsme vytvářeli objekty na jednom stejném místě ve středu vesmíru. V Java 3D lze jednotlivá umístění popsat souřadnicemi x, y a z. Souřadnice se zvětšují směrem doprava na ose x, směrem nahoru na ose y a směrem do obrazovky na ose z.

Tomuto se říká pravoruký systém souřadnic protože můžeme použít palec a dva první prsty pravé ruky jako jednotlivé osy souřadnic. Všechny vzdálenosti jsou měřeny v metrech.

Při rozmísťování objektů na scéně začínáme v bodě (0, 0, 0) a poté je můžeme posouvat kam chceme. Pohybování objekty se říká transformace, takže třídy které budeme používat se jmenují TransformGroup a Transform3D. Objekty na scéně a objekty Transform3D přidáváme do TransformGroup předtím než přidáme samotný objekt TransformGroup na scénu.

  1. Vytvoříme transformaci, skupinu transformací a objekt:
  2. 	Transform t = new Transform3D();
    	TransformGroup tg = new TransformGroup();
    	Cone c = new Cone(0.5f, 0.5f);
    
  3. Určíme polohu objektu:
  4. 	Vector3f v = new Vector3f(-2.f, 1.f, -4.f);
    
  5. Nastavíme transformaci aby posunula objekt na dané místo:
  6. 	t.setTranslation(v);
    
  7. Přidáme transformaci do skupiny transformací:
  8. 	tg.setTransform(t);
    
  9. Přidáme objekt do skupiny transformací:
  10. 	tg.addChild(c);
    

Může to vypadat komplikovaně, ale skupina transformací nám umožní seskupit objekty a pracovat s nimi jako s jedním velkým objektem. Například bychom mohli vytvořit stůl ze čtyř válců sloužících jako nohy a hranolu jako deska stolu. Když vložíme všechny tyto části do jedné skupiny transformací, můžeme posouvat celým stolem.

Třída Transform3D však zvládne mnohem víc než jen umístění objektu na dané souřadnice. Její metody včetně setScale() umožňující změnu velikosti objektu a rotX(), rotY() a rotZ() sloužící pro rotaci kolem os (proti směru hodinových ručiček).

Následující příklad zobrazuje na každé ose jiný objekt.

import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class Position {

	public Position() {
    		SimpleUniverse universe = new SimpleUniverse();
    		BranchGroup group = new BranchGroup();
		// Osa x vyrobená z koulí
    		for (float x = -1.0f; x <= 1.0f; x = x + 0.1f) {
		        Sphere sphere = new Sphere(0.05f);
		        TransformGroup tg = new TransformGroup();
		        Transform3D transform = new Transform3D();
		        Vector3f vector = new Vector3f( x, .0f, .0f);
			transform.setTranslation(vector);
		        tg.setTransform(transform);
		        tg.addChild(sphere);
		        group.addChild(tg);
		}    
    		// Osa Y vyrobená z kuželů
		for (float y = -1.0f; y <= 1.0f; y = y + 0.1f) {
	        	TransformGroup tg = new TransformGroup();
		        Transform3D transform = new Transform3D();
		        Cone cone = new Cone(0.05f, 0.1f);
		        Vector3f vector = new Vector3f(.0f, y, .0f);
		        transform.setTranslation(vector);
        		tg.setTransform(transform);
		        tg.addChild(cone);
		        group.addChild(tg);
		}      
    		// Osa Z vyrobená z válců
		for (float z = -1.0f; z <= 1.0f; z = z+ 0.1f) {        
		        TransformGroup tg = new TransformGroup();
		        Transform3D transform = new Transform3D();
		        Cylinder cylinder = new Cylinder(0.05f, 0.1f);
		        Vector3f vector = new Vector3f(.0f, .0f, z);
		        transform.setTranslation(vector);
		        tg.setTransform(transform);
		        tg.addChild(cylinder);
		        group.addChild(tg);
		} 
     
	    	Color3f light1Color = new Color3f(.1f, 1.4f, .1f);
   		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
    		Vector3f light1Direction  = new Vector3f(4.0f, -7.0f, -12.0f);
    		DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
    		light1.setInfluencingBounds(bounds);
    		group.addChild(light1);
    		universe.getViewingPlatform().setNominalViewingTransform();

	    	// Vložíme skupinu transformací do vesmíru
    		universe.addBranchGraph(group);
	}

	public static void main(String args[]) {
		new Position();
	}
}

Vzhled znamená vše

Existuje mnoho způsobů jak změnit vzhled objektů na scéně. Můžeme změnit jejich barvu, kolik světla odrážejí, můžeme na ně aplikovat dvojrozměrné obrázky nebo aplikovat textury na jejich povrch. Třída Appearance obsahuje metody které umožňují dělat takové změny. V této části si ukážeme jak tyto metody použít.

Nejjednodušším způsobem nastavení vzhledu je určit barvu objektu a metodu stínování. To funguje pro jednoduše, ale aby objekt vypadal realističtěji, musíme určit jak se bude chovat na světle. To uděláme vytvořením materiálu.

  1. Vytvoříme objekt:
  2. 	Sphere s = new Sphere();
    
  3. Vytvoříme vzhled:
  4. 	Appearance a = new Appearance();
    
  5. vytvoříme barvu:
  6. 	Color3f c = new Color3f(0.f, 0.f, 1.f);
    
  7. Určíme metodu obarvení:
  8. 	ColoringAttributes ca = new ColoringAttributes(c, ColoringAttributes.NICEST);
    
  9. Přidáme atributy ke vzhledu:
  10. 	a.setColoringAttributes(ca);
    
  11. Nastavíme vzhled objektu:
  12. 	s.setAppearance(a);
    

Materiály

Materiály mají pět vlastností kterými můžeme definovat vzhled objektu. Čtyři z nich jsou barvy: ambientní, emisivní, difuzní a barva odlesku. Pátou vlastností je lesk.

Změna faktoru lesku ovlivní nejen lesk objektu, ale i velikost plochy odlesku.

Pro většinu objektů můžeme použít jednu barvu jak pro ambientní tak i difuzní složku a černou barvu pro emisivní složku (většina věcí ve tmě nesvítí). Pokud je to lesklý objekt, mohli bychom použít světlejší barvu pro odlesk. Například defince materiálu pro biliárovou kouli by mohla vypadat takto:

// biliárová koule
//                             amb  emi    dif  odl    zář
// Material mat = new Material(red, black, red, white, 70f);

Pro hopskuli bychom mohli použít černé nebo červené světlo k odrazu což by snížilo lesk koule. Snížení lesku ze 70 na 0 by nemuselo fungovat způsobem jaký bychom očekávali, jen by se rozšířila plocha odrazu po celém objektu místo toho aby se koncentrovala jen na jedno místo.

Textury

Materiály způsobí změnu celého objektu, ale občas i ten nejzářivější objekt může vypadat divně. Přidáním textury můžeme vyrobit zajímavější efekty jako třeba mramor nebo obalit celý objekt do dvourozměrného obrázku.

Třída TexturLoader nám umožnuje použít obrázek jako texturu. Rozměry obrázku musí být mocninami čísla 2, například 128 na 256 pixelů. Když načítáme texturu, můžeme také určit jak chceme obrázek použít. Například RGB načte obrázek barevně, zatímco LUMINANCE ho zobrazí černobíle.

Po načtení textury můžeme změnit vlastnosti objektu třídy TextureAttributes a říci zda chceme objekt nahradit tímto obrázkem nebo zda jej budeme modulovat barvou. Můžeme jej také aplikovat jako otisk nebo jej prolnout s jakoukoli barvou.

Pokud použijeme jednoduchý objekt jako je koule pak musíme také umožnit texturování nastavením "primitvních konstant". Ty můžeme nastavit jako Primitive.GENERATE_NORMALS + Primitive.GENERATE_TEXTURE_COORDS při vytváření objektu.

Teď to asi začíná znít trochu komplikovaně, takže si uvedeme příklad. Můžeme experimentovat s nastaveními v tomto příkladu a pak porovnávat výsledky. Obrázek použitý v příkladu lze nahradit svým vlastním:

import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.Container;

public class TexturedBall {

	public TexturedBall() {

    		// Vytvoříme vesmír
		SimpleUniverse universe = new SimpleUniverse();

    		// Vytvoříme "galaxii"
    		BranchGroup group = new BranchGroup();

    		// Nastavíme barvy
    		Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
    		Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
    		Color3f red = new Color3f(0.7f, .15f, .15f);
    
    		// Nastavíme mapování textury
    		TextureLoader loader = new TextureLoader("your_picture.jpg",                
                              "LUMINANCE", new Container());
    		Texture texture = loader.getTexture();
    		texture.setBoundaryModeS(Texture.WRAP);
    		texture.setBoundaryModeT(Texture.WRAP);
		texture.setBoundaryColor(new Color4f(0.0f, 1.0f, 0.0f, 0.0f));
	
    		// Nastavíme atributy textury 
    		// Může být REPLACE, BLEND nebo DECAL místo MODULATE
    		TextureAttributes texAttr = new TextureAttributes();
    		texAttr.setTextureMode(TextureAttributes.MODULATE);
    		Appearance ap = new Appearance();
    		ap.setTexture(texture);
    		ap.setTextureAttributes(texAttr);
 	
    		// Nastavíme materiál
    		ap.setMaterial(new Material(red, black, red, black, 1.0f));
	                  
    		// Vytvoříme kouli na které demonstrujeme textury
    		int primflags = Primitive.GENERATE_NORMALS +                     
                    		Primitive.GENERATE_TEXTURE_COORDS; 
    		Sphere sphere = new Sphere(0.5f, primflags, ap);
    		group.addChild(sphere);

    		// Vytvoříme světla
    		Color3f light1Color = new Color3f(1f, 1f, 1f);
    		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

    		Vector3f light1Direction  = new Vector3f(4.0f, -7.0f, -12.0f);
    		DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
    		light1.setInfluencingBounds(bounds);
    		group.addChild(light1);
    
    		AmbientLight ambientLight = new AmbientLight(new Color3f(.5f,.5f,.5f));
    		ambientLight.setInfluencingBounds(bounds);
    		group.addChild(ambientLight); 
    
    		// Pozorovatele umístíme přímo naproti kouli
    		universe.getViewingPlatform().setNominalViewingTransform();

    		// Vložíme skupinu objektů do vesmíru
    		universe.addBranchGraph(group);
	}

	public static void main(String args[]) {
    		new TexturedBall();
	}
}

Můžeme také použít trojrozměrné textury použitím tvarů místo obrázků.

Speciální efekty

Inspiraci můžeme najít v příkladu který je v distribuci Java 3D a jmenuje se AppearanceTest. Například můžeme zobrazit objekty jako jako drátěné modely, zobrazit pouze rohy objektu atd. Také můžeme objekt i zprůhlednit pomocí následujících nastavení:

	TransparencyAttributes t_attr = new TransparencyAttributes(TransparencyAttributes.BLENDED,0.5,
    					TransparencyAttributes.BLEND_SRC_ALPHA,
    					TransparencyAttributes.BLEND_ONE);
	ap.setTransparencyAttributes(t_attr);

Java 3D a uživatelské rozhraní

Většina skutečných aplikací používá směsici troj a dvojrozměrných prvků. Tato sekce popisuje jak zkombinovat Java 3D se zbytkem našeho programu.

Canvas3D

Každá oblast kde lze vykreslovat torjrozměrnou grafiku se nazývá Canvas3D. To je vlastně obdélníkový pohled na objekty v našem vesmíru. Plátno se vloží do rámu, a pak se vytvoří vesmír který se zobrazí na plátně.

Následující příklad ukazuje jak vytvořit plátno v rámu s popisky nahoře a dole. Program můžeme spustit buď jako applet nebo aplikaci:

import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.ColorCube;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import java.awt.GraphicsConfiguration;
import java.awt.BorderLayout;
import java.awt.Label;
import java.applet.Applet;
import com.sun.j3d.utils.applet.MainFrame;
public class CanvasDemo extends Applet {

	public CanvasDemo()  { 
        
        	setLayout(new BorderLayout());
        	GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
	        Canvas3D canvas = new Canvas3D(config);  
        	add("North",new Label("This is the top"));
        	add("Center", canvas);
        	add("South",new Label("This is the bottom"));
        	BranchGroup contents = new BranchGroup();
        	contents.addChild(new ColorCube(0.3));
        	SimpleUniverse universe = new SimpleUniverse(canvas);
        	universe.getViewingPlatform().setNominalViewingTransform();
        	universe.addBranchGraph(contents);   
    	}

    	public static void main(String args[]) {    
        	CanvasDemo demo = new CanvasDemo(); 
        	new MainFrame(demo,400,400);
    	}    
}

Java 3D a Swing

Canvas3D využívá výhod naší grafické karty ke zvýšení výkonu. Naneštěstí to znamená že to nefunguje příliš dobře se Swing GUI (situace se mohla změnit protože došlo k vývoji Swingu a zejména zlepšení výkonu grafického potrubí). Tyto komponenty se nazývají "odlehčené". Odlehčené komponenty mohou být skryty Canvas3D i když by měly být viditelné.

Pro tento problém existuje několik řešení:

Animace a interakce - odrážející se kulička

K vytvoření animace potřebujeme pohybovat objekty mezi každým snímkem animace. Můžeme použít časovač a pohybovat 3D objekty v malých časových rozmezích. Také můžeme objekty upravovat jinými způsoby, další příklad mění velikost kuličky takže se deformuje při dopadu.

Pro interakci s uživatelem můžeme zpracovávat stisky kláves na tlačítcích a jiných komponentách.

Jedna věc které bychom si měli všimnout je že musíme Java 3D oznámit že budeme něčím hýbat pomocí nastavení schopnosti. Jinak ničím nepohneme.

	objTrans = new TransformGroup();
	objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

Následující příklad tyto techniky kombinuje. Začínáme kliknutím na tlačítko, pak kulička začne skákat nahoru a dolů a můžeme stisknout klávesu a nebo s abychom usměrnili pohyb kuličky doleva nebo doprava.

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.WindowAdapter;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.geometry.Sphere;
import javax.swing.Timer;

public class BouncingBall extends Applet implements ActionListener, KeyListener { 
	private Button go = new Button("Go");
    	private TransformGroup objTrans;
    	private Transform3D trans = new Transform3D();
    	private float height = 0.0f; 
    	private float sign = 1.0f;
    	private Timer timer;
    	private float xloc = 0.0f;
    
	public BranchGroup createSceneGraph() {
		// Vytvoříme kořen grafu větve
		BranchGroup objRoot = new BranchGroup();
		objTrans = new TransformGroup();
		objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		objRoot.addChild(objTrans);

		// Vytvoříme graf listu a vložíme ho do grafu větve
    		Sphere sphere = new Sphere(0.25f);
    		objTrans = new TransformGroup();
    		objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
    		Transform3D pos1 = new Transform3D();    
    		pos1.setTranslation(new Vector3f(0.0f,0.0f,0.0f));
    		objTrans.setTransform(pos1);
    		objTrans.addChild(sphere);
    		objRoot.addChild(objTrans);
        	BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
		Color3f light1Color = new Color3f(1.0f, 0.0f, 0.2f);
    		Vector3f light1Direction  = new Vector3f(4.0f, -7.0f, -12.0f);
    		DirectionalLight light1 = new DirectionalLight(light1Color, light1Direction);
    		light1.setInfluencingBounds(bounds);
    		objRoot.addChild(light1);

     		// Nastavíme ambientní světlo
    		Color3f ambientColor = new Color3f(1.0f, 1.0f, 1.0f);
    		AmbientLight ambientLightNode = new AmbientLight(ambientColor);
    		ambientLightNode.setInfluencingBounds(bounds);
    		objRoot.addChild(ambientLightNode);
		return objRoot;
	}

    	public BouncingBall() {
		setLayout(new BorderLayout());
        	GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
        	Canvas3D c = new Canvas3D(config);
	    	add("Center", c);
        	c.addKeyListener(this);
        	timer = new Timer(100, this);
	    	Panel p = new Panel();
	    	p.add(go);
	    	add("North", p);
	    	go.addActionListener(this);
	    	go.addKeyListener(this);
	    	// Vytvoříme jednoduchou scénu a vložíme ji do vesmíru
	    	BranchGroup scene = createSceneGraph();
	    
	    	SimpleUniverse u = new SimpleUniverse(c);
        	u.getViewingPlatform().setNominalViewingTransform();
	    	u.addBranchGraph(scene);
	}
    

	public void keyPressed(KeyEvent e) {     
        	if (e.getKeyChar() == 's') {
			xloc = xloc + .1f;
		}
        	if (e.getKeyChar()== 'a') {
			xloc = xloc - .1f;
		}
	}

    	public void keyReleased(KeyEvent e) {
	}
    
	public void keyTyped(KeyEvent e){
	}
    
	public void actionPerformed(ActionEvent e ) {
        	// Spustíme časovač
	    	if (e.getSource() == go) {
	        	if (!timer.isRunning()) {
	            	timer.start();
            		}
        	} else {
	        	height += .1 * sign;
        		if (Math.abs(height *2)  >= 1) 
				sign = -1.0f * sign;
        			if (height<-0.4f) {
            				trans.setScale(new Vector3d(1.0, .8, 1.0));
        			} else {
            				trans.setScale(new Vector3d(1.0, 1.0, 1.0));
        		}
        		trans.setTranslation(new Vector3f(xloc,height,0.0f));
	        	objTrans.setTransform(trans);
	    	}
	}
    
	public static void main(String args[]) {
        	System.out.println("Program Started");
        	BouncingBall bb = new BouncingBall();
        	bb.addKeyListener(bb);
	    	MainFrame mf = new MainFrame(bb, 256, 256);	
    	}
}

Přirozený výběr

Poté co jednou vytvoříme 3D scénu přirozeně chceme interagovat s objekty na scéně. Prvním krokem je výběr objektu pomocí myši. Třídy Java 3D určené k výběru nám k tomu pomohou následujícím způsobem:

  1. Vytvoříme objekt PickCanvas z Canvas3D a BranchGroup ze které chceme vybírat.
  2. 	PickCanvas pickCanvas = new PickCanvas(canvas, group);
    
  3. Nastavíme pickCanvas aby používal ohraničení objektu k výběru.
  4. 	pickCanvas.setMode(PickCanvas.BOUNDS);
    
  5. Obsloužíme událost myši rozšířením MouseAdapter a budeme naslouchat událostem myši z Canvas3D použitím canvas.addMouseListener(this)
  6. Definujeme metodu PickCanvas bude volat metodu PickClosest aby navrátila PickResult
  7. Zavoláme metodu getNode objektu PickResult abychom se dozvěděli o objektu který byl vybrán více.

Zde je kompletní příklad který zobrazuje dva objekty (krychli a kouli). Když kliknete myší na jeden z objektů program vytiskne jméno třídy vybraného objektu.

import com.sun.j3d.utils.picking.*;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.event.*;
import java.awt.*;

public class Pick extends MouseAdapter {
	private PickCanvas pickCanvas;

	public Pick() {
		Frame frame = new Frame("Box and Sphere");
		GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
		Canvas3D canvas = new Canvas3D(config);
		canvas.setSize(400, 400);
		SimpleUniverse universe = new SimpleUniverse(canvas);
		BranchGroup group = new BranchGroup();

		// Vytvoříme barevnou kostku
		Vector3f vector = new Vector3f(-0.3f, 0.0f, 0.0f);
		Transform3D transform = new Transform3D();
		transform.setTranslation(vector);
		TransformGroup transformGroup = new TransformGroup(transform);
		ColorCube cube = new ColorCube(0.3);
		transformGroup.addChild(cube);
		group.addChild(transformGroup);

		//create a sphere
		Vector3f vector2 = new Vector3f(+0.3f, 0.0f, 0.0f);
		Transform3D transform2 = new Transform3D();
		transform2.setTranslation(vector2);
		TransformGroup transformGroup2 = new TransformGroup(transform2);
		Appearance appearance = new Appearance();
		appearance.setPolygonAttributes(
			new PolygonAttributes(PolygonAttributes.POLYGON_LINE,
			PolygonAttributes.CULL_BACK, 0.0f));
		Sphere sphere = new Sphere(0.3f, appearance);
		transformGroup2.addChild(sphere);
		group.addChild(transformGroup2);
		universe.getViewingPlatform().setNominalViewingTransform();
		universe.addBranchGraph(group);
		frame.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent winEvent) {
				System.exit(0);

			}
		});
		frame.add(canvas);
		pickCanvas = new PickCanvas(canvas, group);
		pickCanvas.setMode(PickCanvas.BOUNDS);
		canvas.addMouseListener(this);
		frame.pack();
		frame.show();
	}

	public static void main(String args[]) {
		new Pick();
	}

	public void mouseClicked(MouseEvent e) {
		pickCanvas.setShapeLocation(e);
		PickResult result = pickCanvas.pickClosest();
		if (result == null) {
			System.out.println("Nothing picked");
		} else {
			Primitive p = (Primitive)result.getNode(PickResult.PRIMITIVE);
			Shape3D s = (Shape3D)result.getNode(PickResult.SHAPE3D);
			if (p != null) {
				System.out.println(p.getClass().getName());
			} else if (s != null) {
				System.out.println(s.getClass().getName());
			} else {
				System.out.println("null");
			}
		}

	}

}

Více informací

Tento tutoriál byl přeložen ze stránek java3d.org patřící Gregu Hopkinsovi. Stránky autora tohoto překladu jsou na dredwerkz.