Quaternions - Rotation zurück setzen

Einstiegsfragen, Mathematik, Physik, künstliche Intelligenz, Engine Design
Antworten
Northwind877
Beiträge: 5
Registriert: 19.09.2011, 22:24

Quaternions - Rotation zurück setzen

Beitrag von Northwind877 »

Hallo Community,

ich habe ein Problem mit den Quaternions. Ich versuche gerade eine Steuerung für mein Flug-Spiel zu programmieren, dabei möchte ich im Prinzip eine Steuerung wie bei dem Spiel Star Wars Rogue Squadron (http://www.youtube.com/watch?v=_cbR_ZTCzFY) implementieren.

Wenn man zum Beispiel nach links fliegt, soll sich der Flieger um die Y-Achse drehen und zugleich auch etwas um die z-Achse drehen. Also sich in die Kurve rollen.
Lässt man die Taste wieder aus, soll sich der Flieger wieder gerade drehen (Z-Achse = 0).

Das Fliegen in alle Richtungen funktioniert schon mal ganz gut! Ich zeige euch hier mal den Code dazu:

Code: Alles auswählen

 
  		float r = Input.GetAxis("Horizontal")*rollSpeed*Time.deltaTime;
		float p = Input.GetAxis("Vertical")*pitchSpeed*Time.deltaTime;
	
		Quaternion rotZ = Quaternion.AngleAxis(r,new Vector3(0,0,1));
		Quaternion rotY = Quaternion.AngleAxis(r,new Vector3(0,1,0));
   		Quaternion rotX = Quaternion.AngleAxis(p,new Vector3(1,0,0));
		
		transform.rotation *=   rotZ;
		transform.rotation  =   rotY * transform.rotation; // um world achsen drehen
		transform.rotation *=   rotX; //lokal drehen
Damit kann ich breites Loopings machen, links/rechts fliegen und er dreht sich auch in der Kurve! Jedoch fehlt mir jetzt noch das zurück drehen in die z-Achse. Ich habe bereits eine Lösung, leider funktioniert sie jedoch nicht so wie sie sollte:

Code: Alles auswählen

  //hier ist das problem, soll den flieger in z-Achse wieder zurück drehen
		Quaternion rotBack = transform.rotation;
		Vector3 tempRotBack = rotBack.eulerAngles;
		rotBack = Quaternion.Euler(tempRotBack.x,tempRotBack.y,0); //funktioniert auch
		transform.rotation = Quaternion.Lerp(transform.rotation, rotBack, 0.03f);
Das zurück drehen der Z-Achse(roll=0) damit der Flieger wieder gerade ist funktioniert damit gut. Jedoch funktioniert damit der Looping nicht mehr... Wenn man jetzt nach oben fliegt und bei ca. der Wende ankommt, dreht sich der Flieger plötzlich nur mehr um die y-Achse. Irgendwie scheint es, als hätte ich einen Freiheitsgrad oder so durch die Euler-Winkel verloren.

Habt ihr eine Ahnung was ich falsch mache? Ich kenne mich leider mit Quaternions noch nicht so gut aus... Gibt es eine einfache Möglichkeit wie ich den z-Wert eines Quaternions auf der z-Achse nach 0 drehen kann? Mit der Methode Quaternion.AngleAxis(..) kann man leider immer nur einen Winkel angeben um den man sich weiter drehen möchte.

Würde mich freuen wenn ihr mir helfen könnt! :) Danke schon mal.

Liebe Grüße,
Northwind877
Benutzeravatar
joeydee
Establishment
Beiträge: 1119
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Quaternions - Rotation zurück setzen

Beitrag von joeydee »

Also gleichzeitig eigenstabil und Loopingfähig? Und ganz oben im Looping soll die "richtige" Lage auf dem Kopf sein, nehme ich an? Wie würdest du denn zu einem bestimmten Zeitpunkt "über Kopf" unterscheiden, ob sich der Flieger gerade in einem Looping oder einer Rolle befindet?
Und wie würdest du denn "zurückrollen" bei 90 bzw. 270 Grad des Loopings (Nase senkrecht nach oben/unten) definieren?

Ich könnte mir da nur eine Fallunterscheidung bzw. Gewichtung des Effekts denken, der sich aufhebt je mehr die Flugzeugnase in die Senkrechte geht, und der sich umkehrt wenn der up-Vektor mehr als 90 Grad kippt ("kentern" beim Rollen wie eine Eskimorolle). Geeignete Wichtungen und Vorzeichen kann man hier über die Skalarprodukte von lokalen und globalen Vektoren finden, denke ich.
Benutzeravatar
joeydee
Establishment
Beiträge: 1119
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Quaternions - Rotation zurück setzen

Beitrag von joeydee »

Hab grad mal einen kleinen Test gemacht, wie man sowas auf die beschriebene Weise hinbiegen könnte.
Es werden nur x- und z-Achse vom User gesteuert (WASD in der Demo bzw. Maus), dann pro Frame die aktuelle Lage ermittelt und daraus Korrekturwerte für jede Achse berechnet (s. Codeausschnitt). Die Zusammenhänge sind rein empirisch entstanden, die Namen daher auch nicht unbedingt gut gewählt.
Wie gesagt, es kommt zuerst auf deine genaue Definition an, was überhaupt in jeder erdenklichen Fluglage passieren soll. Das hier ist daher nur eine denkbare Lösung, aber vielleicht kannst du daraus was basteln was deinen Vorstellungen nahekommt.

Code: Alles auswählen

	var curve:Number=cam.right.y;//==dot(cam.x*world.y)
	var updown:Number=cam.up.y;//==dot(cam.y*world.y)
	var vertical:Number=cam.front.y;//==dot(cam.z,world.y)
	var horizon:Number=1-Math.abs(vertical);//zero in vertical flight
	var eskimo=curve*horizon;
	
	//rotation values around...
	var pitch:Number=-0.3;//...x-axis while upside down
	if(updown>0)pitch=vertical*updown*0.3;//...x-axis while upright
	var roll:Number=-eskimo;//...z-axis
	var heading:Number=-eskimo*updown;//...y-axis
flightsim.swf
(36.3 KiB) 3500-mal heruntergeladen
Northwind877
Beiträge: 5
Registriert: 19.09.2011, 22:24

Re: Quaternions - Rotation zurück setzen

Beitrag von Northwind877 »

Zuerst mal vielen Dank für die sehr ausführliche Antwort. Mit einer zusätzlichen Demo hätte ich echt nicht gerechnet :)
Leider verstehe ich es aber noch nicht ganz! Mir ist jetzt klar, dass ich im Looping das selbe Quaternion wie bei der Rolle bekomme und somit Rolle von Looping Unterscheiden muss.

Bei deinem Test dreht sich die Kamera/Flieger beim hochsehen bzw. beim nach oben fliegen (Rotations-Achse x) ebenfalls wieder zurück. Ich hätte es gerne so, dass er sich nur um die z-Achse wieder zurück rotiert.
Wie geht denn das mit der Unterscheidung genau? Wenn ich zum Beispiel stark nach oben fliege, sollte horizon im vertikalen den Wert 0 bekommen. Soll ich dann ab diesem Zeitpunkt einfach kein zurück drehen in die z-Achse mehr erlauben?

Code: Alles auswählen

var horizon:Number=1-Math.abs(vertical);//zero in vertical flight
var eskimo=curve*horizon;
Bedeutet das: wenn man vertikal fliegt, dass die Eskimo-Rolle einfach keine Rotation mehr enthält?

Vielen Dank nochmals für die Hilfe!
Benutzeravatar
joeydee
Establishment
Beiträge: 1119
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Quaternions - Rotation zurück setzen

Beitrag von joeydee »

Nichts zu danken; die Demo fiel deshalb leicht, weil ich mir inzwischen ein kleines Flash-Framework für genau solche 3D-Experimente aufgebaut habe und in letzter Zeit auch selbst einiges mit 6DOF-Steuerung gemacht habe.
Bei solchen Themen ist es sowieso schwierig, Tipps zu geben, die man nicht selbst in der Praxis getestet hat.

Ja du hast es richtig erfasst: je senkrechter man steht, desto weniger ist der Einfluss des Zurückrollens. Denn wie schon erwähnt: wohin ist denn "zurückrollen", wenn man senkrecht steht? Normalerweise in Richtung des Bodens, aber diese Richtung fällt in diesem Fall mit der Drehachse zusammen, und "zurück" ist damit nicht mehr eindeutig definiert. Versuche dir das zu veranschaulichen.
Entsprechende Arcade-Steuerungen vermeiden dies, indem sie kritische Fluglagen einfach von vornherein verhindern. Wenn du aber Loopings fliegen willst, kommst du zwangsläufig in diese Situationen. Das ist auch keine Eigenart von Quaternionen, sondern liegt in der Definition.
Bei den Überlegungen zu meiner Demo bin ich von einem Hochdecker in Atmosphäre mit Schwerkraft ausgegangen (was die Reaktionen auf die Achsen in bestimmten Fluglagen betrifft). Daher auch die pitch-Korrektur. Kannst du auch weglassen. Er versucht sich auch über Kopf wieder zurückzurollen, um wieder aufrecht zu fliegen. Soll er stattdessen auch über Kopf parallel zum Horizont "einrasten", muss man roll umkehren, sobald man auf dem Rücken liegt (diese Info steckt in updown), z.B. var roll:Number=eskimo*-updown; wollte ich der Vollständigkeit halber nochmal erwähnen.
Noch zur Frage wie das mit der Unterscheidung geht: statt if multipliziere ich einfach einen Faktor in den Term, der durch sein Vorzeichen den Effekt um- bzw. bei 0 ausschaltet. Dadurch gibt es nicht nur Bereiche mit positivem oder negativem Effekt, sondern dazwischen auch welche mit fast oder gar keinem.

Wenn du eine völlige Freiflug-Simulation in Schwerelosigkeit mit Zurückrollen willst, musst du irgendwie definieren, wo "zurück" in jedem beliebigen Augenblick ist, denn die World-Vektoren dürfen dann keine Rolle mehr spielen ("unten" ist nicht definiert). Evtl. wäre eine Möglichkeit, einen veränderlichen "Boden"-Vektor mitzuführen welcher sich immer ganz leicht der aktuellen Fluglage anpasst.

In welche Richtung solls denn gehen? Eher Landschaft mit Gravitation oder eher Schwerelosigkeit?
Antworten