3D Rotation in Richtung Koordinate x/y/z



  • Hi Leute,

    ich hab mir folgende Formeln zusammengebastelt, um ein Objekt im 3D Raum auf eine bestimmte Koordinate auszurichten, vielleicht könnte mir die jemand kurz bestätigen, weil ich mir absolut nicht sicher bin ob, ich das mit SIN und COS richtig gemacht habe...

    target ist der Vector/Punkt mit den Zielkoordinaten
    position ist die Position des Objekt, an dem sich die Winkel befinden

    // Hoch runter Rotation
    rot.X = asin((target.Y - position.Y) / (target.getDistanceFrom(position))) * 180.0f / PI + 90;
    // Links Rechts Rotation
    rot.Y = asin((position.X - target.X) / (position.getDistanceFrom(vector3df(target.X, position.Y, target.Z))));
    // Rotation um die eigene Achse
    rot.Z = 0;
    

    Gruß
    Scarabol



  • Also so wie ich das lese willst du die Drehwinkel bestimmen um vom Punkt P (=Position) nach T (=Target) zu schauen.

    Ich glaube aber du musst dich dazu mit dem Thema Rotationsmatizen beschäftigen, denn du musst um ein Objekt zu drehen mindestens zwei seperate Rotationen durchführen, welche man gut mit Matrizen beschreiben kann. Und wenn du mittels den Matrizen eine Gleichung aufbaust und dann die Winkel bestimmst, bin ich mir fast sicher dass dabei etwas anderes herauskommt.

    Die Gleichung müsste ungefähr so aussehen:

    B_a * M_x * M_y = P - T

    B_a = Aktulle Blickrichtung
    M_x = Rotationsmatrix um die X-Achse
    M_y = Rotationsmatrix um die Y-Achse



  • Ich habe es mal nachgerechnet und unter der Annahme das die aktuelle Blickrichtung (=Ausrichtung des Objekts) (1 0 0) war und die Drehung erst um die X-Achse und danach um die Y-Achse erfolgen soll habe ich folgende Winkel herausbekommen:

    phi_x = arcsin(-(T_z - P_z))
    phi_y = arctan2((T_y - P_y)/(T_x - P_x))
    

    Target = T
    Position = P

    Die Winkel sind im Bogenmaß, du kannst sie gerne alle (und nicht wie in deinem Bsp.) ins Gradmaß umwandeln.



  • arctan2 ist wohl der arcus von der 2. Funktion Tangenz oder?

    Wie heißt die Funktion in C++?

    Gruß
    Scarabol



  • Also in der Windows API gibts dazu atan2(). Die Funktion berechnet den normalen Arcustangens. Aber weiterhin berücksichtigt die Funktion dass der Divisor 0 sein kann und gibt dann dementsprechend Pi/2 aus.

    Deswegen muss der Aufruf wohl

    phi_y = atan2((T_y - P_y), (T_x - P_x));
    

    lauten.



  • Scarabol schrieb:

    ich hab mir folgende Formeln zusammengebastelt, um ein Objekt im 3D Raum auf eine bestimmte Koordinate auszurichten, vielleicht könnte mir die jemand kurz bestätigen, weil ich mir absolut nicht sicher bin ob, ich das mit SIN und COS richtig gemacht habe...

    Hallo Scarabol,

    von dem Objekt ist nur die Position gegeben. Eine Position ist nur ein Punkt und der schaut nirgendwo hin, egal wie man ihn dreht. Ich unterstelle mal, dass das Objekt in der Ausgangsstellung achsenparallel zu dem Raum steht. Es bleibt die Frage, welche ausgezeichnete Richtung des Objektsystems soll auf das Target zeigen?

    Scarabol schrieb:

    // Hoch runter Rotation
    rot.X = asin((target.Y - position.Y) / (target.getDistanceFrom(position))) * 180.0f / PI + 90;
    // Links Rechts Rotation
    rot.Y = asin((position.X - target.X) / (position.getDistanceFrom(vector3df(target.X, position.Y, target.Z))));
    // Rotation um die eigene Achse
    rot.Z = 0;
    

    wenn man die x- und z-Positionen für position und target gleich setzt und target.Y<position.Y ist, dann kommt für rot.X und rot.Y 0 heraus. In diesem Fall wird also nichts gedreht und die negative(!) Y-Achse zeigt auf das Target.
    Setzt man hingegen die x- und y-Position gleich, dann kommt für rot.X=90° heraus. In diesem Fall liegen Position und Target übereinander (in Z auseinander) und nach einer Drehung um X um 90° würde die Y-Achse entweder auf das Target zeigen oder vom ihm weg. Folglich stimmt die Gleichung nicht für den allgemeinen Fall.

    Ich nehme mal an, die Y-Achse des Objekts soll auf das Target zeigen.
    Es gibt dazu mehr als eine Möglichkeit der Drehung.
    Ich nehme weiter an, es soll erst um Y und dann um die X-Achse gedreht werden (anders herum macht es keinen Sinn, weil die Y-Achse dann nicht überall hinzeigen kann).

    es sei: delta = target - position;

    zunächst kippt man die Y-Z-Ebene so weit um Y, dass Target in der gekippten Ebene Y-Z' liegt.
    rot.Y = atan(delta.X / delta.Z) // Bem.: Sonderbehandlung falls delta.Z == 0, dann rot.Y=90°

    rot.Y liegt dann im Bereich (-90°,90°], das reicht hier aus.

    Dann dreht man die Y-Achse so weit um die X-Achse, so dass Y auf Target zeigt.
    rot.X = atan2( sqrt( delta.X*delta.X + delta.Z*delta.Z ), delta.Y );

    rot.X liegt im Bereich von (-180°,180°]

    Eine weiter Möglichkeit besteht in der 'direkten Drehung'. Dazu berechnet man die Drehachse aus dem Kreuzprodukt von dir x delta (dir := y ist die Richtung, die nachher auf Target zeigen soll) und den Drehwinkel wieder mit dem atan2:
    rot = atan2( Betrag( dir x delta ), dir * delta ); // der 2.Parameter ist das Skalarprodukt

    Mit der Drehachse und dem Drehwinkel kann man das Objekt jetzt mit einem OpenGL-Rotate auf das Target zeigen lassen.

    Gruß
    Werner



  • Also Leute,

    um das ganze noch ein wenig besser zu umschreiben, dass Objekt ist ein kleines Raumschiff, dessen X Achse nach vorne zeigt, Z-Achse links rechts und Y Achse hoch runter.

    Gruß
    Scarabol



  • .. und welche der Achsen soll auf das Target zeigen, dann doch wohl die X-Achse oder ?
    und Y soll soweit nach oben zeigen, wie möglich?



  • ja, genau!

    Wie mach ich das?

    Gruß
    Scarabol



  • Scarabol schrieb:

    ja, genau!

    Wie mach ich das?

    Im Prinzip wie oben schon beschrieben. Nur die Koordinaterichtungen müssen durchgetauscht werden und mir ist noch eine kleine Verbesserung eingefallen, die die Sonderbehandlung bei Division durch 0 beseitigt.

    Es sei 'delta' der Differenzvektor (target-position).

    1.) Rotiere um Y (Hochachse), so dass die X-Achse in Richtung von (delta.x,0,delta.z) zeigt:
    rotY = atan2( -Z(delta), X(delta) ); // rotY im Bogenmass

    2.) Kippe das Raumschiff um die Z-Achse (Querachse), so dass X auf Target zeigt:
    rotZ = atan2( Y(delta), sqrt(X(delta)*X(delta) + Z(delta)*Z(delta)) ); // rotZ im Bogenmass

    Bem.: rotZ bleibt stehts im Bereich von [-90,90]
    Drehe das Raumschiff erst um Y mit dem Wert rotY und dann um Z mit rotZ.

    da war's schon; in C++ werden atan2 und sqrt durch #include <cmath> im namespace std zur Verfügung gestellt.

    Gruß
    Werner



  • JUHU!!!

    Das is ja megageil meine Raumschiffe fliegen geradeaus!!!

    SUPER DANKE!!!

    Gruß
    Scarabol


Anmelden zum Antworten