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.