# Hilfe: Rotation X und Y Achse (Java3d)



## JavaPhil (1. Dez 2009)

Hi,

ich versuche eine Steuerung für ein Raumschiff in Java3d zu schreiben. Probleme hab ich bei der Perechnung der Rotationen um X und Y Achse. Zur zeit kann ich in Ausgangsstellung das Schiff komplett um die Y achse rotieren und auch um die X Achse, jedoch nicht ganz so wie das sein soll.

Kurz: wenn ich zb senkrecht nach oben oder unten schaue und dann eine Linksdrehung einleite Rotiert das Schiff nur... aber es soll nach Links schwenken :-(

Ich hab es mit einer und mit zwei TransformGroups Probiert beide male das selbe Ergebnis.

Muss ich noch irgendeine Flag setzen oder eventuel die Rotation selber berechnen also nicht mit rotX rotY?? aber wie???

MfG
Philipp

Edit: Versteht das keiner? Soll ichs nochmal anders erklären? Oder wisst ihr das auch nicht?


----------



## Marco13 (6. Dez 2009)

Den Unterschied zwischen "Rotieren" und "Schwenken" könntest du vielleicht nochmal näher erläutern. 
Aber ganz allgemein: Über die Auführungsreihenfolge der Rotationen und solche Begriffe wie "Gimbal Lock" sollte man sich schon genau Gedanken machen...


----------



## JavaPhil (13. Dez 2009)

Whaa ich dreh durch... ;(

hab ein Tutorial für Delphi gefunden, das sich genau mit meinem Problem auseinander setzt.

Tutorial Objekt immer um eigene Achse drehen ? DGL Wiki

Es beschreibt im grunde die Vorgehensweise wie ich mir das selber auch gedacht hab. Hab es mal auf java umgeschrieben und funzt nicht.. 

hier ein teil meines Java Codes... will hier nicht alles postenn wäre wohl zu viel


```
//wird von der processStimulus mit Enum RotationsVector und winkel aufgerufen
private void updateRotation(ROT rot , double angle)
	{
		
		if (rot == ROT.rotX)
		{	
                        //Quaternion Rotation anlegen		
			vect.set(vectX);
			vect.scale(Math.sin(angle/2.0));
			scalar = Math.cos(angle/2.0);	
			quat.set(vect.x, vect.y, vect.z, scalar);

                        //Hilfsmatrix mit Quaternion rotieren
			matr_temp.setIdentity(); 
			matr_temp.set(quat);
			
                        //bei rotation um X verändern sich die Lokalen Vetoren Y und Z
			matr_temp.transform(vectY);
			matr_temp.transform(vectZ);

                        //die ObjectMatrix mit der Temporären multiplizieren, Transform3d setzen
			matrix3d.mul(matr_temp);			
			tf_koords.set(matrix3d);
		}
                
                //andere Richtugen

                vectX.normalize();	
		vectY.cross(vectZ, vectX);
		vectY.normalize();	
		vectZ.cross(vectX, vectY);
		vectZ.normalize();

                //transformGroup setzen
		tg_koords.setTransform(tf_koords);

        }
```

Das ganze funktioniert für rotation um x oder y, aber nicht für X und Y da kommt Käse bei raus.

per Sysout hab ich festgestellt das die Lokalen Vectoren nicht mit dem Object übereinstimmen. Hab mir als object 3 Pfeile gebastelt welche Anfangs in XYZ richtung schauen. Wurschtel ich jetzt mit meinen rotationen rum biss sie ungfähr wieder in Ausgangsstellung stehen sollten ja auch die lokalen Vectoren wieder in ausgangsstellung stehen.. Dies ist aber nicht der fall die schauen sonnst wo hin...

Meine vermutung ist daher das irgendwas an dem rotieren der Lokalen falsch ist
matr_temp.transform(vectY);
matr_temp.transform(vectZ);

oder an der rotation der ObjectMatrix
matrix3d.mul(matr_temp);

Hat jemand da eine Idee?

Danke,
Philipp


----------



## Marco13 (13. Dez 2009)

Ja, niemand weiß, was die ganze Fields sind (matr_temp, tf_koords, vectX, ...Schau dir auch mal die Java naming conventions an.... :autsch: ). 

Mich irritiert allein schon die if-Abfrage - was auch immer da gemacht wird, es wird ja NUR bei einer Rotation um die X-Achse gemacht ???:L

Wie auch immer, das allgemeine Schema ist grob sowas wie

```
Matrix4f gesamtRotation = (am Anfang: Matrix4f mit setIdentity)

void rotateX(float angle)
{
    Matrix4f rotation = new Matrix4f();
    rotation.setIdentity();
    rotation.rotX(angle);
    gesamtRotation.mul(matrix, gesamtRotation); // Von LINKS dranmultiplizieren!!!

    someTransformNode.setTransform(... Transform3D mit 'gesamtRotation'  ...);
}

// Für rotation um Y ganz analog...
...
```

Ansonsten wäre ein Compilierbarer Codeschnipsel evtl. ganz hilfreich...


----------



## JavaPhil (14. Dez 2009)

hmm

Also ich hab da //andere Richtungen geschrieben was so viel heisst wie:

 if (rot == ROT.rotY)...
 if (rot == ROT.rotZ)...

ROT ist einfach ne Enum

Die methode wird vom ProzessStimulus aufgerufen, der je nach Tastendruck entscheidet welche enum übergeben wird..

vect ist ein Hilfsvector der für die Quaternion Berechnung benötigt wird
und je nach wahl mit dem jeweiligem lokalen Vector vecX vecY oder vecZ gesetzt wird

Das heist es wird (sollte) dann genau um diesen Vector und nicht um das Weltkoordinatensystem gedreht werden.  --> je nach Rotation werden die beiden Anderen Lokalen Vectoren mitgedreht.. hier
vectY und vectZ da rotation um X

matr_temp ist einfach eine temporäre Matrix3d
tf_koords ist die Transform3D der tg_koords welche die TransformGroup des Objects ist.

das normalisieren passiert um rundungsfehler auszumerzen... 

wenn ich heut abend zu hause bin post ich mal das ganze behavior...

Aber schon mal vornweg .. ich will halt nicht  "rotation.rotX(angle);" verwenden weil dies immer um das Weltkoordinatensystem dreht.. und das ist gerade das was ich nicht will..

Ich hoffe das klärt ein paar Ungenauigkeiten in meinem code... 

Danke,
Philipp


----------



## Marco13 (14. Dez 2009)

JavaPhil hat gesagt.:


> Aber schon mal vornweg .. ich will halt nicht  "rotation.rotX(angle);" verwenden weil dies immer um das Weltkoordinatensystem dreht.. und das ist gerade das was ich nicht will..



Das ist erstmal nur eine Rotation um die X-Achse - in Weltkoordinaten, ja, aber zu einer Rotation um lokale Koordinaten wird das, indem man es an der richtigen Stelle von links oder rechts an eine andere Matrix dranmultipliziert...


----------



## Empire Phoenix (14. Dez 2009)

Zu Quaternions kann ich nur empfehlen bei google nach dem einnen Referat zu suchen, "Einführung in quaternions" oder so. Das ist relativ hilfreich, wenna uch mathematisch etwas anpruchsvoller, dennoch lohnt sich der aufwand.


----------



## JavaPhil (14. Dez 2009)

So hier mal der ganze code... unkommentiert hab leider keine zeit, aber im grunde sollte man alles verstehen.


```
public class RotBehavior extends Behavior{
	
	enum ROT {rotX , rotY, rotZ};
	static double rotSpeed = 0.1;
	
	private WakeupCondition cond;
	private TransformGroup tg_koords;
	private Transform3D tf_koords = new Transform3D();
	
	private Matrix3d matrix3d = new Matrix3d();
	private Matrix3d matr_temp = new Matrix3d();
	
        //Quaternion + das was zum bauen noetig ist
	private Quat4d quat = new Quat4d();
	private Vector3d vect = new Vector3d();
	private double scalar;
	
        //lokale Vectoren
	private Vector3d vectX = new Vector3d();
	private Vector3d vectY = new Vector3d();
	private Vector3d vectZ = new Vector3d();
	

	public RotBehavior(TransformGroup tg_koords)
	{
		this.tg_koords = tg_koords;
	}
	
	@Override
	public void initialize() {	
		cond = new WakeupOnAWTEvent(KeyEvent.KEY_PRESSED);	
		this.wakeupOn(cond);	

                //Vectoren und Matrix initialisieren (ganz unten)
		reset();
	}

	@Override
	public void processStimulus(Enumeration criteria) {
		
		WakeupOnAWTEvent event = (WakeupOnAWTEvent) criteria.nextElement();	
		KeyEvent key = (KeyEvent) event.getAWTEvent() [0];
				
		tg_koords.getTransform(tf_koords);

		if (key.getKeyChar()=='d')
			updateRotation(ROT.rotY, rotSpeed);
		if (key.getKeyChar()=='a')
			updateRotation(ROT.rotY, -rotSpeed);		
		if (key.getKeyChar()=='w')
			updateRotation(ROT.rotX, rotSpeed);
		if (key.getKeyChar()=='s')
			updateRotation(ROT.rotX, -rotSpeed);

                //Ausgabe zum Kontrollieren.. was der so für Mist macht
		System.err.println("vectX: "+ vectX);
		System.err.println("vectY: "+ vectY);
		System.err.println("vectZ: "+ vectZ);

		this.wakeupOn(cond);
	}
	
	
	private void updateRotation(ROT rot , double angle)
	{
		
		if (rot == ROT.rotX)
		{			
			vect.set(vectX);
			vect.scale(Math.sin(angle/2.0));
			scalar = Math.cos(angle/2.0);	
			quat.set(vect.x, vect.y, vect.z, scalar);

			matr_temp.setIdentity(); 
			matr_temp.set(quat);
			
			matr_temp.transform(vectY);
			matr_temp.transform(vectZ);

			matrix3d.mul(matr_temp);			
			tf_koords.set(matrix3d);
						
		}
		
		if (rot == ROT.rotY)
		{
						
			vect.set(vectY);
			vect.scale(Math.sin(angle/2.0));
			scalar = Math.cos(angle/2.0);	
			quat.set(vect.x, vect.y, vect.z, scalar);		
			
			matr_temp.setIdentity(); 
			matr_temp.set(quat);
			
			matr_temp.transform(vectZ);
			matr_temp.transform(vectX);

			matrix3d.mul(matr_temp);
			tf_koords.set(matrix3d);
		
		}
		
		if (rot == ROT.rotZ)
		{			
			vect.set(vectZ);
			vect.scale(Math.sin(angle/2.0));
			scalar = Math.cos(angle/2.0);	
			quat.set(vect.x, vect.y, vect.z, scalar);

			matr_temp.setIdentity(); 
			matr_temp.set(quat);
			
			matr_temp.transform(vectX);
			matr_temp.transform(vectY);

			matrix3d.mul(matr_temp);
			tf_koords.set(matrix3d);
		}
		
		vectX.normalize();	
		vectY.cross(vectZ, vectX);
		vectY.normalize();	
		vectZ.cross(vectX, vectY);
		vectZ.normalize();

		tg_koords.setTransform(tf_koords);
	}
	
	private void reset()
	{
		vectX.set(1.0, 0.0, 0.0);
		vectY.set(0.0, 1.0, 0.0);
		vectZ.set(0.0, 0.0, 1.0);
		
		matrix3d.setIdentity();
	}

}
```


----------



## Marco13 (14. Dez 2009)

Hmmmm ???:L mit welchen... Aufwänden rechnest du, wenn man jetzt versuchen sollte, daraus ein Beispiel zu machen, wo man den Fehler nachvollziehen kann? 

Schreib' mal überall da, wo bisher
matrix3d.mul(matr_temp);
steht, stattdessen
matrix3d.mul(matr_temp, matrix3d);
hin... *rumrat*


----------



## JavaPhil (14. Dez 2009)

matrix3d.mul(matr_temp, matrix3d); das hat ich schonmal so aber is ja im Grunde das gleiche...

DEr aufwand besteht darín schon en kleines programm zu haben das ein object in nem fenster anzeigt.. und da setzte das object in ne transformgroup und übergibst die dem behavior und natürlich noch boundingsphere setzen...

sollte jeder hinbekommen der mir dabei helfen möchte.

Danke,
Philipp


----------



## Marco13 (14. Dez 2009)

Ein KSKB zu bauen sollte auch jeder hinbekommen, der geholfen bekommen möchte. Meine Zeit ist kostbar. Nur noch so viel: 
matrix3d.mul(matr_temp, matrix3d); 
und
matrix3d.mul(matr_temp); 
ist NICHT das gleiche, es ist grundverschieden, und wenn du glaubst, dass beides das gleiche ist, hast du (unter anderem!) meine erste Antwort nicht berücksichtigt. Es ist ein Unterschied, in welcher Reihenfolge man die Matrizen miteinander multipliziert, weil die Matrizenmultiplikation nicht kummutativ ist.


----------



## JavaPhil (14. Dez 2009)

stimmt... hab die Reihenfolge nicht beachtet   (andersrum wärs aber das selbe)... werd das mal morgen ausprobieren.
Morgen hab ich auch wieder mehr zeit genauer im Forum zu lesen und alles auszuprobieren.

Danke Philipp


----------



## JavaPhil (15. Dez 2009)

Waahhooo

Hattest recht... 

matrix3d.mul(matr_temp, matrix3d); 

und funzt... :applaus::applaus::applaus:



DANKE DANKE DANKE DANKE DANKE DANKE DANKE DANKE DANKE :toll::toll::toll::toll:


----------

