[gelöst und getestet] Kreiskoordinaten in 3D-Engine
-
Hallo,
ja, auch ich schreibe (wie tausende andere die ich auf Google gefunden habe) eine kleine 3D-Engine in OpenGL. Aber bevor ich nun die Frage nach dem "Warum" höre: Bei mir ist nur der Weg das Ziel. Ich brauche keine Multi-Plattform für X-Box und Wii und meine Engine wird weder berühmt noch macht sie mich reich. Ich will einfach nur lernen, wie man sich im 3D-Raum bewegt, dabei was zeichnet und sich in diesem Raum bewegt.Mein Problem ist eine Vektorenverschiebung, bzw. Kreiskooridnaten. Ich hab mir einiges an Tuts angeschaut und schon vieles daraus gelernt.
Ich bewege meine Cam-Klasse durch den Raum anhand von einer Point-Klasse. Die Point-Klasse enthält einfach gesagt nur X, Y und Z (jeweils als float).
Jetzt möchte ich die Position der Cam verschieben und dazu habe ich eine Vector-Klasse. Diese enthält drei Werte (auch float). Winkel A, Winkel B und Länge L.
Wenn ich im Koordinaten-System auf dem Null-Punkt bin, ist Winkel A, der Winkel, der flach auf dem Boden liegt und sich nach rechts dreht.
Winkel B ist der Winkel, der sich nach oben bewegt und Länge L ist nun die Strecke, die ich zurück legen möchte.Ich brauche nun 2 Funktionen in meinem C++. Einmal muss ich mir die Koordinaten X, Y und Z anhand von meinen A, B und L ausrechnen. Und natürlich brauche ich auch den Rückweg (A, B und L anhand von X, Y und Z ausrechnen).
void FromXYZtoABL(float X, float Y, float Z) { A = ???; B = ???; L = ???; } void FromABLtoXYZ(float A, float B, float L) { X = ???; Y = ???; Z = ???; }
Ich hab mich schon so weit vorgearbeitet, dass ich Kreiskoordinaten berechnen muss. Auch in Wikipedia schon viele viele Formeln und mathematische Zeichen gefunden. Aber leider blicke ich das ganze nicht so richtig.
Daher bitte ich um Hilfe. Vielleicht kann mir jemand die Formeln kurz schreiben und auch noch kurz erklären, wie und wo man sich zu dem Thema schlau machen kann. Denn nach wie vor gilt für mich: Der Weg ist das Ziel, und nur die Formeln bringen mich zwar theoretisch vorwärts, aber "ich hab ja dann nichts gelernt".
Vielen Dank,
Stefan
-
Da hast du ein Problem, denn das was auf Wikipedia steht, ist schon die einfachstmögliche Form. Was macht dir denn dabei Schwierigkeiten? Sind doch bloß ein paar trigonometrische Funktionen.
Denk übrigens daran, dass eine Kamera auch noch eine Blickrichtung hat.
Um mal deinen Code auszufüllen:
void FromXYZtoABL(float X, float Y, float Z) { Phi = atan2(y,x); Theta = acos(z/sqrt(x*x + y*y +z*z)); r = sqrt(x*x + y*y +z*z); } void FromABLtoXYZ(float Phi, float Theta, float r) { X = r*sin(theta)*cos(phi); Y = r*cos(theta)*sin(phi); Z = r*cos(theta); }
Dabei habe ich mir die Freiheit genommen, A B und L ihre üblichen Namen zu geben und A dreht sich linksrum, wie es sich in der Mathematik gehört. Wo genau hast du denn Schwierigkeiten?
-
Vielen Dank schon mal.
http://de.wikipedia.org/wiki/Polarkoordinaten
Das war die Seite, die mir ein Mathematiker empfohlen hatte. Und wenn man jetzt nicht umbedingt auch einer ist, dann sieht man sehr viele Zeichen und Variablen und weiß nicht so recht, wo man nun ansetzten soll.
Ich dachte nun, es gibt doch sicherlich ein paar Tuts, die "nichts so mathematisch" sind, sondern eher etwas "programmiererfreundlicher".
Die Blickrichtung meiner Kamera hat im ersten Moment mit meinen Koordinaten nichts zu tun. Die Blickrichtung ist unabhängig davon in drei Winkeln A, B und C gespeichert. (A = Drehung auf der X-Achse, B = Drehung auf der Y-Achse, C = Drehung auf der Z-Achse).
Eine Verschiebung würde also erst mal die Cam drehen in die Blickrichtung (Winkel Phi und Theta), den passenden C raus suchen(je nachdem was man braucht sieht das evlt. anders aus) und dann um den Vector verschieben.
Ich hab das deswegen getrennt, weil ich evtl. eine "Verfolgercam" brauche und der Blickwinkel immer fest definiert ist, aber die Position der Cam dann immer ObjektXYZ + VectorABL = CamXYZ ist.Ist meine erste Engine.
Aber zurück zum Thema. Hast du evtl. eine Seite, die mir das mit den Koordinaten und den schönen Formeln etwas "programmiererfreundlicher" erklären kann?
EDIT: Rechtschreibung...*g*
-
Also schonmal um Längen besser erklärt ist das auf der Hauptseite zu Kugelkoordinaten:
http://de.wikipedia.org/wiki/KugelkoordinatenWas verstehst du denn unter programmiererfreundlicher? Ich bin Programmierer und finde das gut genug erklärt. Brauchst du vielleicht allgemeinere Hilfe zu Koordinatentransformation und Bewegung im 3D-Raum? Ich weiß nicht, welchen Kenntnisstand du hast und deshalb auch nicht, was du als Erklärung brauchst.
-
Hallo,
den Link werde ich mir mal in Ruhe geben. Ich glaube mein Problem ist ganz einfach: Mathe war das letzte mal in der 10ten Klasse Realschule und das ist schon fast 10 Jahre her. Also sollte ich ordentlich Mathe-Nachhilfe nehmen und mal wieder in den Grundzügen von Koordinatensystemen und Geometrie fit zu werden.Ich danke dir schon mal bis hier hin.
Bisher habe ich halt nur Datenbanken (viele SQLs), Dateiausgaben (RTF, CSV, XML, HTML, etc), Netzwerke und Musik verarbeitet. OpenGL und solche Dinge sind absolutes Neuland. Es ist das erste Mal, dass ich mich zusammen in C++ mich mit dem Thema auseinander setze. Vielleicht sollte ich mal eine Arbeitsgemeinschaft "Lerne OpenGl und 3D-Engine zusammen mit Stefan" gründen und andere in meinen Quelltext blicken lassen. Ich bin mir sicher, da würde so mancher Mathematiker und so mancher erfahrene Programmierer den Kopf schütteln und sagen: "Mensch, das geht doch besser und schnell...". Tja, das Leid eines Anfängers. Leider sagt meine Erfahrung, dass kein (wirklicher) Profi die Zeit hat, einen NewBee (*g*) hier zu helfen.
Also werde ich weiter meine Bücher und Tuts lesen und bin froh um Leute wie dich, die sich die Zeit nehmen mal kurz was zu posten. Danke nochmal.
So...und jetzt suche ich mal nach nen ordentlichen Mathe-Buch.
-
Hallo,
ich habe nun folgendes in meine Klasse geschrieben:namespace S3DTypes { class Vector { public: // Angel S3DTypes::Angle Phi; // Der am Boden S3DTypes::Angle Theta; // Der nach oben // Entfernung S3DTypes::Length R; /* Punkte */ // Punkt zurück geben S3DTypes::Point PointGet() const; // von Punkte setzen void SetFromPoint(const S3DTypes::Point& point); }; }; /* Punkte */ // Punkt zurück geben S3DTypes::Point S3DTypes::Vector::PointGet() const { S3DTypes::Point toret; toret.ZSet(R * sin(Theta) * cos(Phi)); toret.YSet(R * cos(Theta) * sin(Phi)); toret.ZSet(R * cos(Theta)); return toret; } // von Punkte setzen void S3DTypes::Vector::SetFromPoint(const S3DTypes::Point& point) { Phi = atan2(point.YGet(),point.XGet()); Theta = acos(point.ZGet() / sqrt(point.XGet()*point.XGet() + point.YGet()*point.YGet() + point.ZGet()*point.ZGet())); R = sqrt(point.XGet()*point.XGet() + point.YGet()*point.YGet() + point.ZGet()*point.ZGet()); } void TestIt () { // Tests S3DTypes::Vector ToMove; S3DTypes::Point ToPoint; ToMove.R=1; ToPoint=ToMove.PointGet(); // X:0, Y:0, Z:1 // X-Achse ToMove.Phi = 15; ToPoint=ToMove.PointGet(); // X:0, Y:0.6502878, Z: 1 }
Wenn ich das richtig verstanden habe, ist ja Phi, der Winkel, der linksrum am Boden dreht. Wieso ist aber wenn ich Phi drehe die Bewegung auf der Z-Achse immer noch 1? Dir müsste doch kleiner als 1 sein, weil ja auch auf Y gewandert wird, oder?
-
stefanjann schrieb:
Wenn ich das richtig verstanden habe, ist ja Phi, der Winkel, der linksrum am Boden dreht. Wieso ist aber wenn ich Phi drehe die Bewegung auf der Z-Achse immer noch 1? Dir müsste doch kleiner als 1 sein, weil ja auch auf Y gewandert wird, oder?
Wieso sollte sich meine z-Position ändern, wenn ich mich in der xy-Ebene drehe? Das wäre ja so als ob mein Kopf höher oder tiefer wäre nachdem ich mich um mich selbst drehe.
-
Ich glaub ich peils gerade gar nicht.
Ich fasse mal kurz zusammen:ich habe ein Koordinatensystem mit 3 Ebenen:
Die X-Achse bewegt mich nach links und nach rechts.
Die Y-Achse bewegt nicht nach oben und nach unten.
Die Z-Achse bewegt mich nach vorne und nach hinten.Ich stehe am Null-Punkt und schaue in die ferne (Richtung Z Plus).
Ich drehe mich um 15° nach links und mache einen Schritt vor.
Dann müsste ich mich ja auch X nach links und auf Z nach vorne bewegen, oder?
Wenn ich nun bei mir
ToMove.R=1; ToMove.Phi = 15;
mache, dann müsste ich doch eigentlich eine negative X-Zahl und eine positive Z-Zahl bekommen. Die X müsste zwischen 0 und -1 liegen und die Z zwischen 0 und 1.
Hab ich das soweit verstanden?
Also kann eigentlich an der Formel:
Z = R * cos(Theta)
was nicht stimmen. Bzw. die Formel stimmt sicherlich, nur ist das dann nicht die Formel, die ich brauche, weil bei mir dann Z immer 1 ist?!?!
Ich weiß, ich bin da noch viel zu wenig durchgestiegen. Wo liegt denn mein Denkfehler?
-
Arggh
, jetzt sehe ich's. Ich habe mich leider vertippt bei den Formeln:
X = r*sin(theta)*cos(phi); Y = r*[b]sin[/b](theta)*sin(phi); Z = r*cos(theta);
Entschuldigung für die Unannehmlichkeiten.
-
Hallo,
keine Entschuldigung nötig. Jede Hilfe ist recht und irren ist menschlich.Aber leider klappt auch das noch nicht. Also habe ich mal nach alternativen Ideen gesucht. Ich bin im Geiste in meine Schulzeit zurück gegangen und habe mir die Wege und die Formen die ich berechnen möchte einfach mal aufgezeichnet und bin dahinter gekommen, dass ich eigentlich "nur" zwei rechtwinklige Dreiecke berechnen muss, die aneinander hängen.
Ähnlich dem folgenden:La Ld +------- +------- | / | / |Lb / | / | / Lc Lc | / R | / | / |A/ |B/ |/ |/
Die Bezeichnungen sind natürlich frei gewählt und haben keinerlei mathematischen Bezug, weil ich ja die mathematischen Begriffe nicht kenne.
Das linke Dreieck ist das Dreieck, dass am Boden liegt und das rechte Dreieckt ist das, dass auf dem anderen steht.
Und jetzt Formelsammlung aus der 10. Klasse raus und nach Pytagoras gesucht (und auch Google benutzt).
a²=b²+c² sin(alpha) = Gegenkathete / Hypotenuse
Ein bisschen Mathematik und Formeln umstellen und schon hatte ich ein paar Formeln erarbeitet. Allerdings arbeite ich ja mit mehr als 90°-Winkeln, also habe ich noch ein bisschen Ausgleich betrieben. Folgende Funktion ist dabei rausgekommen.
/* Punkte */ // Punkt zurück geben S3DTypes::Point S3DTypes::Vector::PointGet() const { S3DTypes::Point toret; float Ld = sin(B.GetRad()) * L; float Lc = sqrt((L*L) - (Ld*Ld)); float La = sin(A.GetRad()) * Lc; float Lb = sqrt((Lc*Lc) - (La*La)); // Ausgleich für negative if ((A>90) && (A<=270)) { Lb*=-1; } if ((B>90) && (B<=270)) { Lb*=-1; } toret.XSet(La); toret.YSet(Ld); toret.ZSet(Lb); return toret; }
Ich hab auch wieder meine Winkelnamen A,B und L angenommen um Ähnlichkeiten und Verwechslungen durch bekannte mathematische Begriffe zu vermeiden. Denn mein Koordinatensystem ist nicht linksrum, sondern rechtsrum angelegt. Also A dreht nach rechts und B dreht nach oben.
Die Rechnung von Koordinaten auf die Winkel plus Länge hab ich noch nicht, wird aber wahrscheinlich genauso gehen.
Einen schlimmen Anfängerfehler hab ich auch noch gemacht. Ich rechne mit meinen Winkeln immer in 360°. sin, cos und Freunde denken allerdings anders. Daher auch die Funktion GetRad();
#ifndef M_PIf #define M_PIf 3.1415926535897932384626433832795f #endif float S3DTypes::Angle::GetRad() const { return 2.0f * M_PIf * (InAngle / 360.0f); }
Danke nochmal allen die sich hier mit mir (und über mich) einen Kopf gemacht haben. Ich habe mein Projekt jetzt auch öffentlich gestellt. Vielleicht findet sich ja jemand, der ein bisschen mitprogrammieren möchte. (siehe meine Signatur)
Denn auch wenn hier Kugelkoordinaten nicht mein Weg waren, ich hab viel über Kreise und Kugeln gelernt. (Und eine Bemerkung am Rande: Wikipedia weiß nicht alles!)