Kamera (2): Unterschied zwischen den Versionen

Aus DGL Wiki
Wechseln zu: Navigation, Suche
Zeile 6: Zeile 6:
 
// nie fertig. Immer moechte man etwas verbessern oder neue Features
 
// nie fertig. Immer moechte man etwas verbessern oder neue Features
 
// einbauen.
 
// einbauen.
// Sollte also jemand Aenderungs- oder Verbesserungsvorschlaege haben oder
+
// Sollte also jemand Änderungs- oder Verbesserungsvorschläge haben oder
 
// neue Ideen einbringen wollen, oder sollten Verstaendnisfragen bestehen,
 
// neue Ideen einbringen wollen, oder sollten Verstaendnisfragen bestehen,
 
// so mailt bitte an
 
// so mailt bitte an
Zeile 35: Zeile 35:
 
// Jetzt wird die Position so gesetzt, dass die gewuenschte Kameraposition
 
// Jetzt wird die Position so gesetzt, dass die gewuenschte Kameraposition
 
// immer vor dem Betrachter steht.
 
// 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.
 
//
 
//
 
unit Camera;
 
unit Camera;
Zeile 44: Zeile 62:
 
   type
 
   type
 
   TCameraMatrix=Class
 
   TCameraMatrix=Class
 +
    StackMatrix: array [0..9] of TArrMatrix;
 +
    StackCtr: integer;
 
     Matrix: TArrMatrix;
 
     Matrix: TArrMatrix;
 
     InverseMatrix: TArrMatrix;
 
     InverseMatrix: TArrMatrix;
     //constructor Create;
+
     constructor Create;
 
     //destructor destroy;
 
     //destructor destroy;
 
     procedure Identity;
 
     procedure Identity;
 +
    procedure Push;
 +
    procedure Pop;
 
     procedure Load(M: TArrMatrix);
 
     procedure Load(M: TArrMatrix);
 
   end;
 
   end;
  
 
   TCamera=Class
 
   TCamera=Class
    CameraMatrix: TCameraMatrix;
+
     Enabled: boolean;
    HomeMatrix: TCameraMatrix;
 
     Enabled : boolean;
 
    Initiated: boolean;
 
    FPosition: TGLvector;
 
    FPointOfRotation: TGLvector;
 
    FPositionOffset: TGLvector;
 
 
     function UpVector: TGLvector;
 
     function UpVector: 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;
+
     function GiveStoredPosition(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);
                    ViewVec: TGLvector;
 
    upVec: TGLvector);
 
 
     procedure Adjust;
 
     procedure Adjust;
 
     procedure Apply;
 
     procedure Apply;
 
     procedure ApplyForTerrain;
 
     procedure ApplyForTerrain;
 
   private
 
   private
 +
    FPosition: TGLvector;
 +
    FViewDirection: TGLvector;
 +
    FPointOfRotation: TGLvector;
 +
    HomeMatrix: TCameraMatrix;
 +
    CameraMatrix: TCameraMatrix;
 +
    Initiated: boolean;
 
     PosArray: array [0..9] of TCameraMatrix;
 
     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;
 
     function GetPosition: TGLvector;
 
     procedure SetPosition (Pos: TGLvector);
 
     procedure SetPosition (Pos: TGLvector);
 
     procedure Identity;
 
     procedure Identity;
    procedure RotateMatrix(ix, iy, iz: TGLdouble);
 
 
     procedure Offset(x, y, z: TGLfloat);
 
     procedure Offset(x, y, z: TGLfloat);
 
     procedure RotateRoundAxis(rx, ry, rz: TGLfloat);
 
     procedure RotateRoundAxis(rx, ry, rz: TGLfloat);
 +
    procedure SetPointOfRotation (NewPoint: TGLvector);
 
   public
 
   public
 
     constructor Create;
 
     constructor Create;
 
     destructor Destroy;override;
 
     destructor Destroy;override;
 +
    function InverseMatrix: TArrMatrix;
 +
    procedure PositionCross(CrossVec: TGLvector);
 
   published
 
   published
     property PointOfRotation: TGLvector read FPointOfRotation;
+
     property PointOfRotation: TGLvector read FPointOfRotation write SetPointOfRotation;
 
     property Position: TGLvector read GetPosition write SetPosition;
 
     property Position: TGLvector read GetPosition write SetPosition;
 +
    property ViewDirection: TGLvector read GetViewDirection write SetViewDirection;
 +
    property FixedAxis: boolean read FFixedAxis write FFixedAxis;
 
   end;
 
   end;
 
   TPCamera=^TCamera;
 
   TPCamera=^TCamera;
 +
 +
var
 +
  FDebugFile: Textfile;
 +
  FDebugFileName: string;
 +
  FDebugOn: boolean;
  
 
implementation
 
implementation
  
uses SysUtils;
+
uses SysUtils, KanalUtil;
  
{
 
 
constructor TCameraMatrix.Create;
 
constructor TCameraMatrix.Create;
 
begin
 
begin
 
   inherited create;
 
   inherited create;
 +
  StackCtr := 0;
 
end;
 
end;
 
+
{
 
destructor TCameraMatrix.Destroy;
 
destructor TCameraMatrix.Destroy;
 
begin
 
begin
Zeile 106: Zeile 141:
 
end;
 
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;
 
procedure TCameraMatrix.Identity;
// GetArrIdentity: aus OpenGL.pas
+
// GetIdentity: aus OpenGL.pas
 
// initialisiert die CameraMatrix mit der Identitaetsmatrix
 
// initialisiert die CameraMatrix mit der Identitaetsmatrix
 
begin
 
begin
Zeile 133: Zeile 186:
 
   inherited create;
 
   inherited create;
  
   // Initiated wird gebraucht um einmal alle Positionsspeicher  
+
   // Initiated wird gebraucht um einmal alle Positionsspeicher
 
   // mit der Anfangsposition zu belegen
 
   // mit der Anfangsposition zu belegen
 
   Initiated := false;
 
   Initiated := false;
 
+
 
 
   // Kameramatrix anlegen
 
   // Kameramatrix anlegen
 
   CameraMatrix := TCameraMatrix.Create;
 
   CameraMatrix := TCameraMatrix.Create;
 
+
 
 
   // Matrix der letzten Position von PositionCamera anlegen
 
   // Matrix der letzten Position von PositionCamera anlegen
 
   HomeMatrix := TCameraMatrix.Create;
 
   HomeMatrix := TCameraMatrix.Create;
Zeile 146: Zeile 199:
 
   for i := 0 to 9 do
 
   for i := 0 to 9 do
 
     PosArray[i] := TCameraMatrix.Create;
 
     PosArray[i] := TCameraMatrix.Create;
 +
 +
  // standardmaessig immer entlang der bildschirmachsen verschieben
 +
  FFixedAxis := true;
 
end;
 
end;
  
Zeile 166: Zeile 222:
 
var
 
var
 
   newMatrix: TArrMatrix;
 
   newMatrix: TArrMatrix;
 +
  tempX, tempY, tempZ: TGLvector;
 
begin
 
begin
 
   glMatrixMode (GL_MODELVIEW);
 
   glMatrixMode (GL_MODELVIEW);
 
   glPushMatrix();
 
   glPushMatrix();
 +
 
   // aktuelle Position und Lage der Kamera herstellen
 
   // aktuelle Position und Lage der Kamera herstellen
 
   glLoadMatrixf(@CameraMatrix.Matrix);
 
   glLoadMatrixf(@CameraMatrix.Matrix);
  
   // wenn gewuenscht um die X-Achse drehen
+
   if FFixedAxis then
   if(rx <> 0) then
+
  begin
    glRotatef(rx,1,0,0);
+
    // ü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
 +
      glRotatef(rx,tempX.X,tempX.Y,tempX.Z);
 +
 
 +
    // wenn gewuenscht um die Y-Achse drehen
 +
    if(ry <> 0) then
 +
      glRotatef(ry,tempY.X,tempY.Y,tempY.Z);
 +
 
 +
    // wenn gewuenscht um die Z-Achse drehen
 +
    if(rz <> 0) then
 +
      glRotatef(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
 +
      glRotatef(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
    glRotatef(ry,0,1,0);
+
      glRotatef(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
    glRotatef(rz,0,0,1);
+
      glRotatef(rz,0,0,1);
 +
  end;
  
 
   // die neu erzeugte Matrix auslesen
 
   // die neu erzeugte Matrix auslesen
 
   glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix);
 
   glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix);
 +
 +
  glPopMatrix();
 +
 
   // und in die Kameramatrix sichern
 
   // und in die Kameramatrix sichern
 
   CameraMatrix.Load(newMatrix);
 
   CameraMatrix.Load(newMatrix);
  glPopMatrix();
 
 
end;
 
end;
  
Zeile 203: Zeile 285:
 
var
 
var
 
   newMatrix: TArrMatrix;
 
   newMatrix: TArrMatrix;
 +
  //OldView: TGLvector;
 
begin
 
begin
 +
  Debug ('- Offset - Start --------------------------------------------------');
 
   glMatrixMode (GL_MODELVIEW);
 
   glMatrixMode (GL_MODELVIEW);
 +
 
   glPushMatrix();
 
   glPushMatrix();
 
   glLoadIdentity;
 
   glLoadIdentity;
 
   glTranslatef(x,y,z);
 
   glTranslatef(x,y,z);
 
   glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix);
 
   glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix);
   // wenn ich mit der funktion glMultMatrixf arbeite, wird die zeichnung
+
   glPopMatrix();
  // immer entlang der richtigen achsen verschoben. wenn ich matrixmultiply
+
 
   // nehme, wird sie auf den bildschirmachsen verschoben. das ist angenehmer
+
   Debug ('Position: '+GLvectorToText (GetMatrixPos (newMatrix)));
  // zum arbeiten
+
   newMatrix := UpdateMatrixOffset (newMatrix);
   newMatrix := Multiply (newMatrix, CameraMatrix.Matrix);
 
 
   CameraMatrix.Load(newMatrix);
 
   CameraMatrix.Load(newMatrix);
   glPopMatrix();
+
   Debug ('- Offset - Ende- --------------------------------------------------');
 
end;
 
end;
 
  
 
procedure TCamera.PositionCamera(PositionVec: TGLvector;
 
procedure TCamera.PositionCamera(PositionVec: TGLvector;
Zeile 228: Zeile 311:
 
   Laenge: TGLdouble;
 
   Laenge: TGLdouble;
 
begin
 
begin
 +
  Debug ('- PositionCamera - Start ------------------------------------------');
 
   // die gewuenschte konstruktion immer auf die Z-ebene projizieren.
 
   // die gewuenschte konstruktion immer auf die Z-ebene projizieren.
 
   // zuerst die position in den nullpunkt holen
 
   // zuerst die position in den nullpunkt holen
Zeile 236: Zeile 320:
 
   // U ist halt schneller geschrieben als upVec...
 
   // U ist halt schneller geschrieben als upVec...
 
   U := upVec;
 
   U := upVec;
   // den betrag ermitteln, um den die kamera nachher auf der Z-Achse  
+
 
 +
   // den betrag ermitteln, um den die kamera nachher auf der Z-Achse
 
   // verschoben werden muss
 
   // verschoben werden muss
 
   Laenge := Magnitude (SubtractVector (P, V));
 
   Laenge := Magnitude (SubtractVector (P, V));
  
 
   Identity;
 
   Identity;
  FPointOfRotation := ViewVec;
 
  
 
   glMatrixMode (GL_MODELVIEW);
 
   glMatrixMode (GL_MODELVIEW);
Zeile 256: Zeile 340:
  
 
   // da wir uns jetzt am zielpunkt befinden, müssen wir auf der Z-achse
 
   // da wir uns jetzt am zielpunkt befinden, müssen wir auf der Z-achse
   // wieder zurück zur kameraposition
+
   // wieder zurueck zur kameraposition
 
   Offset (0, 0, -Laenge);
 
   Offset (0, 0, -Laenge);
  
  // damit GetPosition den Wert zurückgibt den wir mit PositionCamera
+
   // alle positionsspeicher mit der Kameraposition, Blickrichtung
  // 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
 
   // und dem upVector belegen. Nur beim ersten Aufruf von
 
   // PositionCamera
 
   // PositionCamera
 
   if not Initiated then
 
   if not Initiated then
   begin
+
    Initiate;
    for i := 0 to 9 do
+
 
      SavePosition (i);
+
  FPointOfRotation := ViewVec;
    Initiated := true;
+
   Debug ('PointOfRotation: '+GLvectorToText (FPointOfRotation));
   end;
+
  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
 +
  glTranslatef (-PosDiff.X, 0, 0);
 +
  glTranslatef (0, -PosDiff.Y, 0);
 +
  glTranslatef (0, 0, -PosDiff.Z);
 +
 
 +
  // jetzt vom neuen Rotationspunktes zurück ins Zentrum, damit beim
 +
  // nächsten Apply das glTranslatef (-FPointOfRotation, ...) klappt
 +
  glTranslatef (CrossVec.X, 0, 0);
 +
  glTranslatef (0, CrossVec.Y, 0);
 +
  glTranslatef (0, 0, CrossVec.Z);
 +
 
 +
  // aktuelle Matrix holen...
 +
  glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix);
 +
 
 +
  // und als Kameramatrix abspeichern
 +
  CameraMatrix.Load(newmatrix);
 +
   Debug ('- PositionCross - Ende --------------------------------------------');
 
end;
 
end;
  
 
procedure TCamera.CameraHome;
 
procedure TCamera.CameraHome;
// Kamera in die beim letzten Aufruf von PositionCamera übergebene
+
// Kamera in die beim letzten Aufruf von PositionCamera uebergebene
 
// Position/Lage bringen
 
// Position/Lage bringen
 
begin
 
begin
Zeile 291: Zeile 409:
  
 
   PosArray[pos].Load(CameraMatrix.Matrix);
 
   PosArray[pos].Load(CameraMatrix.Matrix);
 +
  RotArray[pos] := FPointOfRotation;
 
end;
 
end;
  
Zeile 300: Zeile 419:
  
 
   CameraMatrix.Load(PosArray[pos].Matrix);
 
   CameraMatrix.Load(PosArray[pos].Matrix);
 +
  FPointOfRotation := RotArray[pos];
 
end;
 
end;
  
function TCamera.GivePosition (pos: integer): TGLvector;
+
function TCamera.GiveStoredPosition (pos: integer): TGLvector;
// gibt den Inhalt des durch pos bestimmten  
+
// gibt den Inhalt des durch pos bestimmten
 
// Positionsspecihers zurueck
 
// Positionsspecihers zurueck
 
begin
 
begin
Zeile 309: Zeile 429:
 
     exit;
 
     exit;
  
   result.X := PosArray[pos].Matrix[12];
+
   result := GetMatrixPos (PosArray[pos].Matrix);
  result.Y := PosArray[pos].Matrix[13];
 
  result.Z := PosArray[pos].Matrix[14];
 
 
end;
 
end;
  
Zeile 325: Zeile 443:
 
// durchzufuehren
 
// durchzufuehren
 
begin
 
begin
   RotateMatrix (ix, iy, iz);
+
   RotateRoundAxis (-iy, -ix, -iz);
 
end;
 
end;
  
 
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 benoetigten Drehungen, Verschiebungen  
+
// sollte die Szene mit allen benoetigten Drehungen, Verschiebungen
 
// gezeichnet werden.
 
// gezeichnet werden.
 
begin
 
begin
Zeile 338: Zeile 456:
 
   glMatrixMode (GL_MODELVIEW);
 
   glMatrixMode (GL_MODELVIEW);
 
   glLoadMatrixf(@CameraMatrix.Matrix);
 
   glLoadMatrixf(@CameraMatrix.Matrix);
   glTranslatef (-PointOfRotation.X,
+
   glTranslatef (-FPointOfRotation.X,
                 -PointOfRotation.y,
+
                 -FPointOfRotation.y,
                 -PointOfRotation.Z);
+
                 -FPointOfRotation.Z);
 
end;
 
end;
  
 
procedure TCamera.ApplyForTerrain;
 
procedure TCamera.ApplyForTerrain;
// hier wird wie in Apply die Kamera eingeschaltet. da man um ein terrain  
+
// hier wird wie in Apply die Kamera eingeschaltet. da man um ein terrain
 
// (skycube, ...) anzuzeigen aber immer die gleiche entfernung zur welt
 
// (skycube, ...) anzuzeigen aber immer die gleiche entfernung zur welt
 
// einhalten muss, wird hier nur gedreht und nicht verschoben.
 
// einhalten muss, wird hier nur gedreht und nicht verschoben.
 +
var
 +
  pos: TGLvector;
 
begin
 
begin
 
   if not Enabled then
 
   if not Enabled then
Zeile 355: Zeile 475:
 
   glLoadMatrixf(@CameraMatrix.Matrix);
 
   glLoadMatrixf(@CameraMatrix.Matrix);
 
   // deswegen jetzt die verschiebung zurücknehmen
 
   // deswegen jetzt die verschiebung zurücknehmen
   glTranslatef (CameraMatrix.InverseMatrix[12],
+
   Pos := GetMatrixPos (CameraMatrix.InverseMatrix);
                CameraMatrix.InverseMatrix[13],
+
  glTranslatef (Pos.X, Pos.Y, Pos.Z);
                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;
 
end;
  
 
function TCamera.GetPosition: TGLvector;
 
function TCamera.GetPosition: TGLvector;
 
// diese Property-Funktion fragt die aktuelle Position der Kamera ab
 
// diese Property-Funktion fragt die aktuelle Position der Kamera ab
var
 
  return: TGLvector;
 
 
begin
 
begin
 
   // position: letzte Spalte der Matrix
 
   // position: letzte Spalte der Matrix
   InitVector (return,
+
   result := AddVector (GetMatrixPos (CameraMatrix.InverseMatrix), FPointOfRotation);
              CameraMatrix.Matrix[12],
 
              CameraMatrix.Matrix[13],
 
              CameraMatrix.Matrix[14]);
 
  return := AddVector (return, FPositionOffset);
 
  result := return;
 
 
end;
 
end;
  
 
procedure TCamera.SetPosition (Pos: TGLvector);
 
procedure TCamera.SetPosition (Pos: TGLvector);
 
// diese Property-Funktion setzt eine neue Position der Kamera
 
// diese Property-Funktion setzt eine neue Position der Kamera
 +
var
 +
  m: TArrMatrix;
 
begin
 
begin
 
   // position: letzte Spalte der Matrix
 
   // position: letzte Spalte der Matrix
   CameraMatrix.Matrix[12] := Pos.X;
+
   m := CameraMatrix.Matrix;
   CameraMatrix.Matrix[13] := Pos.Y;
+
   SetMatrixPos (m, SubtractVector (Pos, FPointOfRotation));
   CameraMatrix.Matrix[14] := Pos.Z;
+
   CameraMatrix.Load (m);
 
end;
 
end;
  
function TCamera.ViewDirection: TGLvector;
+
function TCamera.GetViewDirection: TGLvector;
 
// mit dieser Funktion kann die aktuelle Blickrichtung der Kamera
 
// mit dieser Funktion kann die aktuelle Blickrichtung der Kamera
 
// abgefragt werden
 
// abgefragt werden
Zeile 397: Zeile 504:
 
begin
 
begin
 
   // view direction: dritte Spalte der Matrix (Z-Achse)
 
   // view direction: dritte Spalte der Matrix (Z-Achse)
   InitVector (return,
+
   result := GetMatrixZ (CameraMatrix.InverseMatrix);
              CameraMatrix.Matrix[08],
+
end;
              CameraMatrix.Matrix[09],
+
 
              CameraMatrix.Matrix[10]);
+
procedure TCamera.SetViewDirection (View: TGLvector);
   result := return;
+
// 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;
 
end;
  
 
function TCamera.UpVector: TGLvector;
 
function TCamera.UpVector: TGLvector;
// mit dieser Funktion kann die aktuelle Ausrichtung der Kamera  
+
// mit dieser Funktion kann die aktuelle Ausrichtung der Kamera
 
// abgefragt werden
 
// abgefragt werden
 
var
 
var
Zeile 411: Zeile 522:
 
begin
 
begin
 
   // upVector: zweite Spalte der Matrix (Y-Achse)
 
   // upVector: zweite Spalte der Matrix (Y-Achse)
   InitVector (return,
+
   result := GetMatrixY (CameraMatrix.InverseMatrix);
              CameraMatrix.Matrix[04],
 
              CameraMatrix.Matrix[05],
 
              CameraMatrix.Matrix[06]);
 
  result := return;
 
 
end;
 
end;
  
 
procedure TCamera.Adjust;
 
procedure TCamera.Adjust;
// mit dieser Prozedur kann die Kamera zu jeder Zeit, unabhaengig  
+
// mit dieser Prozedur kann die Kamera zu jeder Zeit, unabhaengig
// von Drehung und Position, senkrecht zur Y-Achse ausgerichtet
+
// von Drehung und Position, zur Y-Achse ausgerichtet werden.
// werden. Die aktuelle Position wird dabei beibehalten.
+
// Die aktuelle Position wird dabei beibehalten.
 
var
 
var
   temp: TArrMatrix;
+
   m: TArrMatrix;
 +
  v: TGLvector;
 
begin
 
begin
   temp := GetIdentity(temp);
+
   // position aus der aktuellen cameramatrix holen
   temp[12] := CameraMatrix.Matrix[12];
+
   v := GetMatrixPos (CameraMatrix.Matrix);
   temp[13] := CameraMatrix.Matrix[13];
+
   // m mit identitätsmatrix initialisieren
   temp[14] := CameraMatrix.Matrix[14];
+
  m := GetIdentity(m);
   temp[15] := CameraMatrix.Matrix[15];
+
   // die position aus der aktuellen cameramatrix in m speichern
   CameraMatrix.Load(temp);
+
  SetMatrixPos (m, v);
 +
   // m als aktuelle cameramatrix speichern
 +
   CameraMatrix.Load(m);
 
end;
 
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;
 +
 +
Initialization
 +
  FDebugOn := false;
 +
  FDebugFileName := ExePath + 'APPLICATION.DBG';
 +
  if FDebugOn then
 +
  begin
 +
    AssignFile (FDebugFile, FDebugFileName);
 +
    Rewrite (FDebugFile);
 +
  end;
 +
 +
finalization
 +
  if FDebugOn then
 +
    CloseFile (FDebugFile);
  
 
end.
 
end.
 
</pascal>
 
</pascal>
 
[[Kategorie:Anleitung]]
 
[[Kategorie:Anleitung]]

Version vom 8. Januar 2006, 09:01 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.
//
unit Camera;

interface

  Uses DglOpenGL, OpenGLUtil, 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: TGLdouble);
    procedure TranslateCamera(ix, iy, iz: TGLdouble);
    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: TGLfloat);
    procedure RotateRoundAxis(rx, ry, rz: TGLfloat);
    procedure SetPointOfRotation (NewPoint: TGLvector);
  public
    constructor Create;
    destructor Destroy;override;
    function InverseMatrix: TArrMatrix;
    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, KanalUtil;

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: TGLfloat);
// 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
  glLoadMatrixf(@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
      glRotatef(rx,tempX.X,tempX.Y,tempX.Z);

    // wenn gewuenscht um die Y-Achse drehen
    if(ry <> 0) then
      glRotatef(ry,tempY.X,tempY.Y,tempY.Z);

    // wenn gewuenscht um die Z-Achse drehen
    if(rz <> 0) then
      glRotatef(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
      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);
  end;

  // die neu erzeugte Matrix auslesen
  glGetFloatv(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: TGLfloat);
// verschieben der Kamera auf einer beliebigen Achse
var
  newMatrix: TArrMatrix;
  //OldView: TGLvector;
begin
  Debug ('- Offset - Start --------------------------------------------------');
  glMatrixMode (GL_MODELVIEW);

  glPushMatrix();
  glLoadIdentity;
  glTranslatef(x,y,z);
  glGetFloatv(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: TGLdouble;
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);
  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 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
  glTranslatef (-PosDiff.X, 0, 0);
  glTranslatef (0, -PosDiff.Y, 0);
  glTranslatef (0, 0, -PosDiff.Z);

  // jetzt vom neuen Rotationspunktes zurück ins Zentrum, damit beim
  // nächsten Apply das glTranslatef (-FPointOfRotation, ...) klappt
  glTranslatef (CrossVec.X, 0, 0);
  glTranslatef (0, CrossVec.Y, 0);
  glTranslatef (0, 0, CrossVec.Z);

  // aktuelle Matrix holen...
  glGetFloatv(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: 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
  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);
  glLoadMatrixf(@CameraMatrix.Matrix);
  glTranslatef (-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
  glLoadMatrixf(@CameraMatrix.Matrix);
  // deswegen jetzt die verschiebung zurücknehmen
  Pos := GetMatrixPos (CameraMatrix.InverseMatrix);
  glTranslatef (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;

Initialization
  FDebugOn := false;
  FDebugFileName := ExePath + 'APPLICATION.DBG';
  if FDebugOn then
  begin
    AssignFile (FDebugFile, FDebugFileName);
    Rewrite (FDebugFile);
  end;

finalization
  if FDebugOn then
    CloseFile (FDebugFile);

end.