Java3D Anleitung

Java3D_WuerfelDiese Anleitung bietet einen Einstieg in die 3D Programierung mit Hilfe von Java3D.
Links sehen sie einen Screenshot des fertigen Programms aus der Anleitung.

Inhalt

1. Installation und Integration in Eclipse
2. Anleitung zum Schreiben eines Java 3D Programmes
3. Grundgeometrie in Java3D
4. Code Beispiele
5. Quellen und Links

1. Installation und Integration in Eclipse

  • Java3D 1.5.1 herunterladen
    http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-client-419417.html
  • Nach der Installation von Java3D sollte es folgendes Verzeichnis geben: C:ProgrammeJavaJava3D…
  • Eclipse starten und ein Java-Projekt erstellen
  • Wenn die JARs nicht automatisch gefunden werden, muss man unter „Build Path -> Add External JAR“ die JARs hinzufügen, die im Java3D/1.5.1/lib/ext/…-Unterverzeichnis liegen. (Das ist eigentlich schlecht, weil man sich damit eine Abhängigkeit zu einem fest vorgegebenen Dateipfad einhandelt, aber sollte erstmal kompilierbar sein.)
  • Beim Ausführen müssen die Java3D-DLLs dem Path zugefügt werden, weil es sonst beim Start zu folgender Exception kommt (wenn es von Eclipse nicht automatisch gemacht wird):

Es gibt zwei Möglichkeiten, dieses Problem zu lösen:
=> A) Empfohlen: In der „Run Configuration“ des Eclipse-Projekts auf dem Karteireiter „Environment“ klicken. So wird eine neue Environment Variable „PATH“ hinzugefügt, die auf das “ Java3D/1.5.1/bin“-Verzeichnis der Java3D-Implementation zeigt.
=> B) Alternativ: In Eclipse links bei „Referenced Libraries“ die Java3D-Jar rechtsklicken und dort dann bei „Properties“ die „Native Library Location“ festlegen, auf genau den „Java3D/1.5.1/bin“ Ordner, wo die *.dll Dateien liegen

2. Anleitung zum Schreiben eines Java 3D Programms

Szenengraph

2.1. Grundlegende Objekte im Szenengraph-Modell

„VirtualUniverse“: Wurzelknoten des Szenengraphen;
„Locale“: bildet für den darunter strukturierten Teilbaum immer einen Ursprung
(Wurzelknoten); gibt räumlich zusammengehörige Bereiche des Universums an; wenn Geometrie mit ausreichender Genauigkeit über mehrere Größenordnungen definiert werden soll: mehrere „Locales“; enthält über „BranchGroups“ mehrere Subgraphen
„Group“: Vorfahren aller Zwischenknoten im Graphen; dient als Basisklasse für weitere
Subklassen
„BranchGroup“: Subgraph; bestehend aus inneren „Group“-Knoten und „Leaf“-Knoten
„TransformGroup“: enthält Transformation, die auf alle seine Nachfolger angewendet wird
„Shape3D“: Blattknoten; definiert ein Geometrieobjekt in der Szene
„NodeComponent“: legt mit Subklassen „Appearance“ und „Geometry“ Attribute zur Darstellung des entsprechenden Objektes fest
„View“: koordinierende Aufgabe
„PhysicalBody“: definiert relevante physikalische Eigenschaften des realen Betrachters
„PhysicalEnvironment“: definiert die vorhandenen Sensoren, d.h. die 3D-Eingabegeräte
„Canvas3D“: dient zur Ausgabe auf einem Anzeigegerät; physikalische Größen wie etwa Breite und Höhe werden in Screen3D abgelegt

2.2. Eigentliches „Rezept“
  1. Erzeuge ein Canvas3D Objekt
  2. Erzeuge ein VirtualUniverse Objekt
  3. Erzeuge ein Locale Objekt und verbinde es mit dem VirtualUniverse Objekt
  4. Konstruiere den View Ast
    1. Erzeuge ein View Objekt
    2. Erzeuge ein ViewPlatform Objekt
    3. Erzeuge ein Physical Body Objekt
    4. Erzeuge ein PhysicalEnvironment Objekt
    5. Verbinde die Objekte ViewPlatform, PhysicalBody, PhysicalEnvironment und Canvas3D mit dem View Objekt
  5. Konstruiere den/die Content Ast/Äste
  6. Kompiliere die Äste
  7. Hänge die Äste an das Locale Objekt

2.3 Vereinfachtes Rezept

  1. Erzeuge ein Canvas3D Objekt
  2. Erzeuge ein SimpleUniverse Objekt und übergebe das Canvas3D Objekt
  3. justiere die ViewPlatform des SimpleUniverse Objekts
  4. Konstruiere den Content Ast
  5. Kompiliere den Content Ast
  6. Füge den Content Ast in die Locale des SimpleUniverse Objekts ein

3. Grundgeometrie in Java3D

3.1. Verschieben + Rotieren von 3D Objekten in Java

[java]
/* 1. Würfel */
ColorCube colorcube1 = new ColorCube();
// Neue Transform Informationen
Transform3D transform3d = new Transform3D();
// Rotation um Y- Achse
transform3d.rotY (Math.toRadians(30));
// Verschiebung um Vector
transform3d.setTranslation(new Vector3f(2,2,2));
// Neue Transformgruppe
TransformGroup transcube1 = new TransformGroup(transform3d);
// Colorcube an Transformgruppe hängen
transcube1.addChild(colorcube1);

/* 2. Würfel */
ColorCube colorcube2 = new ColorCube();
// Neue Transform Informationen
transform3d = new Transform3D();
transform3d.rotX (Math.toRadians(30));
// Rotation um X- Achse
transform3d.rotZ (Math.toRadians(15));
// Rotation um Z- Achse
// Neue Transformgruppe
TransformGroup transcube2 = new TransformGroup(transform3d);
// Colorcube an Transformgruppe hängen
transcube2.addChild(colorcube2);

/* Neue Transform Informationen */
Transform3D transform3d = new Transform3D();
// Neue Transformgruppe
TransformGroup transroot = new TransformGroup(transform3d);
// Transcubes an Transformgruppe hängen
transroot.addChild(transcube1);
transroot.addChild(transcube2);
[/java]

3.2. Betrachten mit Hilfe der Maus

[java]
/* Bounds, innerhalb derer das Behaviour gelten soll */
BoundingBox boundBox = new BoundingBox(new Point3d(-10, -10, -10), new Point3d(10, 10, 10));

/* Muss gesetzt werden, um das Betrachten mit der Maus zu erlauben */
transformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
transformgroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

/* Rotieren mit der linken Maustaste */
MouseRotate behavior = new MouseRotate(transformgroup);
behaviour.setSchedulingBounds(boundBox);
transformgroup.addChild(behavior);

/* Zoomen mit der mittleren Maustaste */
MouseZoom mouseBeh2 = new MouseZoom(transformgroup);
mouseBeh2.setSchedulingBounds(boundBox);
transformgroup.addChild(mouseBeh2);

/* Verschieben mit der rechten Maustaste */
MouseTranslate mouseBeh3 = new MouseTranslate(transformgroup);
mouseBeh3.setSchedulingBounds(boundBox);
transformgroup.addChild(mouseBeh3);
[/java]

3.3. Licht, Lichtquellen und Beleuchtung in Java3D

[java]
AmbientLight lightA = new AmbientLight();
lightA.setInfluencingBounds(new BoundingSphere());
branchgroup.addChild(lightA);

DirectionalLight lightD1 = new DirectionalLight();
lightD1.setInfluencingBounds(new BoundingSphere());
branchgroup.addChild(lightD1);
// Licht funktioniert nur, wenn das Material der Geometrien spezifiziert ist.
// Es wird immer an die Branchgroup gehängt.
[/java]

3.4. Manipulieren von Objekten mit der Maus in Java3D

[java]
/* Die folgende Funktion macht eine Transformgruppe bereit, um manipuliert zu werden */
TransformGroup transformGroup = new TransformGroup();
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
// Behaviours definieren
// Bounds, innerhalb deren man sich befinden muss
BoundingSphere behaveBounds = new BoundingSphere();
// Rotieren mit rechts
PickRotateBehavior pickr = new PickRotateBehavior(branch, canvas3d, behaveBounds);
branch.addChild(pickr);
// Verschieben mit links
PickTranslateBehavior pickt = new PickTranslateBehavior(branch, canvas3d, behaveBounds);
branch.addChild(pickt);
// Zoom mit beiden
PickZoomBehavior pickz = new PickZoomBehavior(branch,canvas3d, behaveBounds);
branch.addChild(pickz);
[/java]

3.5. Steuerung / Manipulieren von Objekten mit der Tastatur in Java3D

[java]
// Die folgende Funktion macht eine Transformgruppe bereit manipuliert zu werden
TransformGroup transformGroup = new TransformGroup();
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
// TransformGruppe wird dem branch hinzugefügt
branchGroup.addChild(transformGroup);
// Tastatur Navigator muss erstellt werden und bekommt die View Platform übergeben
KeyNavigatorBehavior keyBehavior = new KeyNavigatorBehavior(universe.getViewingPlatform().getViewPlatformTransform());
keyBehavior.setSchedulingBounds(new BoundingSphere(new Point3d(), Float.MAX_VALUE));
// Der Tastatur Navigator wird auch der Branch hinzugefügt
branchGroup.addChild(keyBehavior);
[/java]

keys

4. Code-Beispiele

4.1. Grundgerüst

[java]
import java.awt.Frame;
import javax.media.j3d.BranchGroup;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class Welt extends Frame {
public Welt(String title) {
super(title);

// SimpleUniverse vereinfacht das Erstellen des Universums
SimpleUniverse universe = new SimpleUniverse();

BranchGroup group = new BranchGroup();

// Color Cube ist das rote Rechteck, das der Branch Group hinzugefügt wird
group.addChild(new ColorCube(0.3));

// ViewPlatform wird so eingestellt,
// dass man Objekt betrachten kann
universe.getViewingPlatform().setNominalViewingTransform();

// Branch Group wird dem Universum hinzugfügt
universe.addBranchGraph(group);
}
public static void main(String args[]) {
new Welt(„Grundgerüst“);
}
}
[/java]

4.2 Schriftzug ‚Hello World !‘ im Java 3D Universum

[java]
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.universe.SimpleUniverse;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.Text2D;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;

public class HelloWorld extends Applet {
public HelloWorld() {
setLayout(new BorderLayout());
GraphicsConfiguration graphConfig = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas3D = new Canvas3D(graphConfig);
add(„Center“, canvas3D);

// SimpleUniverse vereinfacht das Erstellen des Universums
SimpleUniverse simpleUni = new SimpleUniverse(canvas3D);

BranchGroup sceneGraph = createSceneGraph();

// ViewPlatform wird so eingestellt, dass man Objekt betrachten kann
simpleUni.getViewingPlatform().setNominalViewingTransform();
simpleUni.addBranchGraph(sceneGraph);
}

// Erzeugt den Content-Branch des Szenengraphen
public BranchGroup createSceneGraph() {
BranchGroup objRoot = new BranchGroup();

// Hängt ein Demo-3D Objekt nämlich den Schriftzug ‚Hello World !‘
// (Farbe weiss, Schrift Helvetica, Groesse 18, Normalschrift) an den Ast
objRoot.addChild( new Text2D(„Hello World!“,new Color3f(1f, 1f, 1f),“Helvetica“,18,0));

// Nimmt Optimierungen am Ast des Szenengraphen vor
objRoot.compile();
return objRoot;
}

// Um Programm sowohl als Applet wie auch als Applikation laufen zu lassen
public static void main(String[] args) {
// Erzeugt Applikationsfenster der Größe 800×600
MainFrame mainFrame = new MainFrame(new HelloWorld(),800,600);
}
}
[/java]

4.3. Bunter drehender Würfel

Dieses Programm enthält zwei nebeneinander (auf der x-Achse) liegenden Würfel.
Der rechte Würfel lässt sich mit der Maus manipulieren und der linke rotiert die ganze Zeit. Ebenso kann ich das ganze Universum mit der Tastatur manipulieren.

[java]
import static java.awt.BorderLayout.CENTER;
import java.awt.Container;
import java.awt.GraphicsConfiguration;
import java.awt.GridLayout;
import javax.media.j3d.Alpha;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.RotationInterpolator;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.swing.JFrame;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import com.sun.j3d.utils.behaviors.keyboard.KeyNavigatorBehavior;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.pickfast.behaviors.PickRotateBehavior;
import com.sun.j3d.utils.pickfast.behaviors.PickTranslateBehavior;
import com.sun.j3d.utils.pickfast.behaviors.PickZoomBehavior;
import com.sun.j3d.utils.universe.SimpleUniverse;

public class Wuerfel extends JFrame {
/**
* Konstruktor, der das {@link SimpleUniverse} erstellt und ein
* {@link Canvas3D} hinzufügt. Es werden alle Szenen Grafen dem
* Universum hinzugefügt.
*
* @param title
* Überschrift des Frames
*/
public Welt(String title) {
super(title);
GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
Canvas3D canvas = new Canvas3D(config);
Container cp = this.getContentPane();
cp.setLayout(new GridLayout());
cp.add(canvas, CENTER);
SimpleUniverse universe = new SimpleUniverse(canvas);

// ViewPlatform wird so eingestellt, dass man Objekt betrachten kann
universe.getViewingPlatform().setNominalViewingTransform();

// branch Gruppen werden erzeugt
BranchGroup roteteCubeGroup=createSceneGraphRotateCube(canvas);
BranchGroup mouseManipulationGroup = createSceneGraphManipulationWithMouse();
BranchGroup keyManipulationGroup = createSceneGraph(universe);

// Branch Gruppen werdem dem universum hinzugfügt
universe.addBranchGraph(roteteCubeGroup);
universe.addBranchGraph(mouseManipulationGroup);
universe.addBranchGraph(keyManipulationGroup);

// Konfiguriert das JFrame
this.setSize(1000, 1000);
this.setTitle(„Hello Universe“);
this.setVisible(true);
}

/**
* Erzeugt einen KeyNavigator, dass sich das ganze Universum mit der
* Tastatur steuern lässt.
*
* @return {@link BranchGroup}
*/
public BranchGroup createSceneGraph(SimpleUniverse universe) {
BranchGroup objRoot = new BranchGroup();
// Transformgruppe werden zum Manipulieren gesetzt
TransformGroup transformGroup = new TransformGroup();
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
transformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

// TransformGruppe wird dem Branch hinzugefügt
objRoot.addChild(transformGroup);

// Tastatur Navigator muss erstellt werden und bekommt die View Platform übergeben
KeyNavigatorBehavior keyBehavior = new KeyNavigatorBehavior(universe.getViewingPlatform().getViewPlatformTransform());
keyBehavior.setSchedulingBounds(new BoundingSphere(new Point3d(), Float.MAX_VALUE));

// key Navigator wird dem branch hinzugefügt
objRoot.addChild(keyBehavior);
objRoot.compile();
return objRoot;
}

/**
* Erzeugt einen Scenen Graph, sodass der Würfel mit der Maus manipuliert werden kann
*
* @param canvas
* @return {@link BranchGroup}
*/
public BranchGroup createSceneGraphRotateCube(Canvas3D canvas) {
BranchGroup objRoot = new BranchGroup();

// Transformgruppe werden zum Manipulieren gesetzt
TransformGroup objRotate = new TransformGroup();
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
objRotate.setCapability(TransformGroup.ENABLE_PICK_REPORTING);

// Beschreibt eine Bewegung
Transform3D transform = new Transform3D();

// Erstellt den Würfel
ColorCube cube = new ColorCube(0.2);

// Setzt den Würfel an eine bestimmte Position, wird nur
//auf der x-Achse verschoben
Vector3f vector = new Vector3f(0.5f, .0f, .0f);

// Der bewegung wird ein vektor hinzugefügt
transform.setTranslation(vector);

// Die bewegung wird der Transform Gruppe hinzugefügt
objRotate.setTransform(transform);

// Würfel wird der Transform Gruppe hinzugefügt
objRotate.addChild(cube);

// die transform gruppe wird dem branch hinzugefügt
objRoot.addChild(objRotate);

// Bounds inerhalb deren man sich befinden muss
BoundingSphere behaveBounds = new BoundingSphere();

// Objekt rotieren mit der rechten Maustaste
PickRotateBehavior pickr = new PickRotateBehavior(objRoot, canvas, behaveBounds);
objRoot.addChild(pickr);

// Objekt verschieben mit der linken Maustaste
PickTranslateBehavior pickt = new PickTranslateBehavior(objRoot, canvas, behaveBounds);
objRoot.addChild(pickt);

// Zoom mit beiden(bzw scrollrad drücken)
PickZoomBehavior pickz = new PickZoomBehavior(objRoot, canvas,behaveBounds);
objRoot.addChild(pickz);
objRoot.compile();
return objRoot;
}

/**
* Erzeugt einen Scenen Graph, der einen Würfel rotieren lässt
*
* @return {@link BranchGroup}
*/
public BranchGroup createSceneGraphManipulationWithMouse() {
BranchGroup objRoot = new BranchGroup();
// Transformgruppe werden zum manipulieren gesetzt
TransformGroup objRotate = new TransformGroup();
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

// Beschreibt eine Bewegung
Transform3D transform = new Transform3D();

// 3D Würfel wird erstellt
ColorCube cube = new ColorCube(0.3);

// Setzt den Würfel an eine bestimmte Position, wird nur auf
// der x-Achse verschoben
Vector3f vector = new Vector3f(-0.5f, .0f, .0f);

// Der bewegung wird ein vektor hinzugefügt
transform.setTranslation(vector);

// Die bewegung wird der transform gruppe hinzugefügt
objRotate.setTransform(transform);

// Würfel wird der transform gruppe hinzugefügt
objRotate.addChild(cube);

// Die transform gruppe wird dem branch hinzugefügt
objRoot.addChild(objRotate);

// Ein Alpha(loopCount, increasingAlphaDuration)Objekt bestimmt
// den Zeitpunkt der Veränderung eines visuellen Objektes durch
// einen Interpolator.
// loopCount-Anzahl der Male, dass das Alpha durchläuft, ein
// Wert von -1 gibt an, dass das Alpha unbestimmte Zeit
// durchläuft.
// increasingAlphaDuration -Zeitraum
Alpha timing = new Alpha(-1, 4000);

// RotationInterpolation wird erzeugt, damit der würfel rotiert
RotationInterpolator nodeRotator = new RotationInterpolator(timing,objRotate, transform, 0.0f, (float) Math.PI * 2.0f);

nodeRotator.setSchedulingBounds(new BoundingSphere(new Point3d(0.0, 0.0, 0.0), Float.MAX_VALUE));

// Rotation wird dem Würfel hinzugefügt
objRoot.addChild(nodeRotator);

objRoot.compile();
return objRoot;
}

public static void main(String args[]) {
new Wuerfel(„Beispiel“);
}

}
[/java]

5. Quellen

http://linawolf.de/veroeffentlichungen/tutorials-studium/java-3d.html
https://www.matse.rz.rwth-aachen.de/dienste/public/show_document.php?id=7223
http://www2.hs-fulda.de/caelabor/inhalte/java/j3d/j3d_seminar/11/Verwendete%20Literatur/07java3d_1.pdf
http://www.fh-wedel.de/~si/seminare/ws00/Ausarbeitung/12.java3d/java3d0.htm
http://www-vs.informatik.uni-ulm.de/teach/ws03/vp/ausarbeitungen/Java3D_Jahn.pdf
http://www2.hs-fulda.de/caelabor/inhalte/java/j3d/j3d_seminar/8/Java3D_interaktionen.pdf