unit uglcCamera; { Package: OpenGLCore Prefix: glc - OpenGL Core Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Frustum und Kamera Beispiel: var camera: TglcCamera; camera := TglcCamera.Create; try camera.Perspective(45, 0.01, 100, 800/600); // define perspective view camera.Move(gluVector(2, 3, -5)); // move 2 right, 3 up and 5 back camera.Tilt(-25); // turn 25 degrees down camera.Turn(-10); // turn 10 degrees left camera.Activate; // activate camera // do normal rendering finally FreeAndNil(camera); end; } {$mode objfpc}{$H+} interface uses Classes, SysUtils, ugluVector, ugluMatrix; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TglcFrustum = class(TObject) private fProjMatrix: TgluMatrix4f; function GetProjMatrixPtr: Pointer; function GetWidth: Single; function GetHeight: Single; function GetFOVAngle: Single; function GetAspectRatio: Single; procedure UpdateProjMatrix; protected fIsOrthogonal: Boolean; fTop, fBottom, fLeft, fRight, fNear, fFar: Single; public property Top: Single read fTop; property Bottom: Single read fBottom; property Left: Single read fLeft; property Right: Single read fRight; property Near: Single read fNear; property Far: Single read fFar; property Width: Single read GetWidth; property Height: Single read GetHeight; property FOVAngle: Single read GetFOVAngle; property AspectRatio: Single read GetAspectRatio; property IsOrthogonal: Boolean read fIsOrthogonal; property ProjMatrix: TgluMatrix4f read fProjMatrix; property ProjMatrixPtr: Pointer read GetProjMatrixPtr; procedure Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single); procedure Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single); procedure Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single); procedure Activate; {$IFNDEF OPENGL_ES} procedure Render; {$ENDIF} constructor Create; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TglcCamera = class(TglcFrustum) private fPosition: TgluMatrix4f; function GetPositionPtr: Pointer; public property Position: TgluMatrix4f read fPosition write fPosition; property PositionPtr: Pointer read GetPositionPtr; procedure Move(const aVec: TgluVector3f); procedure Tilt(const aAngle: Single); procedure Turn(const aAngle: Single); procedure Roll(const aAngle: Single); procedure Activate; function GetRay(const aPos: TgluVector2f): TgluRayf; constructor Create; end; implementation uses Math, {$IFNDEF OPENGL_ES}dglOpenGL{$ELSE}dglOpenGLES{$ENDIF}; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TglcFrustum/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcFrustum.UpdateProjMatrix; begin if fIsOrthogonal then begin fProjMatrix[maAxisX] := gluVector4f( 2 / (fRight - fLeft), 0, 0, 0); fProjMatrix[maAxisY] := gluVector4f( 0, 2 / (fTop - fBottom), 0, 0); fProjMatrix[maAxisZ] := gluVector4f( 0, 0, -2 / (fFar - fNear), 0); fProjMatrix[maPos] := gluVector4f( -(fRight + fLeft) / (fRight - fLeft), -(fTop + fBottom) / (fTop - fBottom), -(fFar + fNear) / (fFar - fNear), 1); end else begin fProjMatrix[maAxisX] := gluVector4f( 2 * fNear / (fRight - fLeft), 0, 0, 0); fProjMatrix[maAxisY] := gluVector4f( 0, 2 * fNear / (fTop - fBottom), 0, 0); fProjMatrix[maAxisZ] := gluVector4f( (fRight + fLeft) / (fRight - fLeft), (fTop + fBottom) / (fTop - fBottom), -(fFar + fNear) / (fFar - fNear), -1); fProjMatrix[maPos] := gluVector4f( 0, 0, -2 * fFar * fNear / (fFar - fNear), 0); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcFrustum.GetWidth: Single; begin result := (fRight - fLeft); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcFrustum.GetProjMatrixPtr: Pointer; begin result := @fProjMatrix[0, 0]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcFrustum.GetHeight: Single; begin result := (fTop - fBottom); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcFrustum.GetFOVAngle: Single; begin result := arctan2(Height/2, fNear)/Pi*360; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcFrustum.GetAspectRatio: Single; begin result := Height / Width; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcFrustum.Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single); begin fIsOrthogonal := false; fTop := aRight; fBottom := aLeft; fLeft := aBottom; fRight := aTop; fNear := aNear; fFar := aFar; UpdateProjMatrix; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcFrustum.Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single); begin fIsOrthogonal := false; fNear := aNear; fFar := aFar; fTop := fNear * tan(aFOVAngle / 360 * Pi); fBottom := -fTop; fRight := aAspectRatio * fTop; fLeft := -fRight; UpdateProjMatrix; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcFrustum.Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single); begin fIsOrthogonal := true; fLeft := aLeft; fRight := aRight; fTop := aTop; fBottom := aBottom; fNear := aNear; fFar := aFar; UpdateProjMatrix; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcFrustum.Activate; begin glMatrixMode(GL_PROJECTION); glLoadIdentity; if fIsOrthogonal then {$IFNDEF OPENGL_ES}glOrtho{$ELSE}glOrthof{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar) else {$IFNDEF OPENGL_ES}glFrustum{$ELSE}glFrustumf{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar); glMatrixMode(GL_MODELVIEW); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// {$IFNDEF OPENGL_ES} procedure TglcFrustum.Render; var min, max: TgluVector2f; begin min[0] := fLeft / fNear * fFar; min[1] := fBottom / fNear * fFar; max[0] := fRight / fNear * fFar; max[1] := fTop / fNear * fFar; glBegin(GL_LINE_LOOP); glVertex3f(fLeft, fTop, -fNear); glVertex3f(fLeft, fBottom, -fNear); glVertex3f(fRight, fBottom, -fNear); glVertex3f(fRight, fTop, -fNear); glEnd; glBegin(GL_LINE_LOOP); glVertex3f(min[0], min[0], -fFar); glVertex3f(min[0], max[0], -fFar); glVertex3f(max[0], max[0], -fFar); glVertex3f(max[0], min[0], -fFar); glEnd; glBegin(GL_LINES); glVertex3f(0, 0, 0); glVertex3f(min[0], min[0], -fFar); glVertex3f(0, 0, 0); glVertex3f(min[0], max[0], -fFar); glVertex3f(0, 0, 0); glVertex3f(max[0], max[0], -fFar); glVertex3f(0, 0, 0); glVertex3f(max[0], min[0], -fFar); glEnd; end; {$ENDIF} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TglcFrustum.Create; begin inherited Create; fTop := 0; fBottom := 0; fLeft := 0; fRight := 0; fNear := 0; fFar := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TglcCamera//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcCamera.GetPositionPtr: Pointer; begin result := @fPosition[0, 0]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcCamera.Move(const aVec: TgluVector3f); begin fPosition := gluMatrixMult(gluMatrixTranslate(aVec), fPosition); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcCamera.Tilt(const aAngle: Single); begin fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(1,0,0), aAngle), fPosition); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcCamera.Turn(const aAngle: Single); begin fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,1,0), aAngle), fPosition); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcCamera.Roll(const aAngle: Single); begin fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,0,1), aAngle), fPosition); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcCamera.Activate; begin inherited Activate; glLoadMatrixf(@fPosition[0, 0]); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcCamera.GetRay(const aPos: TgluVector2f): TgluRayf; var p: TgluVector3f; begin if (aPos[0] < 0) then p[0] := -aPos[0] * fLeft else p[0] := aPos[0] * fRight; if (aPos[1] < 0) then p[1] := -aPos[1] * fBottom else p[1] := aPos[1] * fTop; if (fIsOrthogonal) then begin p[2] := 0; result.p := fPosition * p; result.v := fPosition * gluVector3f(0, 0, -1); end else begin p[2] := -fNear; result.p := gluVector3f(0, 0, 0); result.v := fPosition * p; end; result := gluRayNormalize(result); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TglcCamera.Create; begin inherited Create; fPosition := gluMatrixIdentity; end; end.