Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Seminar Grafikprogrammierung mittels Java3D Inhaltsverzeichnis Allgemeines zu geometrische Transformationen ..................Seite 2 Translation ...........................................................................Seite 3 Skalierung ............................................................................Seite 5 Rotation ...............................................................................Seite 6 TransformGroup ...................................................................Seite 9 Kombination von Transformationen......................................Seite 10 Quellen ................................................................................Seite 14 Anhang: Szenengraphen RoboterArm................................................Seite 15 Quell-Coder RoboterArm.java ..............................................Seite 16 Quell-Code AxenColorCubeInter.java ..................................Seite 25 1 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Allgemeines zu geometrische Transformationen Mit der Ausarbeitung über Transformationen im Seminar Java3D werden die wichtigsten geometrischen Transformationen dreidimensionaler Objekte betrachtet. Außerdem wird gezeigt wie man die Transformationen auf Objekte in Java3D anwenden kann. Java3D speichert die dreidimensionalen Objekte anhand ihrer Flächen. Zur Erklärung der Transformationen ist es aber einfacher sich die Flächen als eine Anzahl von Punkten (Vertices) und eine Liste von Kanten vorzustellen. Die Endpunkte der Kanten bestehen aus den Eckpunkten des Objekts. Durch die geometrischen Transformationen wie Rotation, Skalierung und Translation auf die Punkte eines Objekts, wird dieses in ein neues Koordinatensystem abgebildet. Die Liste der Punkte eines Objekts ist durch V = { vi | vi = (xi, yi, zi) R3 , i N } definiert. Damit man in Java mit diesen Raumpunkten in Form von Vektoren und Matrizen rechnen kann, werden in dem Paket javax.vecmath die benötigten Klassen für Vektoren und Matrizen bereitgestellt. Dieses Paket behandelt natürlich auch die nötigen Funktionen, damit man mit diesen Vektoren und Matrizen rechnen kann. In diesen Klassen gilt eine Namenskonvention die darauf hinweist zu welchem Wertebereich die Inhalte zählen. Die Klassennamen enden alle auf einen Kleinbuchstaben, der den Wertetyp der Komponente zeigt. So steht - b für byte f für float und d für double Die Zahl, die vor diesen Buchstaben steht, deutet auf die Anzahl der Wertkomponenten hin. Ein dreidimensionaler Vektor mit doppelter Fließkommagenauigkeit wird in einer Instanz von Vector3d gespeichert. Die vierdimensionale Matrize (4 x 4) mit einfach genauen Fließkommawerten ist eine Instanz von Matrix4f. Die Transformationen in Java3D werden in Objekten des Typs javax.media.j3d.Transform3D gespeichert. Die Objekte wiederum referenzieren Instanzen der Klasse javax.vecmath.Matrix4d. Die Transform3D-Klasse repräsentiert also eine 3D-transformationsmatrix in der Form 4 x 4 für Verschiebungen, Drehungen und Dehnungen/Stauchungen. Transform3D wird nicht direkt in einem Szenengraphen, sondern meistens in Verbindung mit der TransformGroup-Klasse verwendet. Ein TransformGroup-Objekt wird meistens aus der Kombination mehrer Transform3D-Objekten konstruiert. 2 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Translation Die Translation ist eine Verschiebung der Punkte eines Objekts. Alle Punkte werden dabei um tx in x-Richtung, ty in y-Richtung und tz in z-Richtung verschoben. Die tx Translation ist eine Addition der Punkte um den Vektor t y . tz x t x x t x x' y + t y = y t y = y' z t z t z' z z Um die die Transformation mit einer Matrixmultiplikation durchführen zu können, bei der sich alle Punkte ändern, benötigt man eine Matrix, die um eine Dimension erweitert ist. Die erweiterte Matrix hat in der unteren Zeile die Koordinaten (0 0 0 1), so dass alle Punkte aus dieser Ebene wieder in die vierte Ebene abgebildet werden. Auch die Punkte des Objekts müssen um eine Dimension erweitert und in x homogenen Koordinaten y dargestellt werden. z 1 Mit dieser Vorgehensweise erhält man die folgende Translationsmatrix: 1 0 0 0 0 tx 0 ty 1 tz 0 1 0 1 0 0 Wird der Punkt nun mit dieser Translationsmatrix multipliziert, so erhält man das gleich Ergebnis wie bei der Addition mit dem Translationsvektor. 1 0 0 0 0 1 0 0 0 tx x x tx 0 ty y y ty O = 1 tz z z tz 1 1 0 1 3 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Die zusätzliche Komponente beim Ergebnis wird nicht beachtet und weggelassen. In Java3D erzeugt man diese 4 x 4 Matrix mit einem Transform3D-Objekt. Transform3D translation = new Transform3D (); Mit dem Standardkonstruktor erhält man so eine 4 x 4 Matrix, die mit der 1 0 0 0 0 1 0 0 Identitätsmatrix vorinstalliert ist. Damit diese Matrix die gewünschte 0 0 1 0 0 0 0 1 Transformation in Form einer Translation vornimmt, muss sie mit einer Funktion initialisiert werden. Die Translation mit den Werten x, y, z mit einfacher Fließkommagenauigkeit wird durch die Initialisierung des Matrix4d-Objekts mit der Funktion Transform3D.setTranslation ( vector3f ) erreicht. Bei dieser Funktion werden nur die Werte, die für die Translation notwendig sind, durch die Werte in dem Vektor ausgetauscht. translation.setTranslation ( new Vector3f ( x, y, z)); Die Funktion Transform3D.set(Vector3f) ändert die 4 x 4 Matrix in eine Translationsmatrix, bei der alle anderen Werte zu der Identitätsmatrix gehören. Transform3D.set(new Vector3f (x, y, z));) Natürlich gibt es diese Translationsfunktionen auch mit Vektoren die eine doppelte Fließkommagenauigkeit (Vector3d) haben. 4 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Skalierung Die Skalierung eines Objekts wird auch als Dehnung bzw. Stauchung bezeichnet. Bei der Skalierung eines Objekts wird jeder Punkt um den Faktor x für die xKoordinaten, y für die y-Koordinaten und z für die z-Funktionen vergrößert bzw. verkleinert. Auch hier wird eine 4 x 4 Matrix verwendet, um durch Multiplikation mit den einzelnen Ursprungspunkten in homogenen Koordinaten die neuen Zielpunkte zu erreichen. x 0 0 0 0 y 0 0 0 0 z 0 0 x x * x 0 y y * y O = 0 z z * z 1 1 1 Die Transformationsmatrix wird hier auch wieder durch eine Transform3D-Instanz bereitgestellt. Transform3D scale = new Transform3D (); Diese Identitätsmatrix muss nun durch eine entsprechende Funktion noch mit den Skalierungswerten initialisiert werden. Sind in der Matrix schon Skalierungsfaktoren vorhanden, so werden diese zuerst herausgerechnet, bevor die neuen Skalierungswerte eingesetzt werden. Bei der ersten der folgenden Funktionen werden verschiedene Werte für die x, y, z-Achse benutzt und bei der zweiten Funktion erfolgt die Skalierung über alle drei Achsen parallel. scale.setScale ( new Vector3f ( x, y, z )); scale.setScale (double scale); Es gibt auch Funktionen, die in einem Schritt eine Skalierung und eine Translation in eine Matrix einbinden. set(Vector3f translation, float scale) set(Vector3d translation, double scale) 5 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Rotation Unter Rotation versteht man die Drehung um eine Achse. Bei den Rotationen gibt es unterschiedliche Transformationsmatrizen für die Drehung um die x, y und z-Achse. Bei der Rotation eines Objekts um die x-Achse bleiben die x-Koordinaten der Punkte konstant und nur die y und z-Koordinaten verändern sich. Die Rotationen erfolgen auch durch die Multiplikation einer 4 x 4 Matrix, der Rotationsmatrix, mit den einzelnen Ursprungspunkten in homogenen Koordinaten. Die Rotationsmatrix wird wieder durch ein Transform3D-Objekt bereitgestellt. Transform3D rotation = new Transform3D (); 0 1 0 cos Rx( ) p = 0 sin 0 0 0 sin cos 0 0 x x 0 y y * cos z * sin O = 0 z y * sin z * cos 1 1 1 Bei der Drehung um die y-Achse ist eine anders aufgebaute Transformationsmatrix nötig, bei der die y-Koordinaten der Punkte konstant belieben. cos 0 Ry( ) p = sin 0 0 sin 1 0 0 cos 0 0 0 x x * cos z * sin 0 y y O = 0 z x * sin z * cos 1 1 1 Und schließlich gibt es noch eine Transformationsmatrix für die Drehung um die ZAchse, bei der die Z-Koordinaten der Punkte konstant bleiben. cos sin Rz( ) p = 0 0 sin cos 0 0 0 0 1 0 0 x x * cos y * sin 0 y x * sin y * cos O = 0 z z 1 1 1 In Java3D werden diese Rotationsmatrizen einfach mit Hilfe der Transform3D-Klasse und den dazugehörigen Funktionen erstellt. 6 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Rotation um die x-Achse: rotation.rotX ( alpha ); Rotation um die y-Achse: rotation.rotY ( alpha ); Rotation um die z-Achse: rotation.rotZ ( alpha ); Der Winkel alpha gibt an um wie viel Grad das Objekt gedreht wird. Der Winkel wird im Bogenmaß angegeben. Man kann aber auch ein Gradmaß einsetzen, und dieses mit einer Funktion ins Bogenmaß umrechnen. Bei der Angabe im Bogenmaß verwendet man die Konstante Math.PI und bei der Angabe in Gradmaß wird die Funktion Math.toRadians benutzt. 1 34 315 3 2 270 1 4 225 2 360 4 45 Bogenmaß Gradmaß 2 90 3 4 180 7 135 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Neben den Standardfunktionen, bei denen man ein Objekt um die x, y oder z-Achse dreht, gibt es aber noch Hilfsfunktionen in der Klasse Transform3D, mit denen man eine Rotationsmatrix um eine beliebige Achse erstellen kann. Die Funktion Transform3D.setRotation (AxisAngle4d) ermöglicht es die Raumachse durch einen Vektor und einen Drehwinkel für die Rotation anzugeben. Das Objekt, das den Vektor und den Winkel aufnimmt, ist ein AxisAngle4d-Objekt. Die Funktion Transform3D.setRotation (AxisAngle 4d) passt die Rotationskomponente an und behält Skalierungs- und Translationskomponenten bei. Eine Transformationsmatrix, die ein Objekt 30 dreht, wird folgendermaßen aufgebaut. 0 um die erste Quadrantenhalbierende Transform3D rotation = new Transform3D (); transform.setRotation ( new AxisAngle4d ( 1, 1, 1, Math.toRadians ( 30.0d))); 8 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D TransformGroup Damit die oben gezeigten Transformationen auf ein Objekt angewendet werden können, müssen sie durch ein TransformGroup-Objekt referenziert werden. Die TransformGroup-Klasse ist von Group abgeleitet und wird zur Konstruktion des Szenengraphen verwendet. Ein Objekt dieser Klasse spezifiziert geometrische 3D-Transformationen, die auf ein oder mehrere Subknoten angewendet werden können. Die Transformationsmatrix wird auf eine der oben beschriebenen Weise konstruiert. Der Standardkonstruktor der TransformGroup-Klasse TransformGroup transGroup = new TransformGroup (); erstell ein TransformGroup-Objekt und initialisiert es mit der Identitätstransformationsmatrix. Wird im Konstruktor schon eine Transformation in Form eines Transform3D-Objekts angegeben, so wird das TransformGroup-Objekt direkt mit der Transformation initialisiert. TransformGroup transGroup = new TransformGroup (Transform3D transformation); Eine Transformation kann man auch TransformGroup.setTransform angeben. noch nachträglich mit transGroup.setTransform ( Transform3D t1); Wenn das TransformGroup-Objekt das erste Objekt unterhalb eines Locale ist, wirkt die Transformation relativ zu diesen Koordinaten. Sind zwischen dem Locale und dem TransformGroup-Objekt schon mehrere TransformGroup-Objekte, werden die entsprechenden Transformationen vom Locale abwärts an kombiniert. Das durch das TransformGroup-Objekt beschriebene Koordinatensystem ist dann relativ zum Koordinatensystem der Vorgänger-TransformGroups. Man spricht in diesem Fall von einer CM Transformation (Composite Modell). Transform3D transform1 = new Transform3D (); transform1.rotX (Math.PI/4.0d); Transform3D transform2 = new Transform3D (); transform2.rotY (Math.PI/6.0d); TransformGroup transformgroup1 = new TransformGroup (transform1); TransformGroup transformgroup2 = new TransformGroup (transform2); transformgroup1.addChild (transformgroup2); transformgroup2.addChild (new ColorCube (0.5)); 9 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Kombination von Transformationen Die Transform3D-Klasse stellt neben den Funktionen zur Konstruktion von Transformationen auch Funktionen zur Kombination von Matrizen zur Verfügung. Hierbei ist zu bemerken, dass Matrizenmultiplikationen assoziativ, aber nicht kommutativ sind. assoziativ M1 * ( M2 * M3 ) = ( M1 * M2 ) * M3 nicht kommutativ M1 * M2 * M3 M3 * M2 * M1 Die Transform3D-Klasse bietet aber nicht nur die Matrizenmultiplikation an, sondern stellt auch Funktionen zur Verfügung, die zusammengefasste Transformationen ohne Matrixmultiplikation erzeugen. Transform3D.scaleAdd (double s, Transform3D trans); Diese Funktion skaliert die eigene 4 x 4 Matrix mit s und addiert die Transformationsmatrix des Transform3D-Objekts. ( this = s * this + trans ) Es gibt verschiedene Kombinationsfunktionen, die man alle in der Dokumentation unter der Klasse Transform3D nachschauen kann. Wenn man keine Funktion findet, die die gewünschte Transformation erzeugt, muss man die Matrizen direkt miteinander multiplizieren. Dies geschieht mit der mul-Funktion. Diese kann zwei Matrizen miteinander multiplizieren und in eine dritte schreiben C=A B oder man multipliziert eine Matrix direkt in die Ausgangsmatrix. A = A B Transform3D a = new Transform3D (); Transform3D b = new Transform3D (); Transform3D c = new Transform3D (); c.mul ( a, b ) a.mul ( b ) 10 c a b a a b Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Nach diesen beiden Matrixmultiplikationen Transformationsmatrizen a und c die gleiche Matrix. steht in den beiden Transform3D rotate_a = new Transform3D(); Transform3D rotate_b = new Transform3D(); rotate_a.rotX(Math.PI/4.0d); rotate_b.rotY(Math.PI/4.0d); Y Y X X Z Z rotate_a.mul(rotate_b); rotate_b.mul(rotate_a); Y Y X Z X Z 11 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Anstatt die einzelnen Transformationen zu kombinieren, ist es auch möglich für jede Transformation ein TransformGroup-Objekt zu erstellen und diese übereinander im Szenegraphen anzuordnen. Die TransformGroup-Objekte müssen nicht unbedingt eine Geometrie referenzieren. BG View branch graph TG TG ColorCube 12 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Bei allen Rotationen, die bis jetzt vorgestellt wurden, sind die Drehungen nur um eine Achse im Ursprung erfolgt. Soll die Drehung nun aber nicht um eine dieser Achsen sondern um eine Achse im einem anderen Punkt, der im Koordinatensystem liegt, durchgeführt werden, so muss man eine Kombination von Transformationen durchführen. Damit das Objekt um eine Achse im Punkt xr yr zr rotiert, muss es zuerst mit einer Translation xr yr zr in den Ursprung verschoben werden. Im Ursprung kann man das Objekt nun um den gewünschten Winkel drehen, und zum Schluss muss das Objekt wieder mit einer Rücktranslation xr yr zr zum Ausgangspunkt verschoben werden. Bei der Kombination dieser Vielzahl von Transformationen ist zu beachten, dass die Matrixmultiplikation nicht kommutativ ist. Die Aktion die als erstes ausgeführt werden soll, muss deshalb am weitesten rechts in der Matrizenmultiplikation stehen. 1 0 0 xr R xr yr zr / = T2 * R * T1 0 1 0 yr T1 0 0 1 zr 0 0 0 1 xr cos sin Rz 0 0 sin cos 0 0 0 0 1 0 yr zr 0 0 0 1 1 0 T2 0 0 0 1 0 0 0 0 1 0 xr yr zr 1 xr 13 yr zr Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Quellen Sun Java 3D Tutorial http://developer.java.sun.com/developer/onlineTraining/java3d/ Skript Graphische Datenverarbeitung Prof. Dr. Werner Heinzel 14 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Szenengraphen RoboterArm Locale View branch graph BG objRoot Behavior_Oberarm TG tg_oben Behavior_Untererarm TG tg_schulter TG tg_oberArm Shape3D schulter Appearance Geometry TG tg_unten Shape3D oberArm Appearance Geometry TG tg_elle Shape3D elle TG tg_unterArm Shape3D unterArm Appearance Appearance Geometry 15 TG tg_hand Shape3D hand Geometry Appearance Geometry Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Quell-Code RoboterArm.java /* Name: RoboterArm * * Autor: Frank Krack * Datum: 20. Oktober 2002 * * Darstellung eines Roboterarms, der durch Tastendruck bewegt * werden kann. * * - s --> ganzer Arm bewegt sich vorwärts * - d --> ganzer Arm bewegt sich rückwärts * - e --> Unterarm bewegt sich vowärts * - r --> Unterarm bewegt sich rückwärts * */ import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.GraphicsConfiguration; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; import java.awt.event.*; import java.util.Enumeration; // RoboterArm erstellt einen Arm bei dem // Ober- und Unterarm durch Tastendruck bewegt werden können public class RoboterArm extends Applet { public class Behavior_Oberarm extends Behavior 16 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D { private TransformGroup targetTG; private Transform3D rotation = new Transform3D(); private double angle_o = 0.0; private WakeupOnAWTEvent lauscher = new WakeupOnAWTEvent (KeyEvent.KEY_PRESSED); // erstellt Behavior_Oberarm Behavior_Oberarm(TransformGroup targetTG) { this.targetTG = targetTG; } // Initialisierung behavior public void initialize() { // Erignis zum Abarbeitungsbeginn this.wakeupOn(lauscher); } // diese Funktion wird von Java3D bei Eintritt // des Erignis aufgerufen public void processStimulus(Enumeration criteria) { TransformGroup tg_temp = new TransformGroup(); TransformGroup tg_punkt = new TransformGroup(); Transform3D t3d_punkt = new Transform3D(); Transform3D t3d_temp = new Transform3D(); KeyEvent key = (KeyEvent) lauscher.getAWTEvent()[0]; char c = key.getKeyChar(); switch (c) { case 's': // ganzer Arm vorwärts drehen angle_o -= 0.1; 17 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D rotation.rotZ(angle_o); targetTG.setTransform(rotation); break; case 'd': // ganzer Arm rückwärts drehen angle_o += 0.1; rotation.rotZ(angle_o); targetTG.setTransform(rotation); break; } this.wakeupOn (lauscher); } } // Ende der Klasse Behavior_Oberarm public class Behavior_Unterarm extends Behavior { private TransformGroup targetTG; private Transform3D rotation = new Transform3D(); private double angle_o = 0.0; private double angle_u = 0.0; private WakeupOnAWTEvent lauscher = new WakeupOnAWTEvent (KeyEvent.KEY_PRESSED); // erstellt Behavior_Unterarm Behavior_Unterarm(TransformGroup targetTG) { this.targetTG = targetTG; } // Initialisierung behavior public void initialize() 18 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D { // Erignis zum Abarbeitungsbeginn this.wakeupOn(lauscher); } // diese Funktion wird von Java3D bei Eintritt // des Erignis aufgerufen public void processStimulus(Enumeration criteria) { TransformGroup tg_temp = new TransformGroup(); TransformGroup tg_punkt = new TransformGroup(); Transform3D t3d_punkt = new Transform3D(); Transform3D t3d_temp = new Transform3D(); KeyEvent key = (KeyEvent) lauscher.getAWTEvent()[0]; char c = key.getKeyChar(); switch (c) { case 'e': // Unterarm vorwärts drehen angle_u -= 0.1; rotation.rotZ(angle_u); // Stellungsmatrix des Unterams // herausfinden tg_temp = (TransformGroup)targetTG.getChild(0); tg_temp.getTransform(t3d_punkt); t3d_temp.invert(t3d_punkt); rotation.mul(t3d_temp); t3d_punkt.mul(rotation); targetTG.setTransform(t3d_punkt); break; case 'r': // Unterarm rückwärts drehen 19 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D angle_u += 0.1; rotation.rotZ(angle_u); // Stellungsmatrix des Unterams // herausfinden tg_temp = (TransformGroup)targetTG.getChild(0); tg_temp.getTransform(t3d_punkt); t3d_temp.invert(t3d_punkt); rotation.mul(t3d_temp); t3d_punkt.mul(rotation); targetTG.setTransform(t3d_punkt); break; } this.wakeupOn (lauscher); } } // Ende der Klasse Behavior_Unterarm public BranchGroup createSceneGraph() { // Wurzel des Szenengraphs BranchGroup objRoot = new BranchGroup(); TransformGroup tg_oben = new TransformGroup(); tg_oben.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); tg_oben.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); tg_oben.setCapability(TransformGroup.ALLOW_CHILDREN_READ); TransformGroup tg_unten = new TransformGroup(); tg_unten.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); tg_unten.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); tg_unten.setCapability(TransformGroup.ALLOW_CHILDREN_READ); 20 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D objRoot.addChild(tg_oben); Transform3D t3d_schulter = new Transform3D(); t3d_schulter.set (new Vector3f(0.0f, 0.0f, 0.0f)); TransformGroup tg_schulter = new TransformGroup(t3d_schulter); Appearance app_schulter = new Appearance(); ColoringAttributes col_schulter = new ColoringAttributes (1.0f, 0.0f, 0.0f, 0); app_schulter.setColoringAttributes (col_schulter); Sphere schulter = new Sphere (0.1f, app_schulter); tg_schulter.addChild(schulter); Transform3D t3d_oberArm = new Transform3D(); t3d_oberArm.set (new Vector3f(0.0f, -0.35f, 0.0f)); TransformGroup tg_oberArm = new TransformGroup(t3d_oberArm); Appearance app_oberArm = new Appearance(); ColoringAttributes col_oberArm = new ColoringAttributes (0.0f, 0.0f, 1.0f, 0); app_oberArm.setColoringAttributes (col_oberArm); Cylinder oberArm = new Cylinder (0.1f, 0.5f, app_oberArm); tg_oberArm.addChild (oberArm); Transform3D t3d_elle = new Transform3D(); t3d_elle.set (new Vector3f(0.0f, -0.7f, 0.0f)); TransformGroup tg_elle = new TransformGroup(t3d_elle); tg_elle.setCapability(TransformGroup.ALLOW_CHILDREN_READ); tg_elle.setCapability(TransformGroup.ALLOW_TRANSFORM_READ); Appearance app_elle = new Appearance(); ColoringAttributes col_elle = new ColoringAttributes (0.0f, 1.0f, 0.0f, 0); app_elle.setColoringAttributes (col_elle); Sphere elle = new Sphere (0.1f, app_elle); elle.setCapability(Sphere.ENABLE_GEOMETRY_PICKING); tg_elle.addChild(elle); Transform3D t3d_unterArm = new Transform3D(); t3d_unterArm.rotZ (Math.PI * 1.5f); 21 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D t3d_unterArm.setTranslation(new Vector3f(-0.32f, -0.7f, 0.0f)); TransformGroup tg_unterArm = new TransformGroup(t3d_unterArm); Appearance app_unterArm = new Appearance(); ColoringAttributes col_unterArm = new ColoringAttributes (0.5f, 0.5f, 1.0f, 0); app_unterArm.setColoringAttributes (col_unterArm); Cylinder unterArm = new Cylinder (0.085f, 0.44f, app_unterArm); tg_unterArm.addChild (unterArm); Transform3D t3d_hand = new Transform3D(); t3d_hand.set (new Vector3f(-0.6f, -0.7f, 0.0f)); TransformGroup tg_hand = new TransformGroup(t3d_hand); Appearance app_hand = new Appearance(); ColoringAttributes col_hand = new ColoringAttributes (1.0f, 1.0f, 0.0f, 0); app_hand.setColoringAttributes (col_hand); Sphere hand = new Sphere (0.08f, app_hand); tg_hand.addChild(hand); tg_oben.addChild(tg_schulter); tg_oben.addChild(tg_oberArm); tg_unten.addChild(tg_elle); tg_unten.addChild(tg_unterArm); tg_unten.addChild(tg_hand); tg_oben.addChild(tg_unten); Behavior_Oberarm myRotationBehavior1 = new Behavior_Oberarm(tg_oben); Behavior_Unterarm myRotationBehavior2 = new Behavior_Unterarm(tg_unten); myRotationBehavior1.setSchedulingBounds(new BoundingSphere()); myRotationBehavior2.setSchedulingBounds(new BoundingSphere()); objRoot.addChild(myRotationBehavior1); objRoot.addChild(myRotationBehavior2); 22 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D // Optimierung des Szenengraphs objRoot.compile(); return objRoot; } public RoboterArm() { // Erstellung eines SimpleUniverse nach Vorgabe // aus dem Sun Tutorial setLayout(new BorderLayout()); GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); Canvas3D canvas3D = new Canvas3D(config); add("Center", canvas3D); BranchGroup scene = createSceneGraph(); // SimpleUniverse SimpleUniverse simpleU = new SimpleUniverse(canvas3D); simpleU.getViewingPlatform().setNominalViewingTransform(); simpleU.addBranchGraph(scene); } public static void main(String[] args) { Frame frame = new MainFrame(new RoboterArm(), 256, 256); } } 23 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Quell-Code AxenColorCubeItnter.java /* Name: AxenColorCubeInter * * Autor: Frank Krack * Datum: 16. Oktober 2002 * * Das Programm dient zur Demonstration einfacher * geometrischer Transformationen. * Der Würfel wird durch drücken verschiedene Tasten * unterschiedliche Axen gedreht. * * x --> dreht den Würfel mit 45 Grad um X-Achse * y --> dreht den Würfel mit 45 Grad um Y-Achse * z --> dreht den Würfel mit 45 Grad um Z-Achse * c --> dreht den Würfel um 2 Achsen * 1. Drehumg mit 45 Grad um X-Achse * 2. Drehung mit 45 Grad um Y-Achse * a --> dreht den Würfel um 2 Achsen * 1. Drehung mit 45 Grad um Y-Achse * 2. Drehung mit 45 Grad um X-Achse * n --> bringt den Würfel in Ausgangsstellung */ import java.applet.Applet; import java.awt.BorderLayout; import java.awt.Frame; import java.awt.event.*; import java.awt.GraphicsConfiguration; import com.sun.j3d.utils.applet.MainFrame; import com.sun.j3d.utils.geometry.*; import com.sun.j3d.utils.universe.*; import javax.media.j3d.*; import javax.vecmath.*; import java.util.Enumeration; 24 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D // AxenColorCube erstellt einen ColorCube mit einem // eingebetteten Koordinatensystem public class AxenColorCubeInter extends Applet { public class Behavior_Tastatur extends Behavior { private TransformGroup targetTG; private WakeupOnAWTEvent lauscher = new WakeupOnAWTEvent (KeyEvent.KEY_PRESSED); // erstellt Behavior_Tastatur Behavior_Tastatur(TransformGroup targetTG) { this.targetTG = targetTG; } // Initialisierung behavior public void initialize() { // Erignis zum Abarbeitungsbeginn this.wakeupOn(lauscher); } // diese Funktion wird von Java3D bei Eintritt // des Erignis aufgerufen public void processStimulus(Enumeration criteria) { TransformGroup tg_temp = new TransformGroup(); // Transformationsmatrizen Transform3D rotation = new Transform3D(); Transform3D rotate_a = new Transform3D(); Transform3D rotate_b = new Transform3D(); 25 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D KeyEvent key = (KeyEvent) lauscher.getAWTEvent()[0]; char c = key.getKeyChar(); switch (c) { case 'x': // Drehung des Würfels um die // X-Achse mit 45 Grad rotation.rotX(Math.PI/4.0d); targetTG.setTransform(rotation); break; case 'y': // Drehung des Würfels um die // Y-Achse mit 45 Grad rotation.rotY(Math.PI/4.0d); targetTG.setTransform(rotation); break; case 'z': // Drehung des Würfels um die // Z-Achse mit 45 Grad rotation.rotZ(Math.PI/4.0d); targetTG.setTransform(rotation); break; case 'c': // Drehung des Würfels um 2 Achsen // 1. Drehung um X-Achse mit 45 Grad // 2. Drehung um y-Achse mit 45 Grad rotate_a.rotX(Math.PI/4.0d); rotate_b.rotY(Math.PI/4.0d); rotate_a.mul(rotate_b); targetTG.setTransform(rotate_a); break; case 'a': // Drehung des Würfels um 2 Achsen // 1. Drehung um Y-Achse mit 45 Grad // 2. Drehung um X-Achse mit 45 Grad 26 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D rotate_a.rotY(Math.PI/4.0d); rotate_b.rotX(Math.PI/4.0d); rotate_a.mul(rotate_b); targetTG.setTransform(rotate_a); break; case 'n': // Würfel in Ausgangsstellung // zurückbringen rotation.rotX(0.0f); targetTG.setTransform(rotation); break; case 'q': // Drehung des Würfels um die erste // Quadrantenhalbierende mit 45 Grad rotation.setRotation (new AxisAngle4d (1,1,1, Math.toRadians (45.0d))); targetTG.setTransform(rotation); break; } this.wakeupOn (lauscher); } } // Ende der Klasse Behavior_Tastatur public BranchGroup createSceneGraph() { // Wurzel des Szenengraphs BranchGroup objRoot = new BranchGroup(); TransformGroup objRotate = new TransformGroup(); objRotate.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); objRoot.addChild(objRotate); Appearance app = new Appearance(); // Y-Achse des Koordinatensystems 27 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D Cylinder yAxe = new Cylinder (0.025f, 2.0f, app); objRotate.addChild(yAxe); // X-Achse des Koordinatensystems Cylinder xAxe = new Cylinder (0.025f, 2.0f, app); Transform3D rotXaxis = new Transform3D(); rotXaxis.rotZ (Math.PI / 2); TransformGroup rotXgroup = new TransformGroup (rotXaxis); rotXgroup.addChild(xAxe); objRotate.addChild(rotXgroup); // Z-Achse des Koordinatensystems Cylinder zAxe = new Cylinder (0.025f, 2.0f, app); Transform3D rotZaxis = new Transform3D(); rotZaxis.rotX (Math.PI / 2); TransformGroup rotZgroup = new TransformGroup (rotZaxis); rotZgroup.addChild(zAxe); objRotate.addChild(rotZgroup); objRotate.addChild(new ColorCube(0.4)); Behavior_Tastatur myRotationBehavior1 = new Behavior_Tastatur(objRotate); myRotationBehavior1.setSchedulingBounds(new BoundingSphere()); objRoot.addChild(myRotationBehavior1); // Optimierung des Szenengraphs objRoot.compile(); return objRoot; } public AxenColorCubeInter() { // Erstellung eines SimpleUniverse nach Vorgabe // aus dem Sun Tutorial setLayout(new BorderLayout()); 28 Transformationen Frank Krack 153 973 Seminar Grafikprogrammierung mittels Java3D GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration(); Canvas3D canvas3D = new Canvas3D(config); add("Center", canvas3D); BranchGroup scene = createSceneGraph(); // SimpleUniverse SimpleUniverse simpleU = new SimpleUniverse(canvas3D); simpleU.getViewingPlatform().setNominalViewingTransform(); simpleU.addBranchGraph(scene); } public static void main(String[] args) { Frame frame = new MainFrame(new AxenColorCubeInter(), 256, 256); } } 29