|
- 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;
- fInvertPos: TgluMatrix4f;
- fInvertValid: Boolean;
-
- function GetInvertPos: TgluMatrix4f;
- function GetPositionPtr: Pointer;
- procedure SetPosition(aValue: TgluMatrix4f);
- public
- property Position: TgluMatrix4f read fPosition write SetPosition;
- property InvertPos: TgluMatrix4f read GetInvertPos;
- 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;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- function TglcCamera.GetInvertPos: TgluMatrix4f;
- begin
- if not fInvertValid then begin
- fInvertValid := true;
- fInvertPos := gluMatrixInvert(fPosition);
- end;
- result := fInvertPos;
- end;
-
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- procedure TglcCamera.SetPosition(aValue: TgluMatrix4f);
- begin
- fPosition := aValue;
- fInvertValid := false;
- 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;
- fInvertValid := false
- end;
-
- end.
|