Kamera (2): Unterschied zwischen den Versionen
Aus DGL Wiki
Andyh (Diskussion | Beiträge) |
Andyh (Diskussion | Beiträge) |
||
Zeile 53: | Zeile 53: | ||
// ein neues Setzen der Property FPointOfRotation weil dabei die Szene in das | // ein neues Setzen der Property FPointOfRotation weil dabei die Szene in das | ||
// Koordinatenkreuz geschoben wird. | // Koordinatenkreuz geschoben wird. | ||
+ | // | ||
+ | // 31.01.2006 | ||
+ | // Umstellung auf genaueres Zahlenformat | ||
+ | // Da die Darstellung von Szenen ausserhalb des Bereichs von FLOAT-Zahlen | ||
+ | // nicht funktioniert, muss alles auf DOUBLE umgestellt werden. Dazu gehört | ||
+ | // das Ersetzen von Datentypen und der Aufruf der entsprechenden GL-Funktionen. | ||
// | // | ||
unit Camera; | unit Camera; | ||
Zeile 58: | Zeile 64: | ||
interface | interface | ||
− | Uses DglOpenGL, | + | Uses DglOpenGL, Util, Windows, Classes; |
type | type | ||
Zeile 80: | Zeile 86: | ||
procedure SavePosition(pos: integer); | procedure SavePosition(pos: integer); | ||
function GiveStoredPosition(pos: integer): TGLvector; | function GiveStoredPosition(pos: integer): TGLvector; | ||
− | procedure RotateCamera(ix, iy, iz: | + | procedure RotateCamera(ix, iy, iz: GLdouble); |
− | procedure TranslateCamera(ix, iy, iz: | + | procedure TranslateCamera(ix, iy, iz: GLdouble); |
procedure CameraHome; | procedure CameraHome; | ||
procedure PositionCamera(PositionVec: TGLvector; ViewVec: TGLvector; upVec: TGLvector); | procedure PositionCamera(PositionVec: TGLvector; ViewVec: TGLvector; upVec: TGLvector); | ||
Zeile 105: | Zeile 111: | ||
procedure SetPosition (Pos: TGLvector); | procedure SetPosition (Pos: TGLvector); | ||
procedure Identity; | procedure Identity; | ||
− | procedure Offset(x, y, z: | + | procedure Offset(x, y, z: GLdouble); |
− | procedure RotateRoundAxis(rx, ry, rz: | + | procedure RotateRoundAxis(rx, ry, rz: GLdouble); |
procedure SetPointOfRotation (NewPoint: TGLvector); | procedure SetPointOfRotation (NewPoint: TGLvector); | ||
public | public | ||
Zeile 112: | Zeile 118: | ||
destructor Destroy;override; | destructor Destroy;override; | ||
function InverseMatrix: TArrMatrix; | function InverseMatrix: TArrMatrix; | ||
+ | procedure ApplyInvers; | ||
procedure PositionCross(CrossVec: TGLvector); | procedure PositionCross(CrossVec: TGLvector); | ||
published | published | ||
Zeile 128: | Zeile 135: | ||
implementation | implementation | ||
− | uses SysUtils | + | uses SysUtils; |
constructor TCameraMatrix.Create; | constructor TCameraMatrix.Create; | ||
Zeile 217: | Zeile 224: | ||
end; | end; | ||
− | procedure TCamera.RotateRoundAxis(rx, ry, rz: | + | procedure TCamera.RotateRoundAxis(rx, ry, rz: GLdouble); |
// hier drehen wir jetzt um die einzelnen Achsen. | // hier drehen wir jetzt um die einzelnen Achsen. | ||
// die Parameter geben die "Drehgeschwindigkeit" vor. | // die Parameter geben die "Drehgeschwindigkeit" vor. | ||
Zeile 228: | Zeile 235: | ||
// aktuelle Position und Lage der Kamera herstellen | // aktuelle Position und Lage der Kamera herstellen | ||
− | + | glLoadMatrixd(@CameraMatrix.Matrix); | |
if FFixedAxis then | if FFixedAxis then | ||
Zeile 238: | Zeile 245: | ||
// wenn gewuenscht um die X-Achse drehen | // wenn gewuenscht um die X-Achse drehen | ||
if(rx <> 0) then | if(rx <> 0) then | ||
− | + | glRotated(rx,tempX.X,tempX.Y,tempX.Z); | |
// wenn gewuenscht um die Y-Achse drehen | // wenn gewuenscht um die Y-Achse drehen | ||
if(ry <> 0) then | if(ry <> 0) then | ||
− | + | glRotated(ry,tempY.X,tempY.Y,tempY.Z); | |
// wenn gewuenscht um die Z-Achse drehen | // wenn gewuenscht um die Z-Achse drehen | ||
if(rz <> 0) then | if(rz <> 0) then | ||
− | + | glRotated(rz,tempZ.X,tempZ.Y,tempZ.Z); | |
end | end | ||
else | else | ||
Zeile 253: | Zeile 260: | ||
// wenn gewuenscht um die X-Achse drehen | // wenn gewuenscht um die X-Achse drehen | ||
if(rx <> 0) then | if(rx <> 0) then | ||
− | + | glRotated(rx,1,0,0); | |
// wenn gewuenscht um die Y-Achse drehen | // wenn gewuenscht um die Y-Achse drehen | ||
if(ry <> 0) then | if(ry <> 0) then | ||
− | + | glRotated(ry,0,1,0); | |
// wenn gewuenscht um die Z-Achse drehen | // wenn gewuenscht um die Z-Achse drehen | ||
if(rz <> 0) then | if(rz <> 0) then | ||
− | + | glRotated(rz,0,0,1); | |
end; | end; | ||
// die neu erzeugte Matrix auslesen | // die neu erzeugte Matrix auslesen | ||
− | + | glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); | |
glPopMatrix(); | glPopMatrix(); | ||
Zeile 281: | Zeile 288: | ||
end; | end; | ||
− | procedure TCamera.Offset(x, y, z: | + | procedure TCamera.Offset(x, y, z: GLdouble); |
// verschieben der Kamera auf einer beliebigen Achse | // verschieben der Kamera auf einer beliebigen Achse | ||
var | var | ||
Zeile 292: | Zeile 299: | ||
glPushMatrix(); | glPushMatrix(); | ||
glLoadIdentity; | glLoadIdentity; | ||
− | + | glTranslated(x,y,z); | |
− | + | glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); | |
glPopMatrix(); | glPopMatrix(); | ||
Zeile 309: | Zeile 316: | ||
i: integer; | i: integer; | ||
P, V, U: TGLvector; | P, V, U: TGLvector; | ||
− | Laenge: | + | Laenge: GLdouble; |
begin | begin | ||
Debug ('- PositionCamera - Start ------------------------------------------'); | Debug ('- PositionCamera - Start ------------------------------------------'); | ||
Zeile 333: | Zeile 340: | ||
// glulookat wird die matrix parallel zur Z-achse ausrichten | // 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); | gluLookAt (P.X, P.Y, P.Z, V.X, V.Y, V.Z, U.X, U.Y, U.Z); | ||
− | + | glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); | |
glPopMatrix; | glPopMatrix; | ||
Zeile 377: | Zeile 384: | ||
// jetzt um den Differenzbetrag des alten und neuen | // jetzt um den Differenzbetrag des alten und neuen | ||
// Rotationspunkts zurück verschieben | // Rotationspunkts zurück verschieben | ||
− | + | glTranslated (-PosDiff.X, 0, 0); | |
− | + | glTranslated (0, -PosDiff.Y, 0); | |
− | + | glTranslated (0, 0, -PosDiff.Z); | |
// jetzt vom neuen Rotationspunktes zurück ins Zentrum, damit beim | // jetzt vom neuen Rotationspunktes zurück ins Zentrum, damit beim | ||
// nächsten Apply das glTranslatef (-FPointOfRotation, ...) klappt | // nächsten Apply das glTranslatef (-FPointOfRotation, ...) klappt | ||
− | + | glTranslated (CrossVec.X, 0, 0); | |
− | + | glTranslated (0, CrossVec.Y, 0); | |
− | + | glTranslated (0, 0, CrossVec.Z); | |
// aktuelle Matrix holen... | // aktuelle Matrix holen... | ||
− | + | glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); | |
// und als Kameramatrix abspeichern | // und als Kameramatrix abspeichern | ||
Zeile 432: | Zeile 439: | ||
end; | end; | ||
− | procedure TCamera.TranslateCamera(ix, iy, iz: | + | procedure TCamera.TranslateCamera(ix, iy, iz: GLdouble); |
// vom Benutzer aufzurufende Methode um eine Verschiebung | // vom Benutzer aufzurufende Methode um eine Verschiebung | ||
// durchzufuehren | // durchzufuehren | ||
Zeile 439: | Zeile 446: | ||
end; | end; | ||
− | procedure TCamera.RotateCamera(ix, iy, iz: | + | procedure TCamera.RotateCamera(ix, iy, iz: GLdouble); |
// vom Benutzer aufzurufende Methode um eine Drehung | // vom Benutzer aufzurufende Methode um eine Drehung | ||
// durchzufuehren | // durchzufuehren | ||
Zeile 455: | Zeile 462: | ||
glMatrixMode (GL_MODELVIEW); | glMatrixMode (GL_MODELVIEW); | ||
− | + | glLoadMatrixd(@CameraMatrix.Matrix); | |
− | + | glTranslated (-FPointOfRotation.X, | |
-FPointOfRotation.y, | -FPointOfRotation.y, | ||
-FPointOfRotation.Z); | -FPointOfRotation.Z); | ||
Zeile 473: | Zeile 480: | ||
glMatrixMode (GL_MODELVIEW); | glMatrixMode (GL_MODELVIEW); | ||
// für das Terrain nur die Drehung ausführen | // für das Terrain nur die Drehung ausführen | ||
− | + | glLoadMatrixd(@CameraMatrix.Matrix); | |
// deswegen jetzt die verschiebung zurücknehmen | // deswegen jetzt die verschiebung zurücknehmen | ||
Pos := GetMatrixPos (CameraMatrix.InverseMatrix); | Pos := GetMatrixPos (CameraMatrix.InverseMatrix); | ||
− | + | glTranslated (Pos.X, Pos.Y, Pos.Z); | |
end; | end; | ||
Zeile 587: | Zeile 594: | ||
TimeToStr (time) + ' | ' + | TimeToStr (time) + ' | ' + | ||
Text); | Text); | ||
+ | end; | ||
+ | |||
+ | procedure TCamera.ApplyInvers; | ||
+ | var | ||
+ | M: TArrMatrix; | ||
+ | begin | ||
+ | // Um Objekte immer zum benutzer ausrichten, darf nur die drehung angewendet | ||
+ | // werden und nicht die verschiebung. Verschiebung wird hier zurückgenommen. | ||
+ | // Vorher muss die Kamera angewendet und die nötigen Verschiebungen/ | ||
+ | // Drehungen ausgeführt werden. | ||
+ | M := InverseMatrix; | ||
+ | M[12] := 0; | ||
+ | M[13] := 0; | ||
+ | M[14] := 0; | ||
+ | M[15] := 1; | ||
+ | glMultMatrixd(@M); | ||
end; | end; | ||
Initialization | Initialization | ||
FDebugOn := false; | FDebugOn := false; | ||
− | FDebugFileName := ExePath + ' | + | FDebugFileName := ExePath + 'SKANAL3D_CAMERA.DBG'; |
if FDebugOn then | if FDebugOn then | ||
begin | begin | ||
Zeile 600: | Zeile 623: | ||
finalization | finalization | ||
if FDebugOn then | if FDebugOn then | ||
+ | begin | ||
CloseFile (FDebugFile); | CloseFile (FDebugFile); | ||
+ | FDebugFileName := ''; | ||
+ | end; | ||
end. | end. | ||
</pascal> | </pascal> | ||
[[Kategorie:Anleitung]] | [[Kategorie:Anleitung]] |
Version vom 7. Oktober 2006, 06:17 Uhr
Eine Beschreibung findet ihr unter Kamera (1).
Die verwendete Toolsammlung findet ihr unter Kamera (3).
// Wie ich selber immer wieder merken muss, ist eine Software anscheinend // nie fertig. Immer moechte man etwas verbessern oder neue Features // einbauen. // Sollte also jemand Änderungs- oder Verbesserungsvorschläge haben oder // neue Ideen einbringen wollen, oder sollten Verstaendnisfragen bestehen, // 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. // // 23.11.2005 // Neues Flag (FFixedAxis) zur Entscheidung zwischen angepasster und realer // Drehung. Dadurch wird das Bewegungsmodell angepasst. Siehe Methode Offset, // bzw. UpdateMatrixOffset. // // 10.12.2005 // Property PointOfRotation ist jetzt nicht mehr ReadOnly. // Der Blickpunkt bzw. Rotationspunkt kann jetzt direkt verändert werden. // So kann eine neue Blickrichtung angenommen werden ohne vorher die Kamera- // eigenschaften zu sichern und nach einem PositionCamera wieder zu setzen. // // 19.12.2005 // Neue Methode PositionCross. // Die Methode PositionCross schiebt das Fadenkreuz in den angegebenen Punkt // ohne die Lage der Szene zu verändern. Diese Funktionalitaet ist anders als // ein neues Setzen der Property FPointOfRotation weil dabei die Szene in das // Koordinatenkreuz geschoben wird. // // 31.01.2006 // Umstellung auf genaueres Zahlenformat // Da die Darstellung von Szenen ausserhalb des Bereichs von FLOAT-Zahlen // nicht funktioniert, muss alles auf DOUBLE umgestellt werden. Dazu gehört // das Ersetzen von Datentypen und der Aufruf der entsprechenden GL-Funktionen. // unit Camera; interface Uses DglOpenGL, Util, Windows, Classes; type TCameraMatrix=Class StackMatrix: array [0..9] of TArrMatrix; StackCtr: integer; Matrix: TArrMatrix; InverseMatrix: TArrMatrix; constructor Create; //destructor destroy; procedure Identity; procedure Push; procedure Pop; procedure Load(M: TArrMatrix); end; TCamera=Class Enabled: boolean; function UpVector: TGLvector; procedure RestorePosition(pos: integer); procedure SavePosition(pos: integer); function GiveStoredPosition(pos: integer): TGLvector; procedure RotateCamera(ix, iy, iz: GLdouble); procedure TranslateCamera(ix, iy, iz: GLdouble); procedure CameraHome; procedure PositionCamera(PositionVec: TGLvector; ViewVec: TGLvector; upVec: TGLvector); procedure Adjust; procedure Apply; procedure ApplyForTerrain; private FPosition: TGLvector; FViewDirection: TGLvector; FPointOfRotation: TGLvector; HomeMatrix: TCameraMatrix; CameraMatrix: TCameraMatrix; Initiated: boolean; PosArray: array [0..9] of TCameraMatrix; RotArray: array [0..9] of TGLvector; FFixedAxis: boolean; procedure Debug (Text: string); function UpdateMatrixOffset(newMatrix: TArrMatrix): TArrMatrix; function GetViewDirection: TGLvector; procedure SetViewDirection (View: TGLvector); procedure Initiate; function GetPosition: TGLvector; procedure SetPosition (Pos: TGLvector); procedure Identity; procedure Offset(x, y, z: GLdouble); procedure RotateRoundAxis(rx, ry, rz: GLdouble); procedure SetPointOfRotation (NewPoint: TGLvector); public constructor Create; destructor Destroy;override; function InverseMatrix: TArrMatrix; procedure ApplyInvers; procedure PositionCross(CrossVec: TGLvector); published property PointOfRotation: TGLvector read FPointOfRotation write SetPointOfRotation; property Position: TGLvector read GetPosition write SetPosition; property ViewDirection: TGLvector read GetViewDirection write SetViewDirection; property FixedAxis: boolean read FFixedAxis write FFixedAxis; end; TPCamera=^TCamera; var FDebugFile: Textfile; FDebugFileName: string; FDebugOn: boolean; implementation uses SysUtils; constructor TCameraMatrix.Create; begin inherited create; StackCtr := 0; end; { destructor TCameraMatrix.Destroy; begin inherited destroy; end; } procedure TCameraMatrix.Push; begin if (StackCtr > -1) and (StackCtr < 10) then begin StackMatrix[StackCtr] := Matrix; inc (StackCtr); end; end; procedure TCameraMatrix.Pop; begin if (StackCtr > 0) and (StackCtr < 11) then begin dec (StackCtr); Load (StackMatrix[StackCtr]); end; end; procedure TCameraMatrix.Identity; // GetIdentity: 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; // standardmaessig immer entlang der bildschirmachsen verschieben FFixedAxis := true; 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: GLdouble); // hier drehen wir jetzt um die einzelnen Achsen. // die Parameter geben die "Drehgeschwindigkeit" vor. var newMatrix: TArrMatrix; tempX, tempY, tempZ: TGLvector; begin glMatrixMode (GL_MODELVIEW); glPushMatrix(); // aktuelle Position und Lage der Kamera herstellen glLoadMatrixd(@CameraMatrix.Matrix); if FFixedAxis then begin // über die bildschirmachsen drehen tempX := GetMatrixX (CameraMatrix.InverseMatrix); tempY := GetMatrixY (CameraMatrix.InverseMatrix); tempZ := GetMatrixZ (CameraMatrix.InverseMatrix); // wenn gewuenscht um die X-Achse drehen if(rx <> 0) then glRotated(rx,tempX.X,tempX.Y,tempX.Z); // wenn gewuenscht um die Y-Achse drehen if(ry <> 0) then glRotated(ry,tempY.X,tempY.Y,tempY.Z); // wenn gewuenscht um die Z-Achse drehen if(rz <> 0) then glRotated(rz,tempZ.X,tempZ.Y,tempZ.Z); end else begin // über die achsen des koordinatenkreuzes drehen // wenn gewuenscht um die X-Achse drehen if(rx <> 0) then glRotated(rx,1,0,0); // wenn gewuenscht um die Y-Achse drehen if(ry <> 0) then glRotated(ry,0,1,0); // wenn gewuenscht um die Z-Achse drehen if(rz <> 0) then glRotated(rz,0,0,1); end; // die neu erzeugte Matrix auslesen glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); glPopMatrix(); // und in die Kameramatrix sichern CameraMatrix.Load(newMatrix); end; procedure TCamera.Identity; begin CameraMatrix.Identity; HomeMatrix.Identity; Enabled := true; end; procedure TCamera.Offset(x, y, z: GLdouble); // verschieben der Kamera auf einer beliebigen Achse var newMatrix: TArrMatrix; //OldView: TGLvector; begin Debug ('- Offset - Start --------------------------------------------------'); glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity; glTranslated(x,y,z); glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); glPopMatrix(); Debug ('Position: '+GLvectorToText (GetMatrixPos (newMatrix))); newMatrix := UpdateMatrixOffset (newMatrix); CameraMatrix.Load(newMatrix); Debug ('- Offset - Ende- --------------------------------------------------'); end; procedure TCamera.PositionCamera(PositionVec: TGLvector; ViewVec: TGLvector; upVec: TGLvector); var newMatrix: TArrMatrix; i: integer; P, V, U: TGLvector; Laenge: GLdouble; begin Debug ('- PositionCamera - Start ------------------------------------------'); // 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; 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); glGetDoublev(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 zurueck zur kameraposition Offset (0, 0, -Laenge); // alle positionsspeicher mit der Kameraposition, Blickrichtung // und dem upVector belegen. Nur beim ersten Aufruf von // PositionCamera if not Initiated then Initiate; FPointOfRotation := ViewVec; Debug ('PointOfRotation: '+GLvectorToText (FPointOfRotation)); Debug ('- PositionCamera - Ende -------------------------------------------'); end; procedure TCamera.PositionCross (CrossVec: TGLvector); // diese prozedur verschiebt, im gegensatz zu einem verändern von // PointOfRotation, das Koordinatenkreuz und nicht die Szene. var newMatrix: TArrMatrix; PosDiff: TGLvector; begin Debug ('- PositionCross - Start -------------------------------------------'); PosDiff := SubtractVector (FPointOfRotation, CrossVec); // Szene in das koordinatenkreuz verschieben FPointOfRotation := CrossVec; // jetzt die Szene wieder um den gleichen betrag zurückverschieben // das sieht dann so aus, als ob das koordinatenkreuz verschoben // worden wäre // zuerst die aktuelle neue Situation herstellen // (mit neuem FPointOfRotation) Apply; // jetzt um den Differenzbetrag des alten und neuen // Rotationspunkts zurück verschieben glTranslated (-PosDiff.X, 0, 0); glTranslated (0, -PosDiff.Y, 0); glTranslated (0, 0, -PosDiff.Z); // jetzt vom neuen Rotationspunktes zurück ins Zentrum, damit beim // nächsten Apply das glTranslatef (-FPointOfRotation, ...) klappt glTranslated (CrossVec.X, 0, 0); glTranslated (0, CrossVec.Y, 0); glTranslated (0, 0, CrossVec.Z); // aktuelle Matrix holen... glGetDoublev(GL_MODELVIEW_MATRIX, @newMatrix); // und als Kameramatrix abspeichern CameraMatrix.Load(newmatrix); Debug ('- PositionCross - Ende --------------------------------------------'); end; procedure TCamera.CameraHome; // Kamera in die beim letzten Aufruf von PositionCamera uebergebene // 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); RotArray[pos] := FPointOfRotation; 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); FPointOfRotation := RotArray[pos]; end; function TCamera.GiveStoredPosition (pos: integer): TGLvector; // gibt den Inhalt des durch pos bestimmten // Positionsspecihers zurueck begin if (pos < 0) or (pos > 9) then exit; result := GetMatrixPos (PosArray[pos].Matrix); end; procedure TCamera.TranslateCamera(ix, iy, iz: GLdouble); // vom Benutzer aufzurufende Methode um eine Verschiebung // durchzufuehren begin Offset (ix, iy, iz); end; procedure TCamera.RotateCamera(ix, iy, iz: GLdouble); // vom Benutzer aufzurufende Methode um eine Drehung // durchzufuehren begin RotateRoundAxis (-iy, -ix, -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); glLoadMatrixd(@CameraMatrix.Matrix); glTranslated (-FPointOfRotation.X, -FPointOfRotation.y, -FPointOfRotation.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. var pos: TGLvector; begin if not Enabled then exit; glMatrixMode (GL_MODELVIEW); // für das Terrain nur die Drehung ausführen glLoadMatrixd(@CameraMatrix.Matrix); // deswegen jetzt die verschiebung zurücknehmen Pos := GetMatrixPos (CameraMatrix.InverseMatrix); glTranslated (Pos.X, Pos.Y, Pos.Z); end; function TCamera.GetPosition: TGLvector; // diese Property-Funktion fragt die aktuelle Position der Kamera ab begin // position: letzte Spalte der Matrix result := AddVector (GetMatrixPos (CameraMatrix.InverseMatrix), FPointOfRotation); end; procedure TCamera.SetPosition (Pos: TGLvector); // diese Property-Funktion setzt eine neue Position der Kamera var m: TArrMatrix; begin // position: letzte Spalte der Matrix m := CameraMatrix.Matrix; SetMatrixPos (m, SubtractVector (Pos, FPointOfRotation)); CameraMatrix.Load (m); end; function TCamera.GetViewDirection: TGLvector; // mit dieser Funktion kann die aktuelle Blickrichtung der Kamera // abgefragt werden var return: TGLvector; begin // view direction: dritte Spalte der Matrix (Z-Achse) result := GetMatrixZ (CameraMatrix.InverseMatrix); end; procedure TCamera.SetViewDirection (View: TGLvector); // mit dieser Funktion kann die aktuelle Blickrichtung der Kamera // gesetzt werden begin // view direction: dritte Spalte der Matrix (Z-Achse) SetMatrixZ (CameraMatrix.InverseMatrix, View); 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) result := GetMatrixY (CameraMatrix.InverseMatrix); end; procedure TCamera.Adjust; // mit dieser Prozedur kann die Kamera zu jeder Zeit, unabhaengig // von Drehung und Position, zur Y-Achse ausgerichtet werden. // Die aktuelle Position wird dabei beibehalten. var m: TArrMatrix; v: TGLvector; begin // position aus der aktuellen cameramatrix holen v := GetMatrixPos (CameraMatrix.Matrix); // m mit identitätsmatrix initialisieren m := GetIdentity(m); // die position aus der aktuellen cameramatrix in m speichern SetMatrixPos (m, v); // m als aktuelle cameramatrix speichern CameraMatrix.Load(m); end; function TCamera.InverseMatrix: TArrMatrix; begin result := CameraMatrix.InverseMatrix; end; procedure TCamera.Initiate; var i: integer; begin for i := 0 to 9 do SavePosition (i); Initiated := true; end; function TCamera.UpdateMatrixOffset (newMatrix: TArrMatrix): TArrMatrix; begin // wenn ich mit Multiply (FixedAxis) arbeite, wird die zeichnung immer // entlang der bildschirmachsen verschoben. wenn ich Multiply, version 2 // nehme, wird sie auf den errechneten achsen verschoben. if FFixedAxis then begin result := Multiply (newMatrix, CameraMatrix.Matrix); end else begin result := Multiply (CameraMatrix.Matrix, newMatrix); end; end; procedure TCamera.SetPointOfRotation (NewPoint: TGLvector); // setzt den viewpoint oder rotationpoint ohne die anderen parameter zu // veraendern. so kann man z.B. eine Kamerafahrt in immer der gleichen // position simulieren. begin FPointOfRotation := NewPoint; end; procedure TCamera.Debug (Text: string); begin if not FDebugOn then exit; writeln (FDebugFile, DateToStr (date) + ' | ' + TimeToStr (time) + ' | ' + Text); end; procedure TCamera.ApplyInvers; var M: TArrMatrix; begin // Um Objekte immer zum benutzer ausrichten, darf nur die drehung angewendet // werden und nicht die verschiebung. Verschiebung wird hier zurückgenommen. // Vorher muss die Kamera angewendet und die nötigen Verschiebungen/ // Drehungen ausgeführt werden. M := InverseMatrix; M[12] := 0; M[13] := 0; M[14] := 0; M[15] := 1; glMultMatrixd(@M); end; Initialization FDebugOn := false; FDebugFileName := ExePath + 'SKANAL3D_CAMERA.DBG'; if FDebugOn then begin AssignFile (FDebugFile, FDebugFileName); Rewrite (FDebugFile); end; finalization if FDebugOn then begin CloseFile (FDebugFile); FDebugFileName := ''; end; end.