Tutorial Kamera1: Unterschied zwischen den Versionen
Flash (Diskussion | Beiträge) (Tutorial Übertragen) |
K (Rechtschreibfehler ausgebessert) |
||
(6 dazwischenliegende Versionen von 4 Benutzern werden nicht angezeigt) | |||
Zeile 2: | Zeile 2: | ||
==Einführung== | ==Einführung== | ||
− | Sicherlich standen schon einige von euch vor dem Problem, wie man denn eine Kamera in OpenGl implementieren könnte. Es stellen sich einem dabei viele Probleme, z.B. wie kann ich die Kamera auf ein Objekt ausrichten. Oder wie sieht es mit Billboarding aus? Die Liste kann fast unendlich erweitert werden. Ich werde versuchen, ein paar dieser Probleme zu lösen und vielleicht schaffe ich es sogar, den | + | Sicherlich standen schon einige von euch vor dem Problem, wie man denn eine Kamera in OpenGl implementieren könnte. Es stellen sich einem dabei viele Probleme, z.B. wie kann ich die Kamera auf ein Objekt ausrichten. Oder wie sieht es mit Billboarding aus? Die Liste kann fast unendlich erweitert werden. Ich werde versuchen, ein paar dieser Probleme zu lösen und vielleicht schaffe ich es sogar, den Einen oder Anderen dazu zu bringen, selbst eigene Kameratechnische Probleme zu lösen. |
− | Wer SchodMC's Objekt xxx Tutorials gelesen hat, hat übrigens schon einiges an Vorwissen, das er hier prima wiederverwerten kann. Ich kann die | + | Wer SchodMC's Objekt xxx Tutorials gelesen hat, hat übrigens schon einiges an Vorwissen, das er hier prima wiederverwerten kann. Ich kann die Lektüre dieser gut gelungenen Werke vor dem Weiterlesen nur wärmstens empfehlen. |
==Die Kamera Analogie== | ==Die Kamera Analogie== | ||
− | Dreht sich die Erde um die Sonne oder die Sonne um die Erde? Ist euch bewusst, dass diese Frage eigentlich nicht zu beantworten ist? Tatsächlich macht es, wenn man richtig darüber nachdenkt keinen Unterschied. Das könnt ihr selber überprüfen: Geht vor eure Haustür und stellt euch hin(pfui, es regnet - nein, macht es doch lieber drinnen). Dreht euch einmal im Kreis. Was habt ihr gesehen? Habt ihr euch nun im Universum gedreht oder das ganze Unviversum um euch herum? Eine seltsame Frage? ... Vielleicht | + | Dreht sich die Erde um die Sonne oder die Sonne um die Erde? Ist euch bewusst, dass diese Frage eigentlich nicht zu beantworten ist? Tatsächlich macht es, wenn man richtig darüber nachdenkt keinen Unterschied. Das könnt ihr selber überprüfen: Geht vor eure Haustür und stellt euch hin (pfui, es regnet - nein, macht es doch lieber drinnen). Dreht euch einmal im Kreis. Was habt ihr gesehen? Habt ihr euch nun im Universum gedreht oder das ganze Unviversum um euch herum? Eine seltsame Frage? ... Vielleicht hat`s der Ein oder Andere schon bemerkt... Für den Mensch der sich da grad im Regen gedreht hat, wäre beides denkbar. Tatsächlich macht es für das Auge keinen Unterschied. Es handelt sich nur um ein philosophisches Problem, besonders eines der westlich geprägten Welt, das ihr zu überwinden habt. Alles dreht sich um euch, nicht ihr darin. Also: Dreht ihr euch nach rechts, ist das gleichbedeutend damit, dass sich das Univerum unter euren Füssen nach links gedreht hat. Noch Fragen? |
− | In der Hoffnung euch jetzt alle komplett verwirrt zu haben mache ich jetzt einfach mal weiter. | + | In der Hoffnung euch jetzt alle komplett verwirrt zu haben, mache ich jetzt einfach mal weiter. |
==Darstellung von Objekten== | ==Darstellung von Objekten== | ||
Bevor wir irgendwelche Objekte zeichnen, müssen wir uns erst einmal eine Welt ausdenken. Der zweite Punkt ist dann, zu definieren, wie diese Objekte dargestellt werden sollen. Mir sind unterschiedliche Ideen gekommen, die sich alle mit mehr oder weniger Aufwand realisieren lassen. | Bevor wir irgendwelche Objekte zeichnen, müssen wir uns erst einmal eine Welt ausdenken. Der zweite Punkt ist dann, zu definieren, wie diese Objekte dargestellt werden sollen. Mir sind unterschiedliche Ideen gekommen, die sich alle mit mehr oder weniger Aufwand realisieren lassen. | ||
− | Letztendlich habe ich mich an einer Weltraumszene festgehängt. Hier lässt sich so einiges zeigen. Besonderen dank an | + | Letztendlich habe ich mich an einer Weltraumszene festgehängt. Hier lässt sich so einiges zeigen. Besonderen dank an [http://www.delphigl.de Sascha Willems], der - freundlich wie er ist - gestattete, einen Satz seiner Texturen einzusetzen und gleich noch ein Paar Orte verriet, an denen man gute Sonnensystem-Texturen finden kann. |
Kommen wir nun zu den Objekten selbst. Wir wollen hier ein wenig OOP verwenden. Das bietet sich an, da es in unserem Fall vorteilhaft ist, einige Objekte voneinander abzuleiten zu können. Alle Objekte müssen 2 Eigenschaften besitzen: Position und Rotationsmatrix: | Kommen wir nun zu den Objekten selbst. Wir wollen hier ein wenig OOP verwenden. Das bietet sich an, da es in unserem Fall vorteilhaft ist, einige Objekte voneinander abzuleiten zu können. Alle Objekte müssen 2 Eigenschaften besitzen: Position und Rotationsmatrix: | ||
− | <pascal> type | + | <source lang="pascal"> type |
//Basis Objekt | //Basis Objekt | ||
TObjekt = class | TObjekt = class | ||
Zeile 27: | Zeile 27: | ||
Position : TVertex; | Position : TVertex; | ||
constructor Create; virtual; | constructor Create; virtual; | ||
− | end;</ | + | end;</source> |
Um die Planeten darzustellen, werden unterschiedliche Nachfolger dieses Objektes verwendet. Ich will auf diese nicht weiter eingehen, da sie an sich nichts mit unserem eigentlichem Interessensgebiet zu tun haben - den Kameras. | Um die Planeten darzustellen, werden unterschiedliche Nachfolger dieses Objektes verwendet. Ich will auf diese nicht weiter eingehen, da sie an sich nichts mit unserem eigentlichem Interessensgebiet zu tun haben - den Kameras. | ||
Zeile 34: | Zeile 34: | ||
Bevor wir uns daran machen, über die Implementierung nachzudenken, sollten wir überlegen, was wir eigentlich haben wollen. Eine Kamera, das ist klar. Was soll sie können? Sie soll einmal aus der Sicht des Objektes schauen können, ein Objekt fest in den Blick nehmen und auch eine freie Ansicht bieten (Freie Bewegungen sind bislang nicht in den Beispielsource mit eingebaut. Eine freie Ansicht hingegen schon - steuerbar mit dem Joystick). Wir wollen aber keine stationäre Kamera, sondern eine die sich gleich noch mehr oder weniger automatisch bewegt. | Bevor wir uns daran machen, über die Implementierung nachzudenken, sollten wir überlegen, was wir eigentlich haben wollen. Eine Kamera, das ist klar. Was soll sie können? Sie soll einmal aus der Sicht des Objektes schauen können, ein Objekt fest in den Blick nehmen und auch eine freie Ansicht bieten (Freie Bewegungen sind bislang nicht in den Beispielsource mit eingebaut. Eine freie Ansicht hingegen schon - steuerbar mit dem Joystick). Wir wollen aber keine stationäre Kamera, sondern eine die sich gleich noch mehr oder weniger automatisch bewegt. | ||
− | Wir brauchen | + | Wir brauchen außerdem die Möglichkeit, unterschiedliche Modi einzustellen und Zielobjekte festzulegen. Nicht zu vergessen auch eine Funktion, die eine Kameramatrix erzeugt und diese auch noch gleich an OpenGL weitergibt. |
− | Dies sollte uns für den Anfang erst einmal genügen. Fangen wir also an uns die gewünschte Kamera zu bauen. | + | Dies sollte uns für den Anfang erst einmal genügen. Fangen wir also an, uns die gewünschte Kamera zu bauen. |
− | <pascal> TLookMode = (lmFree, lmObjektSight, lmLookAtObjekt); | + | <source lang="pascal"> TLookMode = (lmFree, lmObjektSight, lmLookAtObjekt); |
TMoveMode = (mmFree, mmAttatched); | TMoveMode = (mmFree, mmAttatched); | ||
TKamera = class(TObjekt) | TKamera = class(TObjekt) | ||
Zeile 51: | Zeile 51: | ||
constructor Create; override; | constructor Create; override; | ||
procedure ResetView; //Ansicht zurücksetzen | procedure ResetView; //Ansicht zurücksetzen | ||
− | end;</ | + | end;</source> |
==Implementation der Kameramodi== | ==Implementation der Kameramodi== | ||
===lmFree und lmObjektSight=== | ===lmFree und lmObjektSight=== | ||
− | Diese Modi haben einige Gemeinsamkeiten. lmObjektSight steht für die Blickrichtung, die ein Objekt hat, lmFree ist die frei wählbare Variante. Häufig gleichen sich diese Modi, wenn man z.B. das Objekt von dem aus man in die Welt schaut gleich auch vom Spieler gesteuert wird. Von der Implementierung her | + | Diese Modi haben einige Gemeinsamkeiten. lmObjektSight steht für die Blickrichtung, die ein Objekt hat, lmFree ist die frei wählbare Variante. Häufig gleichen sich diese Modi, wenn man z.B. das Objekt von dem aus man in die Welt schaut gleich auch vom Spieler gesteuert wird. Von der Implementierung her sind sie fast Identisch. Das Problem besteht darin, dass die Kameramatrix genau anders herum drehen muss, als wie das Objekt gedreht ist (siehe Kamera Analogie). Die Mathematiker haben das Problem für uns schon gelöst - mit invertierten Matrizen. Wir müssen also nicht einmal das Rad neu erfinden: |
− | <pascal> procedure TKamera.UseMatrix; | + | <source lang="pascal"> procedure TKamera.UseMatrix; |
var | var | ||
RotMatrix : THomogeneousMatrix; | RotMatrix : THomogeneousMatrix; | ||
Zeile 94: | Zeile 94: | ||
glLoadMatrixf(@RotMatrix[0,0]); | glLoadMatrixf(@RotMatrix[0,0]); | ||
glTranslatef(-Pos[0], -Pos[1], -Pos[2]) | glTranslatef(-Pos[0], -Pos[1], -Pos[2]) | ||
− | end;</ | + | end;</source> |
Zeile 102: | Zeile 102: | ||
Nun wollen wir ein Objekt in den Fokus der Kamera nehmen. Voraussetzung ist, dass wir bereits die Koordinaten unserer Kamera kennen, denn sonst können wir nicht bestimmen, in welcher Richtung das Objekt liegt. | Nun wollen wir ein Objekt in den Fokus der Kamera nehmen. Voraussetzung ist, dass wir bereits die Koordinaten unserer Kamera kennen, denn sonst können wir nicht bestimmen, in welcher Richtung das Objekt liegt. | ||
− | Wir müssen uns entscheiden: | + | Wir müssen uns entscheiden: Wollen wir eine komplett neue Matrix erstellen, oder wollen wir die bereits bestehende Rotationsmatrix verwenden und sie so manipulieren, dass die Kamera auf das Objekt ausgerichtet ist? Ich habe mich für letztere Variante entschieden, da man dieses Wissen in Spielen auch anderorts wiederverwerten kann. |
Kommen wir also zur Idee, die hinter unserem Problem steckt: Ich hab eine Rotationsmatrix und die Globale Richtung von unserem Objekt zu unserem Zielpunkt. Drehen wir nun diese Globale Richtung in das lokale Koordinatensystem unseres Objektes, so können wir die Winkel errechnen, die nötig sind, um unsere Kamera auf das Ziel auszurichten. | Kommen wir also zur Idee, die hinter unserem Problem steckt: Ich hab eine Rotationsmatrix und die Globale Richtung von unserem Objekt zu unserem Zielpunkt. Drehen wir nun diese Globale Richtung in das lokale Koordinatensystem unseres Objektes, so können wir die Winkel errechnen, die nötig sind, um unsere Kamera auf das Ziel auszurichten. | ||
− | '''Das Problem:''' Ein Problem, das sich mir beim Nachdenken über diese Idee | + | '''Das Problem:''' Ein Problem, das sich mir beim Nachdenken über diese Idee gestellt hat, ist, dass die Blickrichtung von OpenGl immer in die negative Z-Richtung geht. An sich wird das Problem nicht wesentlich schwieriger, man muss nur an ein paar geschickten Stellen ein Minus verteilen, bzw. Minuend und Subtrahend vertauschen. |
− | Gehen wir einmal davon aus, dass wir die | + | Gehen wir einmal davon aus, dass wir die globale Richtung in die lokale transformiert haben. Wie kommen wir nun an unsere Rotationsmatrix? Bzw. wie kommen wir an die benötigten Kosinus- und Sinuswerte? Zuerst wollen wir um die y-Achse drehen. Deshalb können wir den y-Wert der lokalen Richung erst einmal außer Acht lassen. Setzen wir diesen auf 0 und normalisieren unseren Vektor. Wir erhalten dadurch einen Vektor auf dem Einheitskreis - Vorteil: wir müssen unseren Sinus und Cosinus nicht kompliziert errechnen, denn wir haben ihn bereits. Keine Arbeit mehr für uns. Matrix erzeugen und wir haben fertig. |
− | Jetzt haben wir die Kamera um die y-Achse ausgerichtet. Es fehlt noch die x-Achse. Wir haben bereits einiges an Vorarbeit geleistet. Wir können ganz einfach den Winkel zwischen der lokalen Richtung und dem Vektor auf dem Einheitskreis von vorhin berechnen. Sind beides Einheitsvektoren, so ist das Skalarprodukt(zu Englisch Dotproduct) der | + | Jetzt haben wir die Kamera um die y-Achse ausgerichtet. Es fehlt noch die x-Achse. Wir haben bereits einiges an Vorarbeit geleistet. Wir können ganz einfach den Winkel zwischen der lokalen Richtung und dem Vektor auf dem Einheitskreis von vorhin berechnen. Sind beides Einheitsvektoren, so ist das Skalarprodukt(zu Englisch Dotproduct) der Kosinus des gesuchten Winkels. Wie sicher Einigen bekannt ist, gilt: |
<div align="center">'''Cos²(α) + Sin²(α) = 1'''</div> | <div align="center">'''Cos²(α) + Sin²(α) = 1'''</div> | ||
Zeile 118: | Zeile 118: | ||
Ich würde sagen Problem gelöst, hier der passende Code: | Ich würde sagen Problem gelöst, hier der passende Code: | ||
− | <pascal> procedure LockTarget(Target : TObjekt); | + | <source lang="pascal"> procedure LockTarget(Target : TObjekt); |
var | var | ||
InvMatrix, M1, M2 : THomogeneousMatrix; | InvMatrix, M1, M2 : THomogeneousMatrix; | ||
Zeile 161: | Zeile 161: | ||
RotMatrix := IdentityHmgMatrix | RotMatrix := IdentityHmgMatrix | ||
end | end | ||
− | end;</ | + | end;</source> |
==Vorwärts, Rückwärts, Links, Rechts, Hoch, Runter== | ==Vorwärts, Rückwärts, Links, Rechts, Hoch, Runter== | ||
− | Eine in Ego Shootern als Strafen bezeichnete Art sich zu bewegen, ist das | + | Eine in Ego Shootern als Strafen bezeichnete Art sich zu bewegen, ist das Bewegen der Kamera in eine bestimmte Richtung, die von der Ausrichtung der Kamera abhängt. Dies beschreibt ein recht häufig auftretendes Problem im Zusammenhang mit Kameras. An sich ist es nicht weiter schwer, z.B. entspricht links Strafen dem Bewegen entlang der negativen x-Achse im lokalen Koordinatensystem der Kamera. Will man also die Position der Kamera in dieser Art manipulieren, so erstellt man einfach einen Vektor, der in der zur Kamera lokalen Richtung zeigt (im Beispiel also: [-1, 0,0]). Dann dreht man mit Hilfe der Rotationsmatrix der Kamera diesen Vektor ins globale Koordinatensystem und addiert ihn zum Positionsvektor der Kamera. (Allen denen es nicht aufgefallen ist: Das war eine Kurzfassung der Mathematik in SchodMCs "Objekt gedreht und dennoch nach vorne bewegt" Tutorial). |
==Billboarding== | ==Billboarding== | ||
− | Eine weitere Kameraspezifische Sache | + | Eine weitere Kameraspezifische Sache ist das Billboarding. Das Problem stellt sich einem, wenn man eine Partikelengine schreibt und die Polygone immer parallel zur Kamera ausgerichtet sein sollen. Man muss hierfür einfach die Rotation aus der Matrix entfernen: |
− | <pascal> procedure Billboard; | + | <source lang="pascal"> procedure Billboard; |
const | const | ||
NewModelView : Array[0..11] of TGLFloat = | NewModelView : Array[0..11] of TGLFloat = | ||
Zeile 183: | Zeile 183: | ||
Move(NewModelView[0], ModelView[0], SizeOf(NewModelview)); | Move(NewModelView[0], ModelView[0], SizeOf(NewModelview)); | ||
glLoadMatrixf(@Modelview[0]) | glLoadMatrixf(@Modelview[0]) | ||
− | end;</ | + | end;</source> |
Der Renderer des Kameratutorials könnte dann so abgeändert werden: | Der Renderer des Kameratutorials könnte dann so abgeändert werden: | ||
− | <pascal> ... | + | <source lang="pascal"> ... |
//Kamera initialisieren | //Kamera initialisieren | ||
glLoadIdentity; | glLoadIdentity; | ||
Zeile 209: | Zeile 209: | ||
glVertex3f(-10, 10, 0); | glVertex3f(-10, 10, 0); | ||
glEnd(); | glEnd(); | ||
− | ...</ | + | ...</source> |
− | Ich habe jetzt beschlossen, dass ich hier einmal aufhöre. Das Geschreibe ist doch recht anstrengend und ich will euch doch nicht alle Ideen vorwegnehmen. Deshalb wünsch ich euch jetzt viel | + | Ich habe jetzt beschlossen, dass ich hier einmal aufhöre. Das Geschreibe ist doch recht anstrengend und ich will euch doch nicht alle Ideen vorwegnehmen. Deshalb wünsch ich euch jetzt viel Spaß beim Rumprobieren |
...have a lot of fun! | ...have a lot of fun! | ||
Zeile 222: | Zeile 222: | ||
:Weitere Hinweise zum erstellen von Kameraklassen findet ihr im Artikel [[Kamera (1)]]. | :Weitere Hinweise zum erstellen von Kameraklassen findet ihr im Artikel [[Kamera (1)]]. | ||
+ | |||
+ | == Dateien == | ||
+ | * {{ArchivLink|file=tut_kameras_src_vcl|text=Beispiel-Quelltext (Delphi)}} | ||
+ | * {{ArchivLink|file=tut_kameras_exe|text=Beispiel-Programm}} | ||
{{TUTORIAL_NAVIGATION|[[Tutorial TexFilter]]|-}} | {{TUTORIAL_NAVIGATION|[[Tutorial TexFilter]]|-}} | ||
[[Kategorie:Tutorial|Kamera1]] | [[Kategorie:Tutorial|Kamera1]] |
Aktuelle Version vom 25. September 2013, 15:30 Uhr
Inhaltsverzeichnis
Dreht sich das Universum um uns und andere philosophische Fragen
Einführung
Sicherlich standen schon einige von euch vor dem Problem, wie man denn eine Kamera in OpenGl implementieren könnte. Es stellen sich einem dabei viele Probleme, z.B. wie kann ich die Kamera auf ein Objekt ausrichten. Oder wie sieht es mit Billboarding aus? Die Liste kann fast unendlich erweitert werden. Ich werde versuchen, ein paar dieser Probleme zu lösen und vielleicht schaffe ich es sogar, den Einen oder Anderen dazu zu bringen, selbst eigene Kameratechnische Probleme zu lösen.
Wer SchodMC's Objekt xxx Tutorials gelesen hat, hat übrigens schon einiges an Vorwissen, das er hier prima wiederverwerten kann. Ich kann die Lektüre dieser gut gelungenen Werke vor dem Weiterlesen nur wärmstens empfehlen.
Die Kamera Analogie
Dreht sich die Erde um die Sonne oder die Sonne um die Erde? Ist euch bewusst, dass diese Frage eigentlich nicht zu beantworten ist? Tatsächlich macht es, wenn man richtig darüber nachdenkt keinen Unterschied. Das könnt ihr selber überprüfen: Geht vor eure Haustür und stellt euch hin (pfui, es regnet - nein, macht es doch lieber drinnen). Dreht euch einmal im Kreis. Was habt ihr gesehen? Habt ihr euch nun im Universum gedreht oder das ganze Unviversum um euch herum? Eine seltsame Frage? ... Vielleicht hat`s der Ein oder Andere schon bemerkt... Für den Mensch der sich da grad im Regen gedreht hat, wäre beides denkbar. Tatsächlich macht es für das Auge keinen Unterschied. Es handelt sich nur um ein philosophisches Problem, besonders eines der westlich geprägten Welt, das ihr zu überwinden habt. Alles dreht sich um euch, nicht ihr darin. Also: Dreht ihr euch nach rechts, ist das gleichbedeutend damit, dass sich das Univerum unter euren Füssen nach links gedreht hat. Noch Fragen?
In der Hoffnung euch jetzt alle komplett verwirrt zu haben, mache ich jetzt einfach mal weiter.
Darstellung von Objekten
Bevor wir irgendwelche Objekte zeichnen, müssen wir uns erst einmal eine Welt ausdenken. Der zweite Punkt ist dann, zu definieren, wie diese Objekte dargestellt werden sollen. Mir sind unterschiedliche Ideen gekommen, die sich alle mit mehr oder weniger Aufwand realisieren lassen.
Letztendlich habe ich mich an einer Weltraumszene festgehängt. Hier lässt sich so einiges zeigen. Besonderen dank an Sascha Willems, der - freundlich wie er ist - gestattete, einen Satz seiner Texturen einzusetzen und gleich noch ein Paar Orte verriet, an denen man gute Sonnensystem-Texturen finden kann.
Kommen wir nun zu den Objekten selbst. Wir wollen hier ein wenig OOP verwenden. Das bietet sich an, da es in unserem Fall vorteilhaft ist, einige Objekte voneinander abzuleiten zu können. Alle Objekte müssen 2 Eigenschaften besitzen: Position und Rotationsmatrix:
type
//Basis Objekt
TObjekt = class
private
public
ObjektName : String;
Rotation : THomogeneousMatrix;
Position : TVertex;
constructor Create; virtual;
end;
Um die Planeten darzustellen, werden unterschiedliche Nachfolger dieses Objektes verwendet. Ich will auf diese nicht weiter eingehen, da sie an sich nichts mit unserem eigentlichem Interessensgebiet zu tun haben - den Kameras.
Das Kameraobjekt
Bevor wir uns daran machen, über die Implementierung nachzudenken, sollten wir überlegen, was wir eigentlich haben wollen. Eine Kamera, das ist klar. Was soll sie können? Sie soll einmal aus der Sicht des Objektes schauen können, ein Objekt fest in den Blick nehmen und auch eine freie Ansicht bieten (Freie Bewegungen sind bislang nicht in den Beispielsource mit eingebaut. Eine freie Ansicht hingegen schon - steuerbar mit dem Joystick). Wir wollen aber keine stationäre Kamera, sondern eine die sich gleich noch mehr oder weniger automatisch bewegt.
Wir brauchen außerdem die Möglichkeit, unterschiedliche Modi einzustellen und Zielobjekte festzulegen. Nicht zu vergessen auch eine Funktion, die eine Kameramatrix erzeugt und diese auch noch gleich an OpenGL weitergibt.
Dies sollte uns für den Anfang erst einmal genügen. Fangen wir also an, uns die gewünschte Kamera zu bauen.
TLookMode = (lmFree, lmObjektSight, lmLookAtObjekt);
TMoveMode = (mmFree, mmAttatched);
TKamera = class(TObjekt)
private
public
LookMode : TLookMode; //Ansichtsmodus
MoveMode : TMoveMode; //Bewegungsmodus
LookTarget, MoveTarget : TKugel; //Ansichtsziel und Bewegungsziel
procedure UseMatrix; virtual; //Kamera-Matrix einsetzen
constructor Create; override;
procedure ResetView; //Ansicht zurücksetzen
end;
Implementation der Kameramodi
lmFree und lmObjektSight
Diese Modi haben einige Gemeinsamkeiten. lmObjektSight steht für die Blickrichtung, die ein Objekt hat, lmFree ist die frei wählbare Variante. Häufig gleichen sich diese Modi, wenn man z.B. das Objekt von dem aus man in die Welt schaut gleich auch vom Spieler gesteuert wird. Von der Implementierung her sind sie fast Identisch. Das Problem besteht darin, dass die Kameramatrix genau anders herum drehen muss, als wie das Objekt gedreht ist (siehe Kamera Analogie). Die Mathematiker haben das Problem für uns schon gelöst - mit invertierten Matrizen. Wir müssen also nicht einmal das Rad neu erfinden:
procedure TKamera.UseMatrix;
var
RotMatrix : THomogeneousMatrix;
Pos : TVertex;
begin
//Ansichten
case LookMode of
lmFree : begin
RotMatrix := Rotation;
InvertMatrix(RotMatrix)
end;
lmObjektSight: begin
Assert(Assigned(LookTarget));
Rotation := LookTarget.Rotation;
RotMatrix := Rotation;
InvertMatrix(RotMatrix)
end
end;
//Bewegungen
case MoveMode of
mmFree : begin
Pos := Position
end;
mmAttatched : begin
Assert(Assigned(MoveTarget));
Position := MoveTarget.Position;
Pos := Position;
end;
end;
//Matrix einlegen
glLoadMatrixf(@RotMatrix[0,0]);
glTranslatef(-Pos[0], -Pos[1], -Pos[2])
end;
War doch schon mal gar nicht so schwer, oder?
lmLookAtObjekt
Nun wollen wir ein Objekt in den Fokus der Kamera nehmen. Voraussetzung ist, dass wir bereits die Koordinaten unserer Kamera kennen, denn sonst können wir nicht bestimmen, in welcher Richtung das Objekt liegt.
Wir müssen uns entscheiden: Wollen wir eine komplett neue Matrix erstellen, oder wollen wir die bereits bestehende Rotationsmatrix verwenden und sie so manipulieren, dass die Kamera auf das Objekt ausgerichtet ist? Ich habe mich für letztere Variante entschieden, da man dieses Wissen in Spielen auch anderorts wiederverwerten kann.
Kommen wir also zur Idee, die hinter unserem Problem steckt: Ich hab eine Rotationsmatrix und die Globale Richtung von unserem Objekt zu unserem Zielpunkt. Drehen wir nun diese Globale Richtung in das lokale Koordinatensystem unseres Objektes, so können wir die Winkel errechnen, die nötig sind, um unsere Kamera auf das Ziel auszurichten.
Das Problem: Ein Problem, das sich mir beim Nachdenken über diese Idee gestellt hat, ist, dass die Blickrichtung von OpenGl immer in die negative Z-Richtung geht. An sich wird das Problem nicht wesentlich schwieriger, man muss nur an ein paar geschickten Stellen ein Minus verteilen, bzw. Minuend und Subtrahend vertauschen.
Gehen wir einmal davon aus, dass wir die globale Richtung in die lokale transformiert haben. Wie kommen wir nun an unsere Rotationsmatrix? Bzw. wie kommen wir an die benötigten Kosinus- und Sinuswerte? Zuerst wollen wir um die y-Achse drehen. Deshalb können wir den y-Wert der lokalen Richung erst einmal außer Acht lassen. Setzen wir diesen auf 0 und normalisieren unseren Vektor. Wir erhalten dadurch einen Vektor auf dem Einheitskreis - Vorteil: wir müssen unseren Sinus und Cosinus nicht kompliziert errechnen, denn wir haben ihn bereits. Keine Arbeit mehr für uns. Matrix erzeugen und wir haben fertig.
Jetzt haben wir die Kamera um die y-Achse ausgerichtet. Es fehlt noch die x-Achse. Wir haben bereits einiges an Vorarbeit geleistet. Wir können ganz einfach den Winkel zwischen der lokalen Richtung und dem Vektor auf dem Einheitskreis von vorhin berechnen. Sind beides Einheitsvektoren, so ist das Skalarprodukt(zu Englisch Dotproduct) der Kosinus des gesuchten Winkels. Wie sicher Einigen bekannt ist, gilt:
Wir kennen also auch den Wert des Sinus. Nur das Vorzeichen ist uns dann noch unbekannt. Dies ergibt sich aber daraus, ob der y-Wert der lokalen Richtung positiv oder negativ ist.
Ich würde sagen Problem gelöst, hier der passende Code:
procedure LockTarget(Target : TObjekt);
var
InvMatrix, M1, M2 : THomogeneousMatrix;
ObjektPosition : TVertex;
Cos, Sin : Single;
xzEbenenPosition : TVertex;
begin
try
InvMatrix := Rotation;
InvertMatrix(InvMatrix);
//Globale Objekt Position
ObjektPosition := VectorSubtract(Position, Target.Position);
//In lokale Koordinaten drehen
ObjektPosition := VectorTransform(ObjektPosition, InvMatrix);
xzEbenenPosition[0] := ObjektPosition[0];
xzEbenenPosition[1] := 0;
xzEbenenPosition[2] := ObjektPosition[2];
if not((xzEbenenPosition[0] = 0.0) and (xzEbenenPosition[2] = 0.0)) then
begin
NormalizeVector(xzEbenenPosition);
M1 := CreateRotationMatrixY(xzEbenenPosition[0], xzEbenenPosition[2])
end
else
M1 := IdentityHmgMatrix;
NormalizeVector(ObjektPosition);
Cos := VectorDotProduct(xzEbenenPosition, ObjektPosition);
Sin := Sqrt(1- Cos*Cos);
if (ObjektPosition[1] > 0.0) then
Sin := - Sin;
M2 := CreateRotationMatrixX(Sin, Cos);
RotMatrix := MatrixMultiply(M1, M2);
Rotation := MatrixMultiply(RotMatrix, Rotation);
RotMatrix := Rotation;
InvertMatrix(RotMatrix)
except
RotMatrix := IdentityHmgMatrix
end
end;
Vorwärts, Rückwärts, Links, Rechts, Hoch, Runter
Eine in Ego Shootern als Strafen bezeichnete Art sich zu bewegen, ist das Bewegen der Kamera in eine bestimmte Richtung, die von der Ausrichtung der Kamera abhängt. Dies beschreibt ein recht häufig auftretendes Problem im Zusammenhang mit Kameras. An sich ist es nicht weiter schwer, z.B. entspricht links Strafen dem Bewegen entlang der negativen x-Achse im lokalen Koordinatensystem der Kamera. Will man also die Position der Kamera in dieser Art manipulieren, so erstellt man einfach einen Vektor, der in der zur Kamera lokalen Richtung zeigt (im Beispiel also: [-1, 0,0]). Dann dreht man mit Hilfe der Rotationsmatrix der Kamera diesen Vektor ins globale Koordinatensystem und addiert ihn zum Positionsvektor der Kamera. (Allen denen es nicht aufgefallen ist: Das war eine Kurzfassung der Mathematik in SchodMCs "Objekt gedreht und dennoch nach vorne bewegt" Tutorial).
Billboarding
Eine weitere Kameraspezifische Sache ist das Billboarding. Das Problem stellt sich einem, wenn man eine Partikelengine schreibt und die Polygone immer parallel zur Kamera ausgerichtet sein sollen. Man muss hierfür einfach die Rotation aus der Matrix entfernen:
procedure Billboard;
const
NewModelView : Array[0..11] of TGLFloat =
(1,0,0,0,0,1,0,0,0,0,1,0);
var
Modelview : Array[0..15] of TGLFloat;
begin
// Modelview Matrix holen
glGetFloatv(GL_MODELVIEW_MATRIX , @Modelview[0]);
Move(NewModelView[0], ModelView[0], SizeOf(NewModelview));
glLoadMatrixf(@Modelview[0])
end;
Der Renderer des Kameratutorials könnte dann so abgeändert werden:
...
//Kamera initialisieren
glLoadIdentity;
Kamera.UseMatrix;
//Planeten rendern
for I := Low(Planeten) to High(Planeten) do
if i <> 3 then
Planeten[I].Render;
with Planeten[3] do
glTranslatef(Position[0], Position[1], Position[2]);
Billboard;
glBegin(GL_QUADS);
glVertex3f(-10, -10, 0);
glVertex3f(10, -10, 0);
glVertex3f(10, 10, 0);
glVertex3f(-10, 10, 0);
glEnd();
...
Ich habe jetzt beschlossen, dass ich hier einmal aufhöre. Das Geschreibe ist doch recht anstrengend und ich will euch doch nicht alle Ideen vorwegnehmen. Deshalb wünsch ich euch jetzt viel Spaß beim Rumprobieren
...have a lot of fun!
- Delphic
Nachtrag
- Weitere Hinweise zum erstellen von Kameraklassen findet ihr im Artikel Kamera (1).
Dateien
|
||
Vorhergehendes Tutorial: Tutorial TexFilter |
Nächstes Tutorial: - |
|
Schreibt was ihr zu diesem Tutorial denkt ins Feedbackforum von DelphiGL.com. Lob, Verbesserungsvorschläge, Hinweise und Tutorialwünsche sind stets willkommen. |