unit uglcCamera; { Package: OpenGLCore Prefix: glc - OpenGL Core Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Frustum und Kamera } {$mode objfpc}{$H+} interface uses Classes, SysUtils, ugluVector, ugluMatrix; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TglcFrustum = class(TObject) private function GetWidth: Single; function GetHeight: Single; function GetFOVAngle: Single; function GetAspectRatio: Single; 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; 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; procedure Render; constructor Create; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TglcCamera = class(TglcFrustum) private fPosition: TgluMatrix4f; public property Position: TgluMatrix4f read fPosition write fPosition; 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, dglOpenGL; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TglcFrustum/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TglcFrustum.GetWidth: Single; begin result := (fRight - fLeft); 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; 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; 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; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TglcFrustum.Activate; begin glMatrixMode(GL_PROJECTION); glLoadIdentity; if fIsOrthogonal then glOrtho(fLeft, fRight, fBottom, fTop, fNear, fFar) else glFrustum(fLeft, fRight, fBottom, fTop, fNear, fFar); glMatrixMode(GL_MODELVIEW); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TglcFrustum.Create; begin inherited Create; fTop := 0; fBottom := 0; fLeft := 0; fRight := 0; fNear := 0; fFar := 0; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TglcCamera//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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.