hi,
bin noch sehr neu in der ganzen sache und habe ein problem mit dem im 3. tutorial (zu OpenGL mit dem header von delphigl) beschriebenem "Sonnensystem".
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
glTranslatef(0,0,0);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0); glVertex3f(-1,-1,0);
glColor3f(0,0,1); glVertex3f(1,-1,0);
glColor3f(0,1,0); glVertex3f(0,1,0);
glEnd();
glRotatef(4,0,1,0);
glPushMatrix();
glTranslatef(3,0,0);
glRotatef(90,0,1,0);
glScalef(0.45,0.45,0.45);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0); glVertex3f(-1,-1,0);
glColor3f(0,0,1); glVertex3f(1,-1,0);
glColor3f(0,1,0); glVertex3f(0,1,0);
glEnd();
glTranslatef(1,0,0.5);
glScalef(0.3,0.3,0.3);
glBegin(GL_TRIANGLES);
glColor3f(1,0,0); glVertex3f(-1,-1,0);
glColor3f(0,0,1); glVertex3f(1,-1,0);
glColor3f(0,1,0); glVertex3f(0,1,0);
glEnd();
glPopMatrix();
SwapBuffers(DC);
end;
end.
Die 3 Dreiecke rotieren bereits um den mittelpunkt, nur leider rotieren die beiden kleineren halt nicht um sich selbst.
das liegt wohl daran, dass die alte matrix mit glPopMatrix(); wieder geladen wird. wenn ich das allerdings nicht mache, dann entfernt sich das ganze wegen glRotatef(4,0,1,0); immer weiter.
wie lässt sich sowas am besten richtig erledigen?
danke,
mfg Redfly
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hallo Redfly,
Zitat:
und habe ein problem mit dem im 3. tutorial (zu OpenGL mit dem header von delphigl) beschriebenem "Sonnensystem"
Das ist dort beschrieben - ehrlich?
Zitat:
wie lässt sich sowas am besten richtig erledigen?
z.B. so:
1. Initialisierungen (am besten im OnCreate)
Code:
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);// Tiefentest aktivieren
glDisable(GL_CULL_FACE);// Culling abschalten
Angle:=0;// Rotationswinkel auf Null setzen
2. Form zeichnen
Code:
Procedure RenderShape;
Begin
glBegin(GL_TRIANGLES);
glVertex3f(-1,-1,0);
glVertex3f(+1,-1,0);
glVertex3f(0,+1,0);
glEnd;
End;
3.Renderprozedur
Code:
// KAMERA
glTranslatef(0,0,-5);// Kameramatrix befüllen
glPushMatrix;// Kameramatrix sichern
// SONNE
glRotatef(Angle,0,1,0);// Matrix ändern: Drehen um die eigene Achse
glColor3ub(255,255,0);// Farbe Gelb setzen (schließlich soll es die Sonne sein)
RenderShape;// Figur zeichnen
// PLANET 1
glPopMatrix;// 8. Kameramatrix wiederherstellen
glPushMatrix;// 7. Kameramatrix sichern
glRotatef(Angle,0,1,0);// 6. Matrix ändern: Drehen um die Sonne
glTranslatef(2,0,0);// 5. Matrix ändern: Aus dem Ursprung schieben (von der Sonne weg)
glRotatef(Angle,0,1,0);// 4. Matrix ändern: Drehen um eigene Achse
glScalef(0.5,0.5,0.5);// 3. Matrix ändern: Figur ist kleiner als die Sonne
glColor3ub(255,0,0);// 2. Farbe Rot setzen
RenderShape;// 1. Figur zeichnen
// PLANET 2
glPopMatrix;// 8. Kameramatrix wiederherstellen
//glPushMatrix; // 7. Kameramatrix beim letzen Planet nicht mehr sichern
glRotatef(Angle+45,0,1,0);// 6. Matrix ändern: Drehen um die Sonne
glTranslatef(2.5,0,0);// 5. Matrix ändern: Aus dem Ursprung schieben (von der Sonne weg)
glRotatef(Angle,0,1,0);// 4. Matrix ändern: Drehen um eigene Achse
glScalef(0.3,0.3,0.3);// 3. Matrix ändern: Figur ist kleiner als die Sonne
glColor3ub(0,0,255);// 2. Farbe Blau setzen
RenderShape;// 1. Figur zeichnen
Inc(Angle);// Winkel weiterdrehen
If Angle > 360
Then Angle:=0;
Die Reihenfolge der angegeben Punkte soll deutlich zeigen, dass die Matrixänderungen von unten nach oben zu lesen sind, sonst versteht man sie nicht (zumindest ich verstehe sie sonst nicht). Die Figur - also das Dreieck in unserem Fall - muss ihre Position (ihren Mittelpunkt oder wie immer Du das nennen willst) im Koodinatenurspung haben.
Dort wird sie zuächst skaliert und anschließend um ihre eigene Achse rotiert.
Ertst dann wird sie aus dem Ursprung weg verschoben, und befindet sich durch die zweite Rotation auf einer Umlaufbahn um die Sonne (Coolcat würde sagen: das ist ein Basiswechsel). Die letzte Transformation geschieht durch die Kameramatrix und verschiebt das ganze Gebilde in den sichtbaren Bereich (ins Frustum).
Dass ich die Kameramatrix poppen und gleich wieder pushen muss, ist etwas umständlich, man könnte auch die Kameramatrix mit glGet herausziehen und anstatt des glPopMatrix ein glLoadMatrix verwenden, abr das wollte ich Dir jetzt nicht antun .
Das ganze sollte mit gluPerspective bzw. mit glFrustum gezeichnet werden.
Ich hoffe, ich habe nichts vergessen.
Viele Grüße,
Traude
Hey, danke für den Code, ist super beschrieben, jetzt habe ich schonmal das ganze erst so mehr oder weniger richtig verstanden
Leider entfernt sich mit deinem Code die ganze Geschichte (bzw der Betrachter) immer noch. Soweit ich das sehen kann, stimmt die Rotation aber wie kann ich am besten verhindern, dass sich der Betrachter immer weiter von der Welt "wegschiebt"?
Hoffe, du weisst was ich meine, und dass ich keine furchtbar dämliche Frage stelle
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
LoadIdentity;!
führ das mal nach glClear aus, dann sollte es klappen. Das sorgt dafür, dass die aktuell verwendete Matrix (in deinem fall die ModelviewMatrix) wieder auf ihren ursprung zurück gesetzt wird. Dadurch, dass du das nicht tust, behälst du die veränderungen aus dem alten Frame erhalten und rechnest die veränderungen aus dem neuen Frame einfach dort mit hinein, das Resultat ist eine steigende Entfernung vom Sonnensystem, da du ja jedes mal nur die neue Entfernung hinzuaddierst, anstatt sie komplett neu zu setzen.
Es könnte sein, dass sich dein Sonnensystem dadurch nicht mehr dreht. Lege dafür einfach weitere Variablen für jeden Himmelskörper an und lasse diese mit jedem Frame um einen fixen wert hochzählen. Überschreiten sie die 360, zählst du wieder von 0 an. Diese Variablen benutzt du dann als Winkel im glRotatef(); für den jeweiligen Himmelskörper.
Außerdem sehe ich gerade, dass du im onCreate Ereignis der Form ebenfalls noch ein glTranslatef drin hast, das müsstest du dann nach dem LoadIdentity; ausführen, sonst geht das verschütt und bringt nichts mehr!
EDIT:: Ich sehe gerade, das Traude das mit dem Winkel auch schon mit drin hat im Code naja, doppelt hält besser^^
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
// KAMERA
// Kameramatrix sichern
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
// SONNE
glRotatef(Angle,0,1,0);// Matrix ändern: Drehen um die eigene Achse
glColor3ub(255,255,0);// Farbe Gelb setzen (schließlich soll es die Sonne sein)
RenderShape;// Figur zeichnen
// PLANET 1
glPopMatrix;// 8. Kameramatrix wiederherstellen
glPushMatrix;// 7. Kameramatrix sichern
glRotatef(Angle,0,1,0);// 6. Matrix ändern: Drehen um die Sonne
glTranslatef(2,0,0);// 5. Matrix ändern: Aus dem Ursprung schieben (von der Sonne weg)
glRotatef(Angle,0,1,0);// 4. Matrix ändern: Drehen um eigene Achse
glScalef(0.5,0.5,0.5);// 3. Matrix ändern: Figur ist kleiner als die Sonne
glColor3ub(255,0,0);// 2. Farbe Rot setzen
RenderShape;// 1. Figur zeichnen
// PLANET 2
glPopMatrix;// 8. Kameramatrix wiederherstellen
//glPushMatrix; // 7. Kameramatrix beim letzen Planet nicht mehr sichern
glRotatef(Angle+45,0,1,0);// 6. Matrix ändern: Drehen um die Sonne
glTranslatef(2.5,0,0);// 5. Matrix ändern: Aus dem Ursprung schieben (von der Sonne weg)
glRotatef(Angle,0,1,0);// 4. Matrix ändern: Drehen um eigene Achse
glScalef(0.3,0.3,0.3);// 3. Matrix ändern: Figur ist kleiner als die Sonne
glColor3ub(0,0,255);// 2. Farbe Blau setzen
RenderShape;// 1. Figur zeichnen
Inc(Angle);// Winkel weiterdrehen
If Angle > 360
Then Angle:=0;
SwapBuffers(DC);
end;
so hab ichs jetzt, und es entfernt sich nicht mehr. danke für den guten tipp, Sellmann!
Ich glaube, es dreht sich auch alles wie es soll, wobei ich das nicht so gut erkennen kann^^
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Na, einen kleinen Schubs braucht das ganze noch, weil ich nicht dazugeschrieben habe, wie die Matrizen initialisiert werden müssen. Die ProjektionsMatrix bleibt normalerweise gleich, daher ist es zulässig, sie nur ein einziges Mal zu erstellen und zu initialisieren. Bei einem Fenster-Resize sollte man aber auch die Projektionsmatrix neu setzen.
AAAAABER die ModelView-Matrix sollte man bei JEDEM Rendervorgang initialisieren und beschicken, denn die Kamera steckt in der ModelView-Matrix mit drin und die Kamera sollte sich auch bewegen können, daher sollte man die Kamera mit in die Renderprozedur dazu nehmen.
Code:
// RENDERPROZEDUR: KAMERA
glMatrixMode(GL_MODELVIEW);
glLoadIdentity;
glTranslatef(0,0,-5);// Kameramatrix befüllen
glPushMatrix;// Kameramatrix sichern
....dann kommt die Sonne ...
Die einfachste Kamera-Bewegung die es gibt ist das Zoomen: setz mal das (-5) im Kamera-Tanslate-Befehl auf (minus acht =========> Mist, minus acht in Ziffern geschrieben gibt ein Smily), damit erhöhst Du Entfernung Kamera/Objekt.
Wenn man hier einen Rotationsbefehl einfügt, dreht sich die ganze 3D-Welt - bzw. die Kamera .
Registriert: Fr Jan 04, 2008 21:29 Beiträge: 419 Wohnort: Lübeck
Das hat mich eben gerade auch etwas verwirrt, aber ich hab den Code mal ausprobiert und er funktioniert komplett fehlerfrei mit gewünschtem Ergebnis. Liegt wohl daran, dass die PerpektivMatrix direkt gepusht wird im onCreate-Ereignis... aber da stellt sich mir die Frage, warum die PerspektivMatrix?
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Das glTranslate(0,0,-5) gehört nicht in die Perspektiv-Matrix, sondern in die ModelViewmatrix hinein, denn es ist ja als Kamera-Transformaion gemeint. Nach dem gluPerspektive sollten im Projektions-Modus keine Transformationen mehr stattfinden. So etwas funktioniert schon, man sollte sich das als Anfänger aber nicht angewöhnen. Z.B. verbaut man sich dabei die Möglichkeit, eine Kamera zu bauen. Ich denk schon, dass das ein Argument ist.
Hehe, man kann jetzt immerhin per Tasten näher hin, wieder zurück, links- und rechtsrum drehen Danke für eure super Hilfe, hat mich direkt gewundert wie gut einem hier geholfen wird OpenGL ist ja wunderbar, werd mich noch viel damit beschäftigen, gefällt mir gut Grüsse, Redfly.
EDIT: hm, habe jetzt versucht, das ganze auch noch vertikal verschieben zu lassen, allerdings hat keiner meiner Ansätze Erfolg.
Ich schätze, es ist eine Verständnisfrage: Kann ich die ganze Welt nachträglich drehen, bzw die "Kamera"? (bzw. geht es gut?)
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Hmm, vertikal verschieben. Wir haben doch eine Kamera, nicht?
Wenn wir glTranslate anwenden, wird das Ganze eine Verschiebung. Diese Verschiebung betrifft alles, was sich in Deiner Szene befindet, man könnte also sagen, die ganze 3D-Welt. Solche Verschiebungen werden übrigens immer als letztes angewendet: Zuerst kommen die Bewegungen der einzelnen Objekte und als letztes die Kamerabewegung. Zugegeben, nicht ganz als Letztes, denn dann kommt noch die Projektion und noch ein paar Sachen, damit das Zeug ordnungsgemäß im Fenster erscheinen kann.
Der Input für glTranslate ist ein Vektor. Ich weiß ja nicht, ob Du Dich schon mit Vektoren oder auch dem Koordinatensystem beschäftigt hast. Das Ding hat drei Komponenten, das sind die drei Richungen des Raums: X = rechts/links, Y = oben/unten, Z = nach vor/ zurück. Damit kann ich mir jede 3D-Position erobern. Der Vektor lautet also: (X,Y,Z).
Ganz wichtig: Einen Kameraschwenk muss man simulieren, indem man nicht die Kamera schwenkt sondern alle Objekte dreht, und zwar in die verkehrte Richtung. Beim Verschieben ist es ganz das Gleiche: möchtest Du nach vor, musst Du alles andere zurückschieben (deshalb die [-5] ), möchtest Du nach links, musst Du alles andere nach rechts schieben.
Um das ganze jetzt ordentlich machen zu können, muss man wissen, wie das OpenGL-Koordinatensystem gebaut ist:
Wenn Du "in den Bildschirm hinein" schaust, sieht Du in die MINUS Z-Richtung, demnach ist HINTER Dir die PLUS Z Richtung.
X-Richtung: nach rechts ist X Plus, nach links ist X MINUS
Y-Richtung: nach oben ist Y PLUS, nach unten Y-MINUS.
Kamera nach rechts verschieben heißt also, alles nach links verschieben. Wir brauchen die X-Achse (das ist die vertikale Achse). Sagen wir, wir wollen um 3 in die MINUS X-Richtung verschieben. Der Verschiebevektor lautet demnach: (-3,0,0). Weil Wir aber von unserer Szene auch etwas sehen wollen, weicht die Kamera ein wenig zurück (das heißt, wir schieben alle Objekte ein wenig nach vor). Nach vor ist in die MINUS Z Richtung, der Verschiebevektor lautet daher (0,0,-5).
Verschiebevektoren darf man addieren (das darf man bei den Rotationen NICHT tun - das heißt man darf schon aber es kommt Mist raus), daher können wir einfach schreiben:
Code:
// KAMERA
glTranslatef(-3,0,-5);// Kameramatrix befüllen
Und das Ergebnis sollte jetzt so aussehen, als ob die Kamera ein Stück zurückweicht und ein wenig nach rechts geht. So eine Verschiebe-Kamerabewegung sollte man eigentlich ganz einfach mit den Cursortasten hinkriegen können.
Zitat:
Danke für eure super Hilfe, hat mich direkt gewundert wie gut einem hier geholfen wird Wink
Registriert: Do Sep 25, 2003 15:56 Beiträge: 7810 Wohnort: Sachsen - ERZ / C
Programmiersprache: Java (, Pascal)
Traude hat geschrieben:
Solche Verschiebungen werden übrigens immer als letztes angewendet [...]
Ich hoffe das sorgt nicht für Verwirrung. Schließlich steht der betreffende Code ganz oben in der Renderprozedur.
Ich versuchs mal zu erklären.
Traude gibt einen Hinweis auf die Mathematik die dahinter steht. Jeder Manipulations-Befehl (glTranslate, glRotate, glScale) erzeugt eine Matrix welche mit der aktuellen Matrix multipliziert wird. Das geschieht dabei so (bitte korrigiert mich falls falsch), dass die neu erzeugte Manipulation rechts von den bisherigen angefügt wird. D.h. die ersten Manipulationen (die Kamera) stehen ganz links, und werden deshalb als letztes ranmultipliziert.
I = Identitätsmatrix
M1, ... Mz = alte Manipulationen
Mneu = neue Manipulation
W = neue Weltmatrix
M1 x M2 x ... x Mz x Mneu x I = W
_________________ Blog: kevin-fleischer.de und fbaingermany.com
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
Eigentlich wollt ich gar nicht so tief hinein. Denn was viel wichtiger ist, ist die Tatsache, dass es zwar den Anschein hat, dass die Kamera-Transformationen zuerst angewendet werden, weil sie vor allen anderen Transformationen stehen. Aber in Wirklichkeit kommen sie erst nach den Transformationen der einzelnen Objekte zur Anwendung, und transformieren daher ALLE nachfolgenden gezeichneten Objekte. Intern rollt OpenGL das ganze also von hinten nach vorne auf.
Hast also im Prinzip ganz recht, Flash.
Die Reihenfolge der Transformationen ist imho ziemlich verwirrend. So etwas wie ein Planetensystem zu programmieren wird einem dadurch unnötig schwer gemacht.
Gut, das ist wenigstens einfach!
und wenn ich ALLES drehen will, anstatt nur zu verschieben?
d.h. alles um die Kamera drehen?
einfach statt translatef rotatef schreiben geht ja nicht, weil man für translatef im Gegensatz zu Zweiterem keinen Drehpunkt braucht.
Registriert: Di Okt 03, 2006 14:07 Beiträge: 1277 Wohnort: Wien
@ Redfly: Aber ja doch, das geht. Man muss jetzt nur den Input von glRotate kennen. glRotatef braucht vier Werte. Der erste Wert ist ein Winkel (in Grad). Die drei restlichen Werte sind die Drehachse, ausgedrückt wieder durch einen Vektor.
Und hier gilt wieder der Grundsatz: immer das Gegenteil machen. Wenn sich die Kamera nach rechts dreht, müssen anstatt dessen alle Objekte nach links gedreht werden.
Wie dreht man nach links? Zunächst brauchen wir eine Drehachse. Die positive Y-Achse könnte z.B. unsere Drehachse sein: (0,1,0). Und wir entscheiden uns für einen Winkel von 30 Grad. Eine positive Drehung ist in OpenGL immer eine Drehung gegen gegen den Uhrzeigersinn. Wenn wir mit dem Uhrzeigersinn drehen wollen, müssen wir einen negativen Drehwinkel nehmen.
Dazu brauchen wir: glRotate(30,0,1,0). Damit soll ein Kameraschwenk nach rechts simuliert werden. Wenn alles OK ist, solltest Du den Eindruck haben, dass sich die Kamera nach rechts dreht.
Drehen kann man sich nicht nur um jede der drei Koordinatenachsen, sondern um jede bliebige Achse.
Drehungen bringen uns noch nicht in Verlegenheit. Komplizierter wird es erst, wenn Du versuchst, Rotationen und Translationen zu mischen. Dazu braucht man aber schon ein wenig mehr Vektor-Geometrie und Matrizenrechnung.
In Flash' Tutorial ist erklärt, was sich ereignet, wenn man zunächst eine Translation und dann eine Rotation bzw. umgekehrt macht.
Mitglieder in diesem Forum: 0 Mitglieder und 12 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.