3D: Kugel rotieren

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • 3D: Kugel rotieren

    Joho!

    Also, ich habe aus Tiles (von nun an "Punkte") eine Kugel geformt. Das klappt auch ganz toll, allerdings möchte ich diese rotieren können. Ich habe es bereits mit Kugelkoordinaten probiert, indem ich diese Formeln:

    GML-Quellcode

    1. X = r*sin(a)*cos(b);
    2. Y = r*sin(a)*sin(b);
    3. Z = r*cos(a);

    so erweitert habe:

    GML-Quellcode

    1. X = r*sin(a)*cos(b+ZRotation);
    2. Y = r*sin(a)*sin(b+ZRotation);
    3. Z = r*cos(a);
    (Natürlich habe ich noch mehr herumprobiert. Das ist allerdings das Einzige, das auch wirklich funktioniert, ohne irgendwelche anderen schicken Formen zu formen.)

    Die Positionen der Punkte sind zu Anfang gegeben, sodass sich die Winkel so berechnen lassen:

    GML-Quellcode

    1. a = arccos(Z/r);
    2. b = arctan2(Y, X);


    Wie der Code allerdings vermuten lässt, lässt sich die Kugel nur um eine Achse rotieren: die Z-Achse. Mit folgendem Code habe ich versucht die Punkte um die Y-Achse rotieren zu lassen, allerdings rutschen die Punkte nur kugelförmig rauf und runter:

    GML-Quellcode

    1. X = r*sin(a+YRotation)*cos(b+ZRotation);
    2. Y = r*sin(a+YRotation)*sin(b+ZRotation);
    3. Z = r*cos(a+YRotation);


    Die Suchfunktion habe ich auch bereits benutzt und ähnliche Themen finden können, allerdings konnte ich mein Problem damit nicht lösen.

    Freue mich auf Hilfe.


    Skotchy~
    "Ich sollte schlafen gehen"

    ~Pika-Pika~
  • Hast du beachtet dass die sin() und cos() Funktionen im GM die Winkel in Radianten erwarten?
    Falls du also Winkel (in Grad) an sin() und cos() übergeben möchtest, musst du diese in Radianten umwandeln.
    Dies kann man mithilfe der eingebauten "degtorad()" Funktion machen.
    z.B:

    GML-Quellcode

    1. sin(degtorad(meinWinkel));


    Gib bescheid falls dies dein Problem nicht löst. Werde mir dies dann genauer anschauen.
  • Das, was du vorhast, kann so nicht funktionieren. Wieso? Weil die Rotationen in 3D nicht kommutieren. Das bedeutet: Ob du zuerst um die Z-Achse und dann um die Y-Achse rotierst oder zuerst um die Y-Achse und dann um die Z-Achse macht einen Unterschied. Ich empfehle, das du dir das Konzept einmal klar machst, indem du es einfach mit irgendeinem Quaderförmigen Objekt ausprobierst. Aus diesem Grund kannst du in Kugelkoordinaten nicht einfach so um beliebige Achsen rotieren. Vielmehr hast du in Kugelkoordinaten immer eine "besondere" Achse, um die du einfach rotieren kannst (hier die Z-Achse), für die anderen Achsen sind deutlich kompliziertere Formeln erforderlich.

    Die Lösung des Problems findest du in der linearen Algebra: Siehe de.wikipedia.org/wiki/Drehmatrix.
  • @LEWA: Ja, habe ich. Ich verwende dazu allerdings lieber

    GML-Quellcode

    1. dsin(Winkel);
    2. dcos(Winkel);
    3. dtan(Winkel);

    Mein Problem hat dieser Tipp leider nicht gelöst.
    @boxxar: Auf die Lösung bin ich leider nicht ganz gekommen. Mit Rx(a), Ry(a) und Rz(a) lassen sich die Punkte um die entsprechenden Achsen drehen, allerdings formen sie dann einen Zylinder. Wenn ich versuche die Punkte um eine Ursprungsgerade rotieren zu lassen, mit Rn(a), so formen sie bei mir diese Gerade.
    Meine Formeln dazu sehen so aus (ich zeige mal nur die Rotation um die X-Achse):

    GML-Quellcode

    1. //Rotation um X-Achse
    2. Y = r*(cos(a+XRotation)-sin(a+XRotation));
    3. Z = r*(sin(a+XRotation)+cos(a+XRotation));

    Ursprünglich sahen die Formeln so aus:

    GML-Quellcode

    1. //Rotation um X-Achse //Variante 1
    2. Y = r*(Y*cos(a+XRotation)-Z*sin(a+XRotation));
    3. Z = r*(Y*sin(a+XRotation)+Z*cos(a+XRotation));
    4. //Rotation um X-Achse //Variante 2
    5. Y = r*(StartY*cos(a+XRotation)-StartZ*sin(a+XRotation));
    6. Z = r*(StartY*sin(a+XRotation)+StartZ*cos(a+XRotation));

    Bei beiden Varianten sind die Punkte sehr schnell nicht mehr zu sehen oder fliegen scheinbar wild umher.
    Und noch die Formel mit der Rn(a)-Variante:

    GML-Quellcode

    1. XX = StartX;
    2. YY = StartY;
    3. ZZ = STartZ;
    4. n1 = 1;
    5. n2 = 1;
    6. n3 = 1;
    7. a++;
    8. X = XX*n1*n1*(1-cos(a))+cos(a)
    9. +YY*n1*n2*(1-cos(a))-n3*sin(a)
    10. +ZZ*n1*n3*(1-cos(a))+n2*sin(a);
    11. Y = XX*n2*n1*(1-cos(a))+n3*sin(a)
    12. +YY*n2*n2*(1-cos(a))+cos(a)
    13. +ZZ*n2*n3*(1-cos(a))-n1*sin(a);
    14. Z = XX*n3*n1*(1-cos(a))-n2*sin(a)
    15. +Y*n3*n2*(1-cos(a))+n1*sin(a)
    16. +ZZ*n3*n3*(1-cos(a))+cos(a);
    Alles anzeigen

    So ganz habe ich die Formeln nicht durchblicken können, weshalb ich wohl nicht die gewünschten Ergebnisse erhalte.


    Ich danke euch beiden für eure Hilfe!


    Skotchy~
    "Ich sollte schlafen gehen"

    ~Pika-Pika~
  • So ganz verstehe ich nicht, was genau du zu erreichen versuchst (was genau hast du gegeben und was genau willst du haben?), aber: Du kannst auch die Kugelkoordinaten mit den Drehmatrizen kombinieren. Also zuerst deine Punkte in Kugelkoordinaten erzeugen und dann die Drehmatrizen darauf anwenden, um die gewünschten Rotationen durchzuführen. Die Drehmatrizen machen aus Punkten, die auf einer Kugeloberfläche liegen, wieder Punkte auf der gleichen Kugeloberfläche - vorausgesetzt natürlich, die Kugel hat ihren Mittelpunkt im Koordinatenursprung.
  • Gegeben habe ich Punkte, in kartesischen Koordinaten (x, y, z), die auf einer Kugeloberfläche liegen, sowie den Radius der Kugel. Berechnet werden die Punkte aus dem Koordinatenursprung und werden anschließend verschoben. Diese Punkte möchte ich um eine beliebige Achse rotieren lassen können, damit das Ganze wie eine rotierende Kugel aussieht. Falls es einen Unterschied in der Effizienz macht, ob man mit Kugelkoordinaten oder kartesischen Koordinaten rechnet, dann würde ich die effizientere Variante bevorzugen, da ich möglichst viele Punkte berechnen lassen möchte.
    Kugelkoordinaten und Drehmatrizen sind für mich noch Neuland, weshalb ich mich da noch schwer tue. Ich werde es mir aber morgen noch einmal genauer anschauen. Vielleicht verstehe ich es dann.


    Skotchy~
    "Ich sollte schlafen gehen"

    ~Pika-Pika~
  • So, nach einer kürzeren Pause bin ich wieder da.
    Ich habe es nun soweit hinbekommen, dass ich meine Punkte um alle drei Achsen rotieren lassen kann, ohne das das Objekt (zum testen nun ein Würfel) die Form verliert. Allerdings klappt das immer nur dann, wenn ich vorher um keine andere Achse rotiert habe. Starte ich also das Programm und rotiere um die x-Achse, so verformt sich mein Objekt, wenn ich es dannach um die y-, oder z-Achse rotiere.
    Dazu noch einmal die relevanten Codeausschnitte, dieses mal allerdings so, wie ich sie im GM:S stehen habe:

    GML-Quellcode

    1. // x-Rotation
    2. PointX[i] = 1*PointX[i];
    3. PointY[i] = dcos(Angle_)*Scale+dsin(Angle_)*Scale;
    4. PointZ[i] = -dsin(Angle_)*Scale+dcos(Angle_)*Scale;
    5. // y-Rotation
    6. PointX[i] = dcos(Angle_)*Scale-dsin(Angle_)*Scale;
    7. PointY[i] = 1*PointY[i];
    8. PointZ[i] = dsin(Angle_)*Scale+dcos(Angle_)*Scale;
    9. // z-Rotation
    10. PointX[i] = dcos(Angle_)*Scale-dsin(Angle_)*Scale;
    11. PointY[i] = dsin(Angle_)*Scale+dcos(Angle_)*Scale;
    12. PointZ[i] = 1*PointZ[i];
    Alles anzeigen


    Die Vorzeichen stimmen nicht mit denen aus Wikipedia überein, da ich sie etwas umgestellt habe, um die Rotationen mit der Rechte-Hand-Regel vorhersagen zu können.
    "Angle_" wird für jede Rotation aus einem AngleX, AngleY oder AngleZ berechnet, damit die Punkte im richtigen Quadranten landen.
    "Scale" ist ein Faktor, mit dem ich jede Koordinate jedes Punktes multipliziert habe, um die Form gut zu erkennen, da ich die Punkte, für diesen Test, so per Hand eingegeben habe:

    GML-Quellcode

    1. //...
    2. PointX[i] = -1;
    3. PointY[i] = 1;
    4. PointZ[i] = 1;
    5. i++;
    6. //...


    Aufgerufen werden die Rotationen durch Tastendrücke (keyboard_check()).

    Würde mich über weitere Ratschläge und Hilfe sehr freuen.


    Skotchy~
    "Ich sollte schlafen gehen"

    ~Pika-Pika~
  • Probiers mal folgendermaßen

    um z.B ein Object um die eigene Achse zu rotieren muss es zum Ursprung verschoben werden,... und anschließend wieder zurück.

    Keine Ahnung ob es so klappt,... aber vielleicht hilft dir der Ansatz


    GML-Quellcode

    1. {
    2. d3d_transform_set_translation(100,100,10);
    3. ... dein Code....
    4. d3d_transform_set_identity();
    5. }





    Die Lösung des Problems findest du in der linearen Algebra: Siehe de.wikipedia.org/wiki/Drehmatrix.



    Das ist schonmal der richtige Ansatz.

    Zur Erklärung, es gibt für jede Achse eine 3x3 Drehmatrix oder auch Rotationmatrix genannt
    welche eine Drehung um den Winkel alpha um die jeweilige Achse vollführt.

    Wenn du also ein Objekt hast welches die Koordinaten (x,y,z) besitzt und diese mit der Drehmatix R_x multiplizierst dann bekommst du die neuen Koordinaten.

    Die Rotationsmatrix R_n ist nichts anderes als die Multiplikation der Rotationsmatrix um die X/Y/Z Achse.
    Es gibt deutlich bessere Darstellungen als die in Wiki :P

    Gegebenenfalls könntest die dazu mal en Video anschauen

    Grüßle Blayde
  • Ich hab irgendwie das Gefühl, dass du zwei Dinge vermischst.

    GML-Quellcode

    1. // x-Rotation
    2. PointX[i] = 1*PointX[i];
    3. PointY[i] = dcos(Angle_)*Scale+dsin(Angle_)*Scale;
    4. PointZ[i] = -dsin(Angle_)*Scale+dcos(Angle_)*Scale;

    Die erste Zeile tut gar nichts. Das ist natürlich auch Richtig so: Wenn du um die x-Achse rotierst sollten alle x-Koordinaten unverändert bleiben. Die anderen Zeilen sind merkwürdig. Analysieren wir doch einmal, was genau deine Zeile für Y eigentlich tut:
    Zunächst können wir das "Scale" ausklammern:

    GML-Quellcode

    1. PointY[i] = (dcos(Angle_)+dsin(Angle_))*Scale;

    Was ist die Summe aus Cosinus und Sinus vom gleichen Winkel? Nun, man sollte wissen, dass Summen dieser Form Grundsätzlich wieder einen Cosinus/Sinus ergeben, jedoch im Allgemeinen phasenverschoben und skaliert. Konkret:

    GML-Quellcode

    1. PointY[i] = sqrt(2)*dsin(Angle_ + 45)*Scale;

    Für Z ergibt sich analog:

    GML-Quellcode

    1. PointZ[i] = sqrt(2)*dcos(Angle_ + 45)*Scale;

    D.h. im Prinzip hast du eine Form von Zylinderkoordinaten implementiert. Das war irgendwie nicht Ziel der Übung. Und dieser omniöse Faktor Wurzel 2 dort führt natürlich zu einer gewissen Verzerrung. Zudem hängen deine neuen y- und z-Koordinaten gar nicht von den alten ab! Da kann ja etwas nicht stimmen.

    Wenn du dich nicht mit Matrizrechnung auskennst empfehle ich dringend, dich da irgendwo einzulesen. Das ist wirklich wirklich grundlegend und wichtig für 3D-Programmierung. Und eigentlich nicht so schwierig. So müssten jedenfalls die Transformationen aussehen (am Beispiel für die Rotation um die x-Achse):

    GML-Quellcode

    1. PointX_new[i] = PointX[i];
    2. PointY_new[i] = dcos(Angle_)*PointY[i]-dsin(Angle_)*PointZ[i];
    3. PointZ_new[i] = dsin(Angle_)*PointY[i]+dcos(Angle_)*PointZ[i];
  • Vielen Dank für die Antworten! Es funktioniert soweit alles, wie es soll (und die Formeln ergeben für mich nun auch deutlich mehr Sinn).
    Gibt es da vielleicht ein paar empfehlenswerte Quellen um in die 3D-Programmierung zu finden?


    ~Skotchy
    "Ich sollte schlafen gehen"

    ~Pika-Pika~