Kamera (2)
unit Camera;
interface
Uses DglOpenGL, OpenGLUtil, Windows, Classes;
type
TCameraMatrix=Class Matrix: TArrMatrix; InverseMatrix: TArrMatrix; procedure Identity; procedure Load(M: TArrMatrix); constructor Create; end;
TCamera=Class CameraMatrix: TCameraMatrix; Enabled : boolean; Initiated: boolean; constructor Create; destructor Destroy; function Position: TGLvector; function UpVector: TGLvector; function ViewDirection: TGLvector; procedure RestorePosition(pos: integer); procedure SavePosition(pos: integer); 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; private HomeMatrix: TCameraMatrix; PosArray: array [0..9] of TCameraMatrix; FPointOfRotation: TGLvector; procedure Identity; procedure RotateMatrix(ix, iy, iz: TGLdouble); procedure Offset(x, y, z: TGLfloat); procedure RotateRoundAxis(rx, ry, rz: TGLfloat); published property PointOfRotation: TGLvector read FPointOfRotation; end; TPCamera=^TCamera;
implementation
constructor TCameraMatrix.Create;
// beim erzeugen der Matrix wird die Identitätsmatrix zugewiesen
begin
Identity;
end;
procedure TCameraMatrix.Identity;
// die Funktion GetArrIdentity findet Ihr in der Datei OpenGL.pas
var
i: integer;
begin
Matrix := GetArrIdentity; InverseMatrix := GetArrIdentity;
end;
procedure TCameraMatrix.Load(M: TArrMatrix);
// die Matrix mit den Werten einer beliebigen anderen matrix füllen
var
i: integer;
begin
for i:=0 to 15 do Matrix[i]:=M[i]; InvertMatrix (M, InverseMatrix);
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 gewünscht um die X-Achse drehen if(rx <> 0) then glRotatef(rx,1,0,0);
// wenn gewünscht um die Y-Achse drehen if(ry <> 0) then glRotatef(ry,0,1,0);
// wenn gewünscht 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;
constructor TCamera.Create;
var
i: integer;
begin
// 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;
procedure TCamera.Identity;
begin
CameraMatrix.Identity; HomeMatrix.Identity;
Enabled := true;
end;
destructor TCamera.Destroy;
var
i: integer;
begin
HomeMatrix.Free; CameraMatrix.Free; for i := 0 to 9 do PosArray[i].Free;
end;
procedure TCamera.Offset(x, y, z: TGLfloat);
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 MatrixMultiply (newMatrix, CameraMatrix.Matrix, newMatrix); CameraMatrix.Load(newMatrix); glPopMatrix();
end;
procedure TCamera.PositionCamera(PositionVec: TGLvector;
ViewVec: TGLvector;
upVec: TGLvector);
var
newMatrix: TArrMatrix; i: integer;
begin
Identity; FPointOfRotation := ViewVec;
glMatrixMode (GL_MODELVIEW); glPushMatrix; glLoadIdentity; glTranslatef (PositionVec.X, PositionVec.Y, PositionVec.Z); gluLookAt (PositionVec.X, PositionVec.Y, PositionVec.Z, ViewVec.X, ViewVec.Y, ViewVec.Z, upVec.X, upVec.Y, upVec.Z); glGetFloatv(GL_MODELVIEW_MATRIX, @newMatrix); CameraMatrix.Load(newMatrix); HomeMatrix.Load(newMatrix); glPopMatrix;
if not Initiated then begin for i := 0 to 9 do SavePosition (i); Initiated := true; end;
end;
procedure TCamera.CameraHome;
// Move the camera to the home position
begin
CameraMatrix.Load(HomeMatrix.Matrix);
end;
procedure TCamera.SavePosition (pos: integer);
begin
if (pos < 0) or (pos > 9) then exit;
PosArray[pos].Load(CameraMatrix.Matrix);
end;
procedure TCamera.RestorePosition (pos: integer);
begin
if (pos < 0) or (pos > 9) then exit;
CameraMatrix.Load(PosArray[pos].Matrix);
end;
procedure TCamera.TranslateCamera(ix, iy, iz: TGLdouble);
begin
Offset (ix, iy, iz);
end;
procedure TCamera.RotateCamera(ix, iy, iz: TGLdouble);
begin
RotateMatrix (ix, iy, iz);
end;
procedure TCamera.Apply;
begin
if not Enabled then exit;
glMatrixMode (GL_MODELVIEW); glLoadMatrixf(@CameraMatrix.Matrix); glTranslatef (-PointOfRotation.X, -PointOfRotation.y, -PointOfRotation.Z);
end;
procedure TCamera.RotateMatrix (ix, iy, iz: TGLdouble);
begin
RotateRoundAxis (iy, ix, iz);
end;
function TCamera.Position: TGLvector;
var
return: TGLvector;
begin
// position: letzte Spalte der Matrix InitVector (return, CameraMatrix.Matrix[12], CameraMatrix.Matrix[13], CameraMatrix.Matrix[14]); result := return;
end;
function TCamera.ViewDirection: TGLvector;
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;
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;
var
temp: TArrMatrix;
begin
// kamera senkrecht zur Y-Achse ausrichten // position beibehalten temp := GetArrIdentity; 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.