kramann.info
© Guido Kramann

Login: Passwort:










Arbeiten mit Java3D

  • An kleinen Beispielen soll Schritt für Schritt die Benutzung von Java3D beschrieben werden.
  • Da die Programme schnell umfangreich werden, wird zuvor erarbeitetes immer wieder in Hilfsmethoden zusammengefaßt werden.
  • Es wird von darauf abgezielt, die Darstellung innerhalb eines Applets einzufügen, dies gelingt zur Zeit aber noch nicht (gelang aber bereits im Beispiel 2dlinienapplet, s. .zip-File).
  • Dies setzt voraus, dass beim Client-Rechner Java3D installiert ist, da hardwarenahe Library-Teile nicht über das Internet übertragen werden.
  • Die Elemente der darzustellenden Szene werden in einen Szenen-Graph eingehangen (Baumstruktur).
java3dbeispiele.zip - nachfolgende und weitere Beispiele.

Der Klassenpfad

  • Beim Kompilieren unter KNOPPIX muß der Klassenpfad für die Java3D-Bibliotheken mit angegeben werden.
  • Komilieren und Starten eines Programms sieht deshalb folgendermaßen aus (Beispiel):
cd Verzeichnis/in/dem/Beispiel3D.java liegt
javac -classpath /usr/share/java/vecmath.jar:/usr/share/java/j3dcore.jar:/usr/share/java/j3dcore-1.5.2+dfsg.jar:/usr/share/java/java3ds-fileloader-1.2.jar:/usr/share/java/j3dutils.jar:/usr/share/java/j3dutils-1.5.2+dfsg.jar:. -Xlint:deprecation Beispiel3D.java
java  -classpath /usr/share/java/vecmath.jar:/usr/share/java/j3dcore.jar:/usr/share/java/j3dcore-1.5.2+dfsg.jar:/usr/share/java/java3ds-fileloader-1.2.jar:/usr/share/java/j3dutils.jar:/usr/share/java/j3dutils-1.5.2+dfsg.jar:. Beispiel3D

Code 8-1: Kompilieren und Starten eines Programms.

  • Es ist ab Java6 auch möglich eine Wildcard (*) zu verwenden, um alle Archive in einem Verzeichnis dem Classpath hinzuzufügen:
cd Verzeichnis/in/dem/Beispiel3D.java liegt
javac -classpath /usr/share/java/*:. -Xlint:deprecation Beispiel3D.java
java  -classpath /usr/share/java/*:. -Xlint:deprecation Beispiel3D

Code 8-2: Kompilieren und Starten eines Programms mit Wildcard.

  • Legt man die jar-Pakete von Java3d in das Applet-Verzeichnis funktioniert auch:
cd Verzeichnis/in/dem/Beispiel3D.java liegt
javac -classpath ./*:. -Xlint:deprecation Beispiel3D.java
java  -classpath ./*:. -Xlint:deprecation Beispiel3D

Code 8-3: Kompilieren und Starten eines Programms mit lokalen .jar-Files.

  • Die .jar-Dateien für Java3D liegen bei Knoppix nach der Installation des Debian-Paketes unter:
  • /KNOPPIX-DATA/usr/share/java
  • Es sind:
  • j3dcore-1.5.2+dfsg.jar
  • j3dutils-1.5.2+dfsg.jar
  • java3ds-fileloader-1.2.jar
  • vecmath-1.5.2.jar
  • Der Classpath kann auch vorher festgelegt werden mit:
export CLASSPATH=:/usr/share/java/vecmath.jar:/usr/share/java/j3dcore.jar:/usr/share/java/j3dcore-1.5.2+dfsg.jar:/usr/share/java/java3ds-fileloader-1.2.jar:/usr/share/java/j3dutils.jar:/usr/share/java/j3dutils-1.5.2+dfsg.jar:.

Code 8-4: Setzen des Classpath.

"Einfaches" Beispiel

  • Um überhaupt etwas auf den Bildschirm zu zaubern, ist bei Java3D ziemlich viel Quellcode zu schreiben.
  • In dem folgenden Beispiel soll eine rote Kugel in einer vertikalen Bewegung animiert werden.
  • Dieses Beispiel ist zwar nicht ganz einfach, enthält aber alles, was zur Erstellung von 3D-Animationen notwendig ist.
  • Um Szenen performanter animieren zu können, können unveränderlche Äste mit compile() kompiliert werden.
  • Dies wird hier nicht genutzt.
  • Die einzelnen Elemente der 3D-Animation werden hier durch statische Methoden in einer selbst geschriebenen Hilfsklasse erzeugt.
  • holeKugel(..) beispielsweise liefert ein geometrisches Kugel-Objekt des gewünschten Radius und der gewünschten Farbe zurück.
  • Die Methode erzeugt aber zugleich auch einen Transformationsknoten, an den die Kugel gehangen wird.
  • Zurückgegeben wird der Transformationsknoten, in dem die Kugel dann liegt.
  • Dies erlaubt es, Größe, Position und Drehung der Kugel später in der Animation zu transformiern.
  • Für die Verschiebung und Drehung geometrischer Komponenten existiert die Methode holeTransformation(..) in J3D.
  • Diese Methode liefert ein Transformationsobjekt, in dem die Information über die Art der Transformation enthalten ist.
  • Insbesondere können Verschiebung, Drehung und auch Skalierung darin über eine 4x4-Matrix beschrieben werden.
  • Die obere linke 3x3 Untermatrix darin entspricht der Rotation.
  • In dem Beispiel hier wurden vorher von Hand drei Drehmatrizen (um die x-, y- und z-Achse) miteinander multipliziert und das Ergebnis hier hinein gelegt.
  • Dass alle Drehungen möglich sind ist günstig, um alle Wege bei der Animation offen zu lassen, aber führt natürlich zu Einbußen in der Performance.
  • Kameraposition, Beleuchtung usw. werden hier in elementarer Weise festgelegt und nicht weiter behandelt.
  • Unter Verwendung der Hilfsklasse J3D kann das Testbeispiel recht einfach gestaltet werden:
import com.sun.j3d.utils.universe.SimpleUniverse;
import java.applet.Applet;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.BranchGroup;

import javax.media.j3d.TransformGroup;
import com.sun.j3d.utils.applet.MainFrame;

import vis3d.J3D;

import java.awt.Frame;
import java.awt.BorderLayout;

public class Java3D1 extends Applet implements Runnable
{
    double phi = 0.0;

    public SimpleUniverse universum;
    public BranchGroup    welt; //Wurzel der Baumstruktur, in der die Szene zusammengestellt wird.
    public TransformGroup kugel;

    public Java3D1()
    {
        setLayout(new BorderLayout());

        this.universum = J3D.holeUniversum();

        welt = J3D.holeWelt();


        kugel = J3D.holeKugel(0.1,255,0,0);

        welt.addChild(kugel);

        kugel.setTransform(J3D.holeTransformation(0.0,0.5,0.0,0.0,0.0,0.0));

        universum.addBranchGraph(welt);
        add(this.universum.getCanvas()); //Zeichenfläche auf Applet setzen.
    }

    public void start()
    {
        Thread thread = new Thread(this);
        thread.start();
    }

    public void run()
    {
        while(true)
        {
            try
            {
                Thread.sleep(40);
            }
            catch(Exception e)
            {
            }
            kugel.setTransform(J3D.holeTransformation(0.0,-0.1+0.3*(1.0+Math.sin(phi)),0.0,0.0,0.0,0.0));
            
            phi+=0.02;
        }
    }

    public static void main(String[] args)
    {
       Java3D1 applet = new Java3D1();
       applet.init();
       applet.start();
       MainFrame mainframe = new MainFrame(applet,600,600);
       mainframe.dispose();
       mainframe.setUndecorated(true);
       mainframe.setVisible(true);       
       mainframe.setExtendedState(Frame.MAXIMIZED_BOTH);
       mainframe.setAlwaysOnTop(true);
    }
}

Code 8-5: Klasse Java3D1.java: Vertikale Animation einer roten Kugel.

  • Es folgt die Klasse J3D mit den Hilfsmethoden:
package vis3d;

import com.sun.j3d.utils.universe.SimpleUniverse;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import java.awt.GraphicsConfiguration;

import javax.media.j3d.BoundingSphere;

import javax.media.j3d.AmbientLight;
import javax.media.j3d.SpotLight;
import javax.media.j3d.PointLight;

import javax.vecmath.Color3f;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;

import javax.media.j3d.TransformGroup;
import com.sun.j3d.utils.geometry.Sphere;
import javax.media.j3d.Material;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.Appearance;

import javax.vecmath.Matrix4d;
import javax.media.j3d.Transform3D;



/**
Klasse mit statischen Methoden, mit denen sich die Benutzung von Java3D 
übersichtlicher gestalten lassen soll.
*/
public class J3D
{
    /**Liefert die Welt, in der ein Szenenbaum eingefügt werden kann
    */
    public static SimpleUniverse holeUniversum()
    {
        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();        
        Canvas3D c = new Canvas3D(config);        
        SimpleUniverse universum = new SimpleUniverse(c);
        universum.getViewingPlatform().setNominalViewingTransform();
        return universum;                
    }

    public static BranchGroup holeWelt()
    {
        BranchGroup welt = new BranchGroup();

        //Umgebungslicht
        AmbientLight licht = new AmbientLight(new Color3f(0.3f,0.3f,0.3f));
          
        licht.setInfluencingBounds(
                                    new BoundingSphere(
                                                           new Point3d(0.0,0.0,0.0), 100.0
                                                      )
                                  );

        //spot( farbe, Quellpos, Richtung)
        PointLight spot = new PointLight(
                                            new Color3f(1.0f,1.0f,1.0f),
                                            new Point3f(-3.0f,10.0f,3.0f),
                                            new Point3f(0.3f,-1.0f,-0.3f)
                                        );
                                        
        spot.setInfluencingBounds(
                                      new BoundingSphere(
                                                             new Point3d(0.0,0.0,0.0), 100.0
                                                        )
                                  );

        welt.addChild(licht);
        welt.addChild(spot);

        return welt;               
    }

    /**
    Es wird ein Transformationsknoten zurückgeliefert, an dem die Kugel hängt.
    */
    public static TransformGroup holeKugel(double radius, int rot, int gruen, int blau)
    {
        //Material(Color3f ambientColor, Color3f emissiveColor, Color3f diffuseColor, float shininess)
        float r = (float)rot/256.0f;
        float g = (float)gruen/256.0f;
        float b = (float)blau/256.0f;
        
        Color3f farbe_a = new Color3f(r,g,b);
        Color3f farbe_e = new Color3f(0.0f,0.0f,0.0f);
        Color3f farbe_d = new Color3f(r*0.5f,g*0.5f,b*0.5f);
        Color3f farbe_x = new Color3f(1.0f,1.0f,1.0f);
        
        Appearance erscheinung = new Appearance();
                        
        Material mat = new Material(farbe_a,farbe_e,farbe_d,farbe_x,100.0f);
        
        mat.setLightingEnable(true);
        
        erscheinung.setMaterial(mat);
        
        erscheinung.setColoringAttributes(
                                             new ColoringAttributes(farbe_d,ColoringAttributes.SHADE_GOURAUD)
                                         );
        Sphere kugel = new Sphere( (float)radius,Sphere.GENERATE_NORMALS, 80, erscheinung );
        
        TransformGroup tg = new TransformGroup();
        
        tg.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        
        tg.addChild(kugel);
        
        return tg;
    }

    public static Transform3D holeTransformation(double x, double y, double z,
                                                 double a, double b, double c)
    {
        return 
            new Transform3D
            (
                new Matrix4d  //zeilenweise
                (
                    Math.cos(b)*Math.cos(c),  
                   -Math.cos(a)*Math.sin(c) + Math.sin(a)*Math.sin(b)*Math.cos(c),
                    Math.sin(a)*Math.sin(c) + Math.cos(a)*Math.sin(b)*Math.cos(c),
                    x,
                    
                    Math.cos(b)*Math.sin(c),
                    Math.cos(a)*Math.cos(c) + Math.sin(a)*Math.sin(b)*Math.sin(c),
                   -Math.sin(a)*Math.cos(c) + Math.cos(a)*Math.sin(b)*Math.sin(c),
                    y,
                    
                   -Math.sin(b),
                    Math.sin(a)*Math.sin(b),
                    Math.cos(a)*Math.cos(b),
                    z,
                    
                    0.0,
                    0.0,
                    0.0,
                    1.0 
                )            
            );
    }                       

}

Code 8-6: Klasse J3D.java - Hilfsmethoden zur Erleichteurng der Verwendung von Java3D.

  • Neben diesem, sind in obigem .zip-File noch weitere Beispiele zum Testen enthalten.