Willkürliche Rotation um eine Kugel

12

Ich programmiere eine Mechanik, mit der sich ein Benutzer auf der Oberfläche einer Kugel bewegen kann. Die Position auf der Kugel wird derzeit als thetaund gespeichert phi, wobei thetader Winkel zwischen der z-Achse und der xz-Projektion der aktuellen Position (dh Drehung um die y-Achse) und phider Winkel von der y-Achse zur Position ist. Ich erklärte das schlecht, aber es ist im Wesentlichen theta = yaw,phi = pitch

Vector3 position = new Vector3(0,0,1);
position.X = (float)Math.Sin(phi) * (float)Math.Sin(theta);
position.Y = (float)Math.Sin(phi) * (float)Math.Cos(theta);
position.Z = (float)Math.Cos(phi);
position *= r;

Ich glaube, das ist richtig, aber ich könnte mich irren. Ich muss in der Lage sein, mich in einer beliebigen pseudo-zweidimensionalen Richtung um die Oberfläche einer Kugel am Ursprung des Weltraums mit Radius zu bewegen r. Zum Beispiel Wsollte sich das Halten in Bezug auf die Ausrichtung des Spielers nach oben um die Kugel bewegen.

Ich glaube, ich sollte ein Quaternion verwenden, um die Position / Orientierung auf der Kugel darzustellen, aber ich kann mir nicht vorstellen, wie ich das richtig mache. Die sphärische Geometrie ist nicht meine Stärke.

Im Wesentlichen muss ich den folgenden Block füllen:

public void Move(Direction dir)
{   
    switch (dir)
    {
        case Direction.Left:
            // update quaternion to rotate left
            break;
        case Direction.Right:   
            // update quaternion to rotate right
            break;
        case Direction.Up:
            // update quaternion to rotate upward
            break;
        case Direction.Down:
            // update quaternion to rotate downward
            break;
    }
}
azz
quelle
Was soll passieren, wenn der Spieler die Pole erreicht? Mir ist aufgefallen, dass Sie "aufwärts" geschrieben haben. Bedeuten Sie wörtlich "aufwärts" (dh von der Oberfläche der Kugel weg), "geradeaus" oder "in Richtung Nordpol" (die beiden letzteren sind die gleichen, wenn der Spieler können ihre Ausrichtung nicht ändern und "vor ihnen" oder "oben" auf dem Bildschirm ist immer der Norden)?
Martin Sojka
Vielleicht war es schlecht formuliert. Der Spieler sollte die Oberfläche der Kugel nicht verlassen und sich der Kardinalachse nicht bewusst sein. Wenn Sie sich also "nach oben" bewegen, bewegen Sie sich entlang der Oberfläche der Kugel relativ zur Ausrichtung des Spielers nach oben. Wenn Sie sich bei (r, 0,0) befinden und nach oben drücken, gehen Sie in Richtung des Z + -Pols.
azz
Es bleibt noch eine Frage offen: Kann der Spieler die Ausrichtung ändern ("links" und "rechts" drehen)?
Martin Sojka
Vielleicht ein besseres Beispiel , was ich für: Spieler auf (1,1,1)links hält die Kugel würde drehen sich um, die durch (~1.2,0,~-1.2), dann (-1,-1,-1), dann (~-1.2,0,~1.2)und zurück nach (1,1,1).
azz
1
Wenn Sie immer den Überblick behalten thetaund phiIhre Position aktualisieren möchten, wird Ihr Problem unnötig komplex. Es ist viel einfacher, die 2 Rotationsachsen pro Frame (von denen sich eine (Gier) nie ändert) und Vector3.Transormum die Kugel herum zu berechnen . Dies würde Ihr Problem vereinfachen, aber dazu führen, dass Sie die Verbindung mit phi& trennen theta.
Steve H

Antworten:

5

Tatsächlich stellt sich heraus, dass Sie es nicht in beide Richtungen haben können: wenn Sie nicht die Absicht haben, ein Gefühl der "absoluten Orientierung" auf der Kugel zu haben (dh wenn die Spieler nicht immer z. B. in Richtung der Pole blicken) ), dann müssen Sie eine Vorstellung von der Orientierung des Spielers haben. Dies liegt daran, dass Bewegung auf der Kugel entgegen der Intuition nicht genau wie Bewegung auf einer Ebene ist, auch nicht lokal (ganz); Die intrinsische Krümmung der Kugel bedeutet, dass Spieler Aktionen ausführen können, die sich selbst drehen!

Als extremstes Beispiel für das, worüber ich spreche, stellen Sie sich vor, dass der Spieler an einem Punkt am Äquator beginnt (der Einfachheit halber stellen wir uns ein Ziffernblatt vor, das von oben auf den Äquator abgebildet wird, und stellen Sie den Spieler auf 6 Uhr ), mit dem Gesicht nach oben, dh in Richtung Nordpol. Angenommen, der Spieler geht den ganzen Weg zum Nordpol. dann stehen sie direkt vor dem 12-Uhr-Punkt. Lassen Sie den Spieler nun direkt nach rechts vom Nordpol zurück zum Äquator gehen. Sie landen um 3 Uhr - aber weil sich ihre Ausrichtung nicht ändert, wenn sie sich nach rechts bewegen(die Idee ist, dass sich ihre Ausrichtung nicht ändert, egal wie sie sich bewegen), sie stehen immer noch vor dem 12-Uhr-Punkt - sie stehen jetzt entlang des Äquators! Lassen Sie sie nun "rückwärts" zu ihrem Startpunkt (6 Uhr) zurückkehren. dann sind sie immer noch entlang des Äquators ausgerichtet, so dass sie dem 3-Uhr-Punkt zugewandt sind. Wenn sie sich nur entlang der Kugel bewegen, ohne jemals ihre "persönliche" Ausrichtung zu ändern, drehen sie sich vom Nordpol zum Nordpol mit Blick auf den Äquator! In gewisser Weise ist dies eine Ausarbeitung des alten Witzes "Ein Jäger bewegt sich eine Meile nach Süden, eine Meile nach Westen und dann eine Meile nach Norden" - aber hier nutzen wir die Krümmung der Kugel, um eine Richtungsänderung zu bewirken. Beachten Sie, dass derselbe Effekt auch in viel kleineren Maßstäben auftritt.

Glücklicherweise können Quaternionen (wie Sie selbst bemerkt haben) mit dieser Situation umgehen. Da ein Quaternion eine willkürliche Drehung darstellt, stellt es effektiv einen willkürlichen "Punkt plus Orientierung" auf der Kugel dar. Stellen Sie sich vor, Sie beginnen mit einer "Triaxis" am Ursprung und geben ihr eine willkürliche Drehung, und bewegen dann eine Einheit in die jeweils richtige Richtung der gedrehten Achsen. Z-Achsenpunkte; Ein kleiner Gedanke wird Sie überzeugen, dass dies Sie zu einem Punkt auf der Einheitskugel mit einer gewissen "Orientierung" (dh einer gewissen Anordnung der X - und Y - Achse Ihrer Triaxis) bringt und dass Sie zu jedem Punkt + Orientierung auf der Einheit Kugel auf diese Weise (weisen Sie einfach Ihre Z-Achse zu, um entlang der Linie vom Ursprung durch Ihren Punkt auf der Kugel zu zeigen, und transportieren Sie dann Ihre Triaxe entlang dieser Linie zurück zum Ursprung). Was ist mehr, Da die Multiplikation von Quaternionen der Zusammensetzung von Rotationen entspricht, kann jede der von Ihnen beschriebenen Operationen durch Multiplikation Ihrer 'aktuellen Orientierung' mit einer entsprechend ausgewählten Quaternion dargestellt werden: Insbesondere, da die (Einheits-) Quaternion (qx, qy, qz, qw) bedeutet "um die Achse (qx, qy, qz) um Arccos (qw) drehen", dann (abhängig von Ihrer spezifischen Wahl des Koordinatensystems, und c_a sei cos (alpha) und s_a sei sin (alpha)) zwei der Die drei Quaternionen M_x = (s_a, 0, 0, c_a), M_y = (0, s_a, 0, c_a) und M_z = (0, 0, s_a, c_a) repräsentieren die Drehung (dh Bewegung) in Richtung I "Ich bin gerade mit Alpha konfrontiert" und "Drehe in einer Richtung, die orthogonal zu der ist, der ich gerade mit Alpha konfrontiert bin". (Das dritte dieser Quaternionen steht für "Rotiere meinen Charakter um seine eigene Achse".)Cur_q = M_x * Cur_qwenn der Spieler gedrückt hat oder Cur_q = M_y * Cur_qwenn der Spieler nach rechts gedrückt hat (oder möglicherweise so ähnlich, Cur_q = M_yinv * Cur_qwenn der Spieler nach links gedrückt hat, wobei M_yinv das 'Inverse' der M_y-Quaternion ist und eine Rotation in die andere Richtung darstellt). Beachten Sie, dass Sie darauf achten müssen, auf welcher Seite Sie die Rotation anwenden, ob vor oder nach der Multiplikation. Um ehrlich zu sein, ist es vielleicht am einfachsten, dies durch Ausprobieren zu lösen, indem man sowohl Multiplikationen versucht als auch sieht, was funktioniert.

Der Übergang von Ihrer aktualisierten Quaternion zu einem Punkt auf der Kugel (und zu einer Ausrichtung Ihres Charakters) ist ebenfalls relativ einfach: Nach der Entsprechung des letzten Absatzes müssen Sie Ihre Quaternion nur auf Basis von Vektoren verwenden (1, 2). 0,0), (0,1,0) und (0,0,1) Ihres Frames über die Operation 'Vektor um Quaternion drehen' v → qvq -1 (wobei die Multiplikationen hier Quaternion-Multiplikationen sind und wir den Vektor v identifizieren) = (x, y, z) mit der 'entarteten Quaternion' (x, y, z, 0)). Zum Beispiel wird die Position auf der Einheitskugel durch einfaches Transformieren des z-Vektors erhalten: pos = (qx, qy, qz, qw) * (0, 0, 1, 0) * (-qx, -qy, -qz, qw) = (qx, qy, qz, qw) * (qy, -qx, qw, qz) = (2 (qy * qw + qz * qx), 2 (qz * qy-qw * qx), (qz ^ 2 + qw ^ 2) - (qx ^ 2 + qy ^ 2), 0), also(2(qy*qw+qz*qx), 2(qz*qy-qw*qx), (qz^2+qw^2)-(qx^2+qy^2))wären die Koordinaten des 'transformierten' Benutzers auf der Einheitskugel (und um die Koordinaten auf einer beliebigen Kugel zu erhalten, multiplizieren Sie diese natürlich einfach mit dem Radius der Kugel); Ähnliche Berechnungen funktionieren für die anderen Achsen, um z. B. die Blickrichtung des Benutzers zu definieren.

Steven Stadnicki
quelle
Genau das, was ich erreichen will. Ich konnte mir einfach nicht vorstellen, wie ich eine Position aus der Orientierungsfrage herausholen könnte. Mit dem, was Sie angegeben haben, kann ich die Move()Prozedur schreiben , aber um die normalisierte Achse (dh meine Position) zu erhalten, würde ich einfach nehmen (sin(qx),sin(qy),sin(qw)) * r?
Azz
@Der nicht genau - Ich werde meinen Beitrag mit den Details aktualisieren, aber die Kurzversion ist, dass Sie Ihre Quaternion verwenden, um einen Einheitsvektor, z. B. (0,0,1), mit dem üblichen v -> qvq <sup> zu transformieren -1 Operation; Die Tatsache, dass Sie einen einfachen Vektor transformieren, bedeutet (natürlich), dass es hier eine Abkürzung gibt, aber die Endkoordinaten sind in den Werten Ihrer Quaternion quadratisch und nicht linear.
Steven Stadnicki
1

Ich denke, Sie möchten etwas Ähnliches wie http://www.youtube.com/watch?v=L2YRZbRSD1k

Ich habe das für einen 48h Gamejam entwickelt ... Du kannst den Code hier herunterladen ... http://archive.globalgamejam.org/2011/evil-god

Ich habe etwas Ähnliches wie Ihren Code verwendet, um die 3D-Koordinaten zu ermitteln ... aber ich habe den Planeten gedreht und der Spieler befand sich in derselben Position. Ich glaube, Sie interessieren sich für die Kreaturenbewegung.

    // To add movement
    protected override void LocalUpdate(float seconds)
    {
        Creature.Alfa += Direction.X * seconds * Speed;
        Creature.Beta += Direction.Y * seconds * Speed;            
    }


    // To calculate position
       World.Planet.GetCartesian(Alfa, Beta, out Position); // as you do
       Matrix PositionMatrix = Matrix.CreateTranslation(Position) * World.Planet.RotationMatrix;           
       LastPositionAbsolute = PositionAbsolute;
       Vector3 Up = PositionAbsolute = Vector3.Transform(Vector3.Zero, PositionMatrix);           
       Up.Normalize();
       // This is to add and offset to the creature model position
       PositionAbsolute += Up * 8;  
      // calculate new forward vector if needed

       if ((PositionAbsolute - LastPositionAbsolute).Length() > 0.1f) {
           Forward = PositionAbsolute - LastPositionAbsolute;
           Forward.Normalize();
       }

       // Calculate the world transform with position, forward vector and up vector
       Matrix LocalWorld = Matrix.CreateWorld(PositionAbsolute, Forward, Up); 

       Transform = Matrix.CreateScale(Scale * ScaleFactor) * LocalWorld;
Blau
quelle