Kamera (2): Unterschied zwischen den Versionen
Aus DGL Wiki
Andyh (Diskussion | Beiträge) |
Andyh (Diskussion | Beiträge) |
||
Zeile 6: | Zeile 6: | ||
// was leider direkt zu Beginn meiner OpenGL Karriere geschehen | // was leider direkt zu Beginn meiner OpenGL Karriere geschehen | ||
// musste, halte ich dieses Produkt schon fuer ziemlich ausgereift. | // musste, halte ich dieses Produkt schon fuer ziemlich ausgereift. | ||
− | // Sollten allerdings Verbesserungen eingebracht werden oder | + | // Sollten allerdings Verbesserungen eingebracht werden oder |
− | // | + | // Verstaendnisfragen entstehen, so mailt bitte an |
// | // | ||
// Andree.Heyroth@t-online.de | // Andree.Heyroth@t-online.de | ||
Zeile 20: | Zeile 20: | ||
// gegeben wurden und es zu EAccessViolations kam. Die Methode wird | // gegeben wurden und es zu EAccessViolations kam. Die Methode wird | ||
// jetzt in der PUBLIC Section mit der Direktive OVERRIDE aufgerufen. | // jetzt in der PUBLIC Section mit der Direktive OVERRIDE aufgerufen. | ||
+ | // | ||
+ | // 11.11.2005 | ||
+ | // Die Positionierung funktioniert jetzt. | ||
+ | // Wegen eines Verstaendnisproblems wurden die Positionen immer auf den | ||
+ | // Kamerapunkt aufaddiert. Das bedeutete, dass die Positionierung aus | ||
+ | // dem Ruder lief wenn sie nicht im Nullpunkt stattfand. Je groesser die | ||
+ | // gewuenschte Position war um so groesser war die Abweichung von der | ||
+ | // Darstellung. | ||
+ | // Ich habe nicht bedacht, dass bei einer "Kamera"-bewegung und -drehung | ||
+ | // ja eigentlich die Szene bewegt und gedreht wird. Deswegen wurden nach | ||
+ | // einer Positionierung die folgenden Projektionen immer basierend auf der | ||
+ | // danach gueltigen Kameraposition gemacht. | ||
+ | // Jetzt wird die Position so gesetzt, dass die gewuenschte Kameraposition | ||
+ | // immer vor dem Betrachter steht. | ||
// | // | ||
unit Camera; | unit Camera; | ||
Zeile 25: | Zeile 39: | ||
interface | interface | ||
− | Uses DglOpenGL, OpenGLUtil, Windows, Classes; | + | Uses DglOpenGL, OpenGLUtil, Windows, Classes; |
− | type | + | type |
TCameraMatrix=Class | TCameraMatrix=Class | ||
Matrix: TArrMatrix; | Matrix: TArrMatrix; | ||
InverseMatrix: TArrMatrix; | InverseMatrix: TArrMatrix; | ||
+ | //constructor Create; | ||
+ | //destructor destroy; | ||
procedure Identity; | procedure Identity; | ||
procedure Load(M: TArrMatrix); | procedure Load(M: TArrMatrix); | ||
− | |||
end; | end; | ||
TCamera=Class | TCamera=Class | ||
CameraMatrix: TCameraMatrix; | CameraMatrix: TCameraMatrix; | ||
+ | HomeMatrix: TCameraMatrix; | ||
Enabled : boolean; | Enabled : boolean; | ||
Initiated: boolean; | Initiated: boolean; | ||
− | + | FPosition: TGLvector; | |
+ | FPointOfRotation: TGLvector; | ||
+ | FPositionOffset: TGLvector; | ||
function UpVector: TGLvector; | function UpVector: TGLvector; | ||
function ViewDirection: TGLvector; | function ViewDirection: TGLvector; | ||
procedure RestorePosition(pos: integer); | procedure RestorePosition(pos: integer); | ||
procedure SavePosition(pos: integer); | procedure SavePosition(pos: integer); | ||
+ | function GivePosition(pos: integer): TGLvector; | ||
procedure RotateCamera(ix, iy, iz: TGLdouble); | procedure RotateCamera(ix, iy, iz: TGLdouble); | ||
procedure TranslateCamera(ix, iy, iz: TGLdouble); | procedure TranslateCamera(ix, iy, iz: TGLdouble); | ||
procedure CameraHome; | procedure CameraHome; | ||
− | procedure PositionCamera(PositionVec: TGLvector; | + | procedure PositionCamera(PositionVec: TGLvector; |
− | + | ViewVec: TGLvector; | |
− | + | upVec: TGLvector); | |
procedure Adjust; | procedure Adjust; | ||
procedure Apply; | procedure Apply; | ||
procedure ApplyForTerrain; | procedure ApplyForTerrain; | ||
private | private | ||
− | |||
PosArray: array [0..9] of TCameraMatrix; | PosArray: array [0..9] of TCameraMatrix; | ||
− | + | function GetPosition: TGLvector; | |
+ | procedure SetPosition (Pos: TGLvector); | ||
procedure Identity; | procedure Identity; | ||
procedure RotateMatrix(ix, iy, iz: TGLdouble); | procedure RotateMatrix(ix, iy, iz: TGLdouble); | ||
Zeile 67: | Zeile 86: | ||
published | published | ||
property PointOfRotation: TGLvector read FPointOfRotation; | property PointOfRotation: TGLvector read FPointOfRotation; | ||
+ | property Position: TGLvector read GetPosition write SetPosition; | ||
end; | end; | ||
TPCamera=^TCamera; | TPCamera=^TCamera; | ||
Zeile 72: | Zeile 92: | ||
implementation | implementation | ||
+ | uses SysUtils; | ||
+ | |||
+ | { | ||
constructor TCameraMatrix.Create; | constructor TCameraMatrix.Create; | ||
− | |||
begin | begin | ||
− | + | inherited create; | |
+ | end; | ||
+ | |||
+ | destructor TCameraMatrix.Destroy; | ||
+ | begin | ||
+ | inherited destroy; | ||
end; | end; | ||
+ | } | ||
procedure TCameraMatrix.Identity; | procedure TCameraMatrix.Identity; | ||
− | // | + | // GetArrIdentity: aus OpenGL.pas |
− | + | // initialisiert die CameraMatrix mit der Identitaetsmatrix | |
− | |||
begin | begin | ||
− | Matrix := | + | Matrix := GetIdentity(Matrix); |
− | InverseMatrix := | + | InverseMatrix := GetIdentity(InverseMatrix); |
end; | end; | ||
procedure TCameraMatrix.Load(M: TArrMatrix); | procedure TCameraMatrix.Load(M: TArrMatrix); | ||
− | // die Matrix mit den Werten einer beliebigen anderen matrix | + | // die Matrix mit den Werten einer beliebigen anderen matrix fuellen |
var | var | ||
i: integer; | i: integer; | ||
begin | begin | ||
for i:=0 to 15 do | for i:=0 to 15 do | ||
− | Matrix[i]:=M[i]; | + | Matrix[i]:=M[i]; |
// die invertierte Matrix kann benutzt werden um Objkekte z.B. | // die invertierte Matrix kann benutzt werden um Objkekte z.B. | ||
// immer zum Benutzer auszurichten | // immer zum Benutzer auszurichten | ||
− | InvertMatrix (M, InverseMatrix); // | + | InvertMatrix (M, InverseMatrix); |
+ | end; | ||
+ | |||
+ | constructor TCamera.Create; | ||
+ | var | ||
+ | i: integer; | ||
+ | begin | ||
+ | inherited create; | ||
+ | |||
+ | // Initiated wird gebraucht um einmal alle Positionsspeicher | ||
+ | // mit der Anfangsposition zu belegen | ||
+ | Initiated := false; | ||
+ | |||
+ | // Kameramatrix anlegen | ||
+ | CameraMatrix := TCameraMatrix.Create; | ||
+ | |||
+ | // Matrix der letzten Position von PositionCamera anlegen | ||
+ | HomeMatrix := TCameraMatrix.Create; | ||
+ | |||
+ | // Positionsspeicher anlegen | ||
+ | for i := 0 to 9 do | ||
+ | PosArray[i] := TCameraMatrix.Create; | ||
+ | end; | ||
+ | |||
+ | destructor TCamera.Destroy; | ||
+ | // alle in create belegten Resourcen wieder freigeben | ||
+ | var | ||
+ | i: integer; | ||
+ | begin | ||
+ | FreeAndNil (CameraMatrix); | ||
+ | FreeAndNil (HomeMatrix); | ||
+ | for i := 0 to 9 do | ||
+ | FreeAndNil (PosArray[i]); | ||
+ | |||
+ | inherited destroy; | ||
end; | end; | ||
Zeile 108: | Zeile 169: | ||
glPushMatrix(); | glPushMatrix(); | ||
// aktuelle Position und Lage der Kamera herstellen | // aktuelle Position und Lage der Kamera herstellen | ||
− | glLoadMatrixf(@CameraMatrix.Matrix); | + | glLoadMatrixf(@CameraMatrix.Matrix); |
− | // wenn | + | |
+ | // wenn gewuenscht um die X-Achse drehen | ||
if(rx <> 0) then | if(rx <> 0) then | ||
− | glRotatef(rx,1,0,0); | + | glRotatef(rx,1,0,0); |
− | // wenn | + | |
+ | // wenn gewuenscht um die Y-Achse drehen | ||
if(ry <> 0) then | if(ry <> 0) then | ||
− | glRotatef(ry,0,1,0); | + | glRotatef(ry,0,1,0); |
− | // wenn | + | |
+ | // wenn gewuenscht um die Z-Achse drehen | ||
if(rz <> 0) then | if(rz <> 0) then | ||
− | glRotatef(rz,0,0,1); | + | glRotatef(rz,0,0,1); |
+ | |||
// die neu erzeugte Matrix auslesen | // die neu erzeugte Matrix auslesen | ||
− | glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); | + | glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); |
// und in die Kameramatrix sichern | // und in die Kameramatrix sichern | ||
− | CameraMatrix.Load(newMatrix); | + | CameraMatrix.Load(newMatrix); |
glPopMatrix(); | glPopMatrix(); | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end; | end; | ||
Zeile 147: | Zeile 196: | ||
Enabled := true; | Enabled := true; | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
end; | end; | ||
Zeile 174: | Zeile 212: | ||
// nehme, wird sie auf den bildschirmachsen verschoben. das ist angenehmer | // nehme, wird sie auf den bildschirmachsen verschoben. das ist angenehmer | ||
// zum arbeiten | // zum arbeiten | ||
− | + | newMatrix := Multiply (newMatrix, CameraMatrix.Matrix); | |
CameraMatrix.Load(newMatrix); | CameraMatrix.Load(newMatrix); | ||
glPopMatrix(); | glPopMatrix(); | ||
end; | end; | ||
− | procedure TCamera.PositionCamera(PositionVec: TGLvector; | + | |
− | + | procedure TCamera.PositionCamera(PositionVec: TGLvector; | |
− | + | ViewVec: TGLvector; | |
− | + | upVec: TGLvector); | |
− | |||
var | var | ||
newMatrix: TArrMatrix; | newMatrix: TArrMatrix; | ||
i: integer; | i: integer; | ||
+ | P, V, U: TGLvector; | ||
+ | Laenge: TGLdouble; | ||
begin | begin | ||
− | // | + | // die gewuenschte konstruktion immer auf die Z-ebene projizieren. |
+ | // zuerst die position in den nullpunkt holen | ||
+ | InitVector (P, 0, 0, 0); | ||
+ | // jetzt den viewpoint um den gleichen betrag reduzieren, damit | ||
+ | // die gerade parallel verschoben wird. | ||
+ | V := SubtractVector (ViewVec, PositionVec); | ||
+ | // U ist halt schneller geschrieben als upVec... | ||
+ | U := upVec; | ||
+ | // den betrag ermitteln, um den die kamera nachher auf der Z-Achse | ||
+ | // verschoben werden muss | ||
+ | Laenge := Magnitude (SubtractVector (P, V)); | ||
+ | |||
Identity; | Identity; | ||
− | |||
FPointOfRotation := ViewVec; | FPointOfRotation := ViewVec; | ||
− | + | ||
glMatrixMode (GL_MODELVIEW); | glMatrixMode (GL_MODELVIEW); | ||
glPushMatrix; | glPushMatrix; | ||
glLoadIdentity; | glLoadIdentity; | ||
− | + | ||
− | gluLookAt ( | + | // glulookat wird die matrix parallel zur Z-achse ausrichten |
− | + | gluLookAt (P.X, P.Y, P.Z, V.X, V.Y, V.Z, U.X, U.Y, U.Z); | |
− | |||
glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); | glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); | ||
+ | glPopMatrix; | ||
+ | |||
CameraMatrix.Load(newMatrix); | CameraMatrix.Load(newMatrix); | ||
HomeMatrix.Load(newMatrix); | HomeMatrix.Load(newMatrix); | ||
− | + | ||
+ | // da wir uns jetzt am zielpunkt befinden, müssen wir auf der Z-achse | ||
+ | // wieder zurück zur kameraposition | ||
+ | Offset (0, 0, -Laenge); | ||
+ | |||
+ | // damit GetPosition den Wert zurückgibt den wir mit PositionCamera | ||
+ | // eingestellt haben, müssen wir die zu der von gluLookAt errechneten | ||
+ | // Position bestehende Differenz errechnen | ||
+ | FPositionOffset.X := PositionVec.X - CameraMatrix.Matrix[12]; | ||
+ | FPositionOffset.Y := PositionVec.Y - CameraMatrix.Matrix[13]; | ||
+ | FPositionOffset.Z := PositionVec.Z - CameraMatrix.Matrix[14]; | ||
+ | |||
// alle positionsspeicher mit der Kameraposition, Blickrichtung | // alle positionsspeicher mit der Kameraposition, Blickrichtung | ||
// und dem upVector belegen. Nur beim ersten Aufruf von | // und dem upVector belegen. Nur beim ersten Aufruf von | ||
Zeile 216: | Zeile 277: | ||
procedure TCamera.CameraHome; | procedure TCamera.CameraHome; | ||
− | // Kamera in die beim letzten Aufruf von PositionCamera | + | // Kamera in die beim letzten Aufruf von PositionCamera übergebene |
// Position/Lage bringen | // Position/Lage bringen | ||
begin | begin | ||
Zeile 226: | Zeile 287: | ||
begin | begin | ||
if (pos < 0) or (pos > 9) then | if (pos < 0) or (pos > 9) then | ||
− | exit; | + | exit; |
+ | |||
PosArray[pos].Load(CameraMatrix.Matrix); | PosArray[pos].Load(CameraMatrix.Matrix); | ||
end; | end; | ||
Zeile 234: | Zeile 296: | ||
begin | begin | ||
if (pos < 0) or (pos > 9) then | if (pos < 0) or (pos > 9) then | ||
− | exit; | + | exit; |
+ | |||
CameraMatrix.Load(PosArray[pos].Matrix); | CameraMatrix.Load(PosArray[pos].Matrix); | ||
+ | end; | ||
+ | |||
+ | function TCamera.GivePosition (pos: integer): TGLvector; | ||
+ | // gibt den Inhalt des durch pos bestimmten | ||
+ | // Positionsspecihers zurueck | ||
+ | begin | ||
+ | if (pos < 0) or (pos > 9) then | ||
+ | exit; | ||
+ | |||
+ | result.X := PosArray[pos].Matrix[12]; | ||
+ | result.Y := PosArray[pos].Matrix[13]; | ||
+ | result.Z := PosArray[pos].Matrix[14]; | ||
end; | end; | ||
procedure TCamera.TranslateCamera(ix, iy, iz: TGLdouble); | procedure TCamera.TranslateCamera(ix, iy, iz: TGLdouble); | ||
+ | // vom Benutzer aufzurufende Methode um eine Verschiebung | ||
+ | // durchzufuehren | ||
begin | begin | ||
Offset (ix, iy, iz); | Offset (ix, iy, iz); | ||
Zeile 244: | Zeile 321: | ||
procedure TCamera.RotateCamera(ix, iy, iz: TGLdouble); | procedure TCamera.RotateCamera(ix, iy, iz: TGLdouble); | ||
+ | // vom Benutzer aufzurufende Methode um eine Drehung | ||
+ | // durchzufuehren | ||
begin | begin | ||
RotateMatrix (ix, iy, iz); | RotateMatrix (ix, iy, iz); | ||
Zeile 250: | Zeile 329: | ||
procedure TCamera.Apply; | procedure TCamera.Apply; | ||
// hier wird die Kamera eingeschaltet. Nach dem Aufruf dieser Prozedur | // hier wird die Kamera eingeschaltet. Nach dem Aufruf dieser Prozedur | ||
− | // sollte die Szene mit allen | + | // sollte die Szene mit allen benoetigten Drehungen, Verschiebungen |
// gezeichnet werden. | // gezeichnet werden. | ||
begin | begin | ||
if not Enabled then | if not Enabled then | ||
− | exit; | + | exit; |
+ | |||
glMatrixMode (GL_MODELVIEW); | glMatrixMode (GL_MODELVIEW); | ||
glLoadMatrixf(@CameraMatrix.Matrix); | glLoadMatrixf(@CameraMatrix.Matrix); | ||
− | glTranslatef (-PointOfRotation.X, -PointOfRotation.y, -PointOfRotation.Z); | + | glTranslatef (-PointOfRotation.X, |
+ | -PointOfRotation.y, | ||
+ | -PointOfRotation.Z); | ||
end; | end; | ||
Zeile 266: | Zeile 348: | ||
begin | begin | ||
if not Enabled then | if not Enabled then | ||
− | exit; | + | exit; |
+ | |||
glMatrixMode (GL_MODELVIEW); | glMatrixMode (GL_MODELVIEW); | ||
+ | // für das Terrain nur die Drehung ausführen | ||
glLoadMatrixf(@CameraMatrix.Matrix); | glLoadMatrixf(@CameraMatrix.Matrix); | ||
+ | // deswegen jetzt die verschiebung zurücknehmen | ||
glTranslatef (CameraMatrix.InverseMatrix[12], | glTranslatef (CameraMatrix.InverseMatrix[12], | ||
CameraMatrix.InverseMatrix[13], | CameraMatrix.InverseMatrix[13], | ||
Zeile 276: | Zeile 361: | ||
procedure TCamera.RotateMatrix (ix, iy, iz: TGLdouble); | procedure TCamera.RotateMatrix (ix, iy, iz: TGLdouble); | ||
begin | begin | ||
− | RotateRoundAxis (iy, ix, iz); | + | // um den austausch von verschiedenen kameramodulen so einfach |
+ | // wie möglich zu gestalten, kann hier ein bisschen variiert werden... | ||
+ | RotateRoundAxis (-iy, -ix, -iz); | ||
end; | end; | ||
− | function TCamera. | + | function TCamera.GetPosition: TGLvector; |
− | // | + | // diese Property-Funktion fragt die aktuelle Position der Kamera ab |
− | |||
var | var | ||
return: TGLvector; | return: TGLvector; | ||
Zeile 290: | Zeile 376: | ||
CameraMatrix.Matrix[13], | CameraMatrix.Matrix[13], | ||
CameraMatrix.Matrix[14]); | CameraMatrix.Matrix[14]); | ||
+ | return := AddVector (return, FPositionOffset); | ||
result := return; | result := return; | ||
+ | end; | ||
+ | |||
+ | procedure TCamera.SetPosition (Pos: TGLvector); | ||
+ | // diese Property-Funktion setzt eine neue Position der Kamera | ||
+ | begin | ||
+ | // position: letzte Spalte der Matrix | ||
+ | CameraMatrix.Matrix[12] := Pos.X; | ||
+ | CameraMatrix.Matrix[13] := Pos.Y; | ||
+ | CameraMatrix.Matrix[14] := Pos.Z; | ||
end; | end; | ||
Zeile 318: | Zeile 414: | ||
CameraMatrix.Matrix[05], | CameraMatrix.Matrix[05], | ||
CameraMatrix.Matrix[06]); | CameraMatrix.Matrix[06]); | ||
− | + | result := return; | |
end; | end; | ||
procedure TCamera.Adjust; | procedure TCamera.Adjust; | ||
− | // mit dieser Prozedur kann die Kamera zu jeder Zeit, | + | // mit dieser Prozedur kann die Kamera zu jeder Zeit, unabhaengig |
// von Drehung und Position, senkrecht zur Y-Achse ausgerichtet | // von Drehung und Position, senkrecht zur Y-Achse ausgerichtet | ||
// werden. Die aktuelle Position wird dabei beibehalten. | // werden. Die aktuelle Position wird dabei beibehalten. | ||
Zeile 328: | Zeile 424: | ||
temp: TArrMatrix; | temp: TArrMatrix; | ||
begin | begin | ||
− | + | temp := GetIdentity(temp); | |
− | |||
− | temp := | ||
temp[12] := CameraMatrix.Matrix[12]; | temp[12] := CameraMatrix.Matrix[12]; | ||
temp[13] := CameraMatrix.Matrix[13]; | temp[13] := CameraMatrix.Matrix[13]; |
Version vom 13. November 2005, 12:53 Uhr
Eine Beschreibung findet ihr unter Kamera (1).
Die verwendete Toolsammlung findet ihr unter Kamera (3).
// Da ich einige Monate gebraucht habe um diese Kamera zu bauen, // was leider direkt zu Beginn meiner OpenGL Karriere geschehen // musste, halte ich dieses Produkt schon fuer ziemlich ausgereift. // Sollten allerdings Verbesserungen eingebracht werden oder // Verstaendnisfragen entstehen, so mailt bitte an // // Andree.Heyroth@t-online.de // // Danke. // // Updates: // // 06.11.2005 // Die Deklaration der DESTROY Methode war falsch. Das fuehrte dazu, // dass in der Methode CREATE erzeugte Objekte nicht richtig frei- // gegeben wurden und es zu EAccessViolations kam. Die Methode wird // jetzt in der PUBLIC Section mit der Direktive OVERRIDE aufgerufen. // // 11.11.2005 // Die Positionierung funktioniert jetzt. // Wegen eines Verstaendnisproblems wurden die Positionen immer auf den // Kamerapunkt aufaddiert. Das bedeutete, dass die Positionierung aus // dem Ruder lief wenn sie nicht im Nullpunkt stattfand. Je groesser die // gewuenschte Position war um so groesser war die Abweichung von der // Darstellung. // Ich habe nicht bedacht, dass bei einer "Kamera"-bewegung und -drehung // ja eigentlich die Szene bewegt und gedreht wird. Deswegen wurden nach // einer Positionierung die folgenden Projektionen immer basierend auf der // danach gueltigen Kameraposition gemacht. // Jetzt wird die Position so gesetzt, dass die gewuenschte Kameraposition // immer vor dem Betrachter steht. // unit Camera; interface Uses DglOpenGL, OpenGLUtil, Windows, Classes; type TCameraMatrix=Class Matrix: TArrMatrix; InverseMatrix: TArrMatrix; //constructor Create; //destructor destroy; procedure Identity; procedure Load(M: TArrMatrix); end; TCamera=Class CameraMatrix: TCameraMatrix; HomeMatrix: TCameraMatrix; Enabled : boolean; Initiated: boolean; FPosition: TGLvector; FPointOfRotation: TGLvector; FPositionOffset: TGLvector; function UpVector: TGLvector; function ViewDirection: TGLvector; procedure RestorePosition(pos: integer); procedure SavePosition(pos: integer); function GivePosition(pos: integer): TGLvector; procedure RotateCamera(ix, iy, iz: TGLdouble); procedure TranslateCamera(ix, iy, iz: TGLdouble); procedure CameraHome; procedure PositionCamera(PositionVec: TGLvector; ViewVec: TGLvector; upVec: TGLvector); procedure Adjust; procedure Apply; procedure ApplyForTerrain; private PosArray: array [0..9] of TCameraMatrix; function GetPosition: TGLvector; procedure SetPosition (Pos: TGLvector); procedure Identity; procedure RotateMatrix(ix, iy, iz: TGLdouble); procedure Offset(x, y, z: TGLfloat); procedure RotateRoundAxis(rx, ry, rz: TGLfloat); public constructor Create; destructor Destroy;override; published property PointOfRotation: TGLvector read FPointOfRotation; property Position: TGLvector read GetPosition write SetPosition; end; TPCamera=^TCamera; implementation uses SysUtils; { constructor TCameraMatrix.Create; begin inherited create; end; destructor TCameraMatrix.Destroy; begin inherited destroy; end; } procedure TCameraMatrix.Identity; // GetArrIdentity: aus OpenGL.pas // initialisiert die CameraMatrix mit der Identitaetsmatrix begin Matrix := GetIdentity(Matrix); InverseMatrix := GetIdentity(InverseMatrix); end; procedure TCameraMatrix.Load(M: TArrMatrix); // die Matrix mit den Werten einer beliebigen anderen matrix fuellen var i: integer; begin for i:=0 to 15 do Matrix[i]:=M[i]; // die invertierte Matrix kann benutzt werden um Objkekte z.B. // immer zum Benutzer auszurichten InvertMatrix (M, InverseMatrix); end; constructor TCamera.Create; var i: integer; begin inherited create; // Initiated wird gebraucht um einmal alle Positionsspeicher // mit der Anfangsposition zu belegen Initiated := false; // Kameramatrix anlegen CameraMatrix := TCameraMatrix.Create; // Matrix der letzten Position von PositionCamera anlegen HomeMatrix := TCameraMatrix.Create; // Positionsspeicher anlegen for i := 0 to 9 do PosArray[i] := TCameraMatrix.Create; end; destructor TCamera.Destroy; // alle in create belegten Resourcen wieder freigeben var i: integer; begin FreeAndNil (CameraMatrix); FreeAndNil (HomeMatrix); for i := 0 to 9 do FreeAndNil (PosArray[i]); inherited destroy; end; procedure TCamera.RotateRoundAxis(rx, ry, rz: TGLfloat); // hier drehen wir jetzt um die einzelnen Achsen. // die Parameter geben die "Drehgeschwindigkeit" vor. var newMatrix: TArrMatrix; begin glMatrixMode (GL_MODELVIEW); glPushMatrix(); // aktuelle Position und Lage der Kamera herstellen glLoadMatrixf(@CameraMatrix.Matrix); // wenn gewuenscht um die X-Achse drehen if(rx <> 0) then glRotatef(rx,1,0,0); // wenn gewuenscht um die Y-Achse drehen if(ry <> 0) then glRotatef(ry,0,1,0); // wenn gewuenscht um die Z-Achse drehen if(rz <> 0) then glRotatef(rz,0,0,1); // die neu erzeugte Matrix auslesen glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); // und in die Kameramatrix sichern CameraMatrix.Load(newMatrix); glPopMatrix(); end; procedure TCamera.Identity; begin CameraMatrix.Identity; HomeMatrix.Identity; Enabled := true; end; procedure TCamera.Offset(x, y, z: TGLfloat); // verschieben der Kamera auf einer beliebigen Achse var newMatrix: TArrMatrix; begin glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity; glTranslatef(x,y,z); glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); // wenn ich mit der funktion glMultMatrixf arbeite, wird die zeichnung // immer entlang der richtigen achsen verschoben. wenn ich matrixmultiply // nehme, wird sie auf den bildschirmachsen verschoben. das ist angenehmer // zum arbeiten newMatrix := Multiply (newMatrix, CameraMatrix.Matrix); CameraMatrix.Load(newMatrix); glPopMatrix(); end; procedure TCamera.PositionCamera(PositionVec: TGLvector; ViewVec: TGLvector; upVec: TGLvector); var newMatrix: TArrMatrix; i: integer; P, V, U: TGLvector; Laenge: TGLdouble; begin // die gewuenschte konstruktion immer auf die Z-ebene projizieren. // zuerst die position in den nullpunkt holen InitVector (P, 0, 0, 0); // jetzt den viewpoint um den gleichen betrag reduzieren, damit // die gerade parallel verschoben wird. V := SubtractVector (ViewVec, PositionVec); // U ist halt schneller geschrieben als upVec... U := upVec; // den betrag ermitteln, um den die kamera nachher auf der Z-Achse // verschoben werden muss Laenge := Magnitude (SubtractVector (P, V)); Identity; FPointOfRotation := ViewVec; glMatrixMode (GL_MODELVIEW); glPushMatrix; glLoadIdentity; // glulookat wird die matrix parallel zur Z-achse ausrichten gluLookAt (P.X, P.Y, P.Z, V.X, V.Y, V.Z, U.X, U.Y, U.Z); glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); glPopMatrix; CameraMatrix.Load(newMatrix); HomeMatrix.Load(newMatrix); // da wir uns jetzt am zielpunkt befinden, müssen wir auf der Z-achse // wieder zurück zur kameraposition Offset (0, 0, -Laenge); // damit GetPosition den Wert zurückgibt den wir mit PositionCamera // eingestellt haben, müssen wir die zu der von gluLookAt errechneten // Position bestehende Differenz errechnen FPositionOffset.X := PositionVec.X - CameraMatrix.Matrix[12]; FPositionOffset.Y := PositionVec.Y - CameraMatrix.Matrix[13]; FPositionOffset.Z := PositionVec.Z - CameraMatrix.Matrix[14]; // alle positionsspeicher mit der Kameraposition, Blickrichtung // und dem upVector belegen. Nur beim ersten Aufruf von // PositionCamera if not Initiated then begin for i := 0 to 9 do SavePosition (i); Initiated := true; end; end; procedure TCamera.CameraHome; // Kamera in die beim letzten Aufruf von PositionCamera übergebene // Position/Lage bringen begin CameraMatrix.Load(HomeMatrix.Matrix); end; procedure TCamera.SavePosition (pos: integer); // wie der Prozedurname schon sagt... begin if (pos < 0) or (pos > 9) then exit; PosArray[pos].Load(CameraMatrix.Matrix); end; procedure TCamera.RestorePosition (pos: integer); // wie der Prozedurname schon sagt... begin if (pos < 0) or (pos > 9) then exit; CameraMatrix.Load(PosArray[pos].Matrix); end; function TCamera.GivePosition (pos: integer): TGLvector; // gibt den Inhalt des durch pos bestimmten // Positionsspecihers zurueck begin if (pos < 0) or (pos > 9) then exit; result.X := PosArray[pos].Matrix[12]; result.Y := PosArray[pos].Matrix[13]; result.Z := PosArray[pos].Matrix[14]; end; procedure TCamera.TranslateCamera(ix, iy, iz: TGLdouble); // vom Benutzer aufzurufende Methode um eine Verschiebung // durchzufuehren begin Offset (ix, iy, iz); end; procedure TCamera.RotateCamera(ix, iy, iz: TGLdouble); // vom Benutzer aufzurufende Methode um eine Drehung // durchzufuehren begin RotateMatrix (ix, iy, iz); end; procedure TCamera.Apply; // hier wird die Kamera eingeschaltet. Nach dem Aufruf dieser Prozedur // sollte die Szene mit allen benoetigten Drehungen, Verschiebungen // gezeichnet werden. begin if not Enabled then exit; glMatrixMode (GL_MODELVIEW); glLoadMatrixf(@CameraMatrix.Matrix); glTranslatef (-PointOfRotation.X, -PointOfRotation.y, -PointOfRotation.Z); end; procedure TCamera.ApplyForTerrain; // hier wird wie in Apply die Kamera eingeschaltet. da man um ein terrain // (skycube, ...) anzuzeigen aber immer die gleiche entfernung zur welt // einhalten muss, wird hier nur gedreht und nicht verschoben. begin if not Enabled then exit; glMatrixMode (GL_MODELVIEW); // für das Terrain nur die Drehung ausführen glLoadMatrixf(@CameraMatrix.Matrix); // deswegen jetzt die verschiebung zurücknehmen glTranslatef (CameraMatrix.InverseMatrix[12], CameraMatrix.InverseMatrix[13], CameraMatrix.InverseMatrix[14]); end; procedure TCamera.RotateMatrix (ix, iy, iz: TGLdouble); begin // um den austausch von verschiedenen kameramodulen so einfach // wie möglich zu gestalten, kann hier ein bisschen variiert werden... RotateRoundAxis (-iy, -ix, -iz); end; function TCamera.GetPosition: TGLvector; // diese Property-Funktion fragt die aktuelle Position der Kamera ab var return: TGLvector; begin // position: letzte Spalte der Matrix InitVector (return, CameraMatrix.Matrix[12], CameraMatrix.Matrix[13], CameraMatrix.Matrix[14]); return := AddVector (return, FPositionOffset); result := return; end; procedure TCamera.SetPosition (Pos: TGLvector); // diese Property-Funktion setzt eine neue Position der Kamera begin // position: letzte Spalte der Matrix CameraMatrix.Matrix[12] := Pos.X; CameraMatrix.Matrix[13] := Pos.Y; CameraMatrix.Matrix[14] := Pos.Z; end; function TCamera.ViewDirection: TGLvector; // mit dieser Funktion kann die aktuelle Blickrichtung der Kamera // abgefragt werden var return: TGLvector; begin // view direction: dritte Spalte der Matrix (Z-Achse) InitVector (return, CameraMatrix.Matrix[08], CameraMatrix.Matrix[09], CameraMatrix.Matrix[10]); result := return; end; function TCamera.UpVector: TGLvector; // mit dieser Funktion kann die aktuelle Ausrichtung der Kamera // abgefragt werden var return: TGLvector; begin // upVector: zweite Spalte der Matrix (Y-Achse) InitVector (return, CameraMatrix.Matrix[04], CameraMatrix.Matrix[05], CameraMatrix.Matrix[06]); result := return; end; procedure TCamera.Adjust; // mit dieser Prozedur kann die Kamera zu jeder Zeit, unabhaengig // von Drehung und Position, senkrecht zur Y-Achse ausgerichtet // werden. Die aktuelle Position wird dabei beibehalten. var temp: TArrMatrix; begin temp := GetIdentity(temp); temp[12] := CameraMatrix.Matrix[12]; temp[13] := CameraMatrix.Matrix[13]; temp[14] := CameraMatrix.Matrix[14]; temp[15] := CameraMatrix.Matrix[15]; CameraMatrix.Load(temp); end; end.