Skip to content

Commit 902d10b

Browse files
ADD: uopenGL_camera.pas
1 parent 24ed36f commit 902d10b

File tree

2 files changed

+262
-0
lines changed

2 files changed

+262
-0
lines changed

OpenGL/uopengl_camera.pas

+261
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
(******************************************************************************)
2+
(* uopengl_camera.pas 13.05.2025 *)
3+
(* *)
4+
(* Version : 0.01 *)
5+
(* *)
6+
(* Author : Uwe Schächterle (Corpsman) *)
7+
(* *)
8+
(* Support : www.Corpsman.de *)
9+
(* *)
10+
(* Description : Implements a OpenGL, 3D camera class *)
11+
(* By defining a Pos, Target and Up Vector, you could afterwords*)
12+
(* Translate / Rotate the CAM freely. *)
13+
(* *)
14+
(* License : See the file license.md, located under: *)
15+
(* https://github.com/PascalCorpsman/Software_Licenses/blob/main/license.md *)
16+
(* for details about the license. *)
17+
(* *)
18+
(* It is not allowed to change or remove this text from any *)
19+
(* source file of the project. *)
20+
(* *)
21+
(* Warranty : There is no warranty, neither in correctness of the *)
22+
(* implementation, nor anything other that could happen *)
23+
(* or go wrong, use at your own risk. *)
24+
(* *)
25+
(* Known Issues: none *)
26+
(* *)
27+
(* History : 0.01 - Initial version *)
28+
(* *)
29+
(******************************************************************************)
30+
Unit uopengl_camera;
31+
32+
{$MODE ObjFPC}{$H+}
33+
34+
Interface
35+
36+
Uses
37+
Classes, SysUtils, dglOpenGL
38+
, uvectormath;
39+
40+
Type
41+
42+
{ TOpenGLCamera }
43+
44+
TOpenGLCamera = Class
45+
private
46+
fDefPos, fDefTarget, fDefUp: TVector3;
47+
fPos, fTarget, fup: TVector3;
48+
public
49+
50+
Property Target: TVector3 read fTarget;
51+
Property Pos: TVector3 read fPos;
52+
53+
Constructor Create(aPos, aTarget, aUp: TVector3);
54+
55+
(*
56+
* Call this function right after you cleared all OpenGL Buffers and
57+
* glLoadIdentity in the OnRender Routine, it will initialize the
58+
* ModelView Matrix, so that you can directly render the szene.
59+
*)
60+
Procedure SetCam;
61+
62+
(*
63+
* Resets, Camera Position, Up and Target to the values given on creation
64+
*)
65+
Procedure Reset;
66+
67+
(*
68+
* Translate Camera and Target, no change in Direction
69+
*
70+
* So ganz Sauber sind die beiden Routinen nicht, da sie beide
71+
* die Kamera Richtung berücksichtigen.
72+
* Im Zweifel dürfte "TranslateByWorld" die gefühlt Richtigere sein
73+
*)
74+
Procedure TranslateByView(x, y, z: Single);
75+
Procedure TranslateByWorld(x, y, z: Single);
76+
77+
(*
78+
* Roates Camera, without Gimbal Lock
79+
*)
80+
Procedure Rotate(dx, dy, dz: Single); // Attention: atm, dz is ignored !
81+
82+
(*
83+
* Zoom In / Out
84+
* Effects Cam - Target distance
85+
* aZoomValue: 1 = No Zoom , < 1 = Zoom in, > 1 = Zoom Out
86+
* Example: If you zoomed in with 1.1 you need to zoom out with 1/1.1
87+
*)
88+
Procedure Zoom(aZoomValue: Single);
89+
90+
(*
91+
* Renders a small little gizmo in the right bottom corner ;)
92+
* If used, call directly after SetCam (
93+
*)
94+
Procedure RenderGizmo(aBorder, aWidth, aHeight: Integer; aSize: Single); // Size (= Size) -> -2 = Big, -9 = tiny
95+
End;
96+
97+
Implementation
98+
99+
Uses uquaternion;
100+
101+
{ TOpenGLCamera }
102+
103+
Procedure TOpenGLCamera.RenderGizmo(aBorder, aWidth, aHeight: Integer; aSize: Single);
104+
Var
105+
vp: Array[0..3] Of GLint;
106+
mv: TMatrix4x4;
107+
lw: GLfloat;
108+
Begin
109+
// Auslesen der Modelview (wie sie von SetCam gesetzt wurde)
110+
glGetFloatv(GL_MODELVIEW_MATRIX, @mv);
111+
112+
// Anpassen des ViewPort für den Gizmo
113+
glGetIntegerv(GL_VIEWPORT, @vp);
114+
glViewport(vp[2] - aBorder - aWidth, aBorder, aWidth, aHeight);
115+
glMatrixMode(GL_PROJECTION);
116+
glPushMatrix;
117+
glLoadIdentity;
118+
gluPerspective(45.0, 1.0, 0.1, 10.0);
119+
120+
glMatrixMode(GL_MODELVIEW);
121+
glPushMatrix;
122+
glLoadIdentity;
123+
124+
// Rendern des Gizmo
125+
126+
// 1. Übernehmen der SetCam Rotation Matrix, aber mit "eigener" Position
127+
mv[3, 0] := 0;
128+
mv[3, 1] := 0;
129+
mv[3, 2] := -aSize;
130+
glMultMatrixf(@mv);
131+
132+
// Eigentlichen Rendern des Gizmo
133+
glGetFloatv(GL_LINE_WIDTH, @lw);
134+
glLineWidth(2.0);
135+
136+
glBegin(GL_LINES);
137+
// X – Rot
138+
glColor3f(1, 0, 0);
139+
glVertex3f(0, 0, 0);
140+
glVertex3f(1, 0, 0);
141+
// Y – Grün
142+
glColor3f(0, 1, 0);
143+
glVertex3f(0, 0, 0);
144+
glVertex3f(0, 1, 0);
145+
// Z – Blau
146+
glColor3f(0, 0, 1);
147+
glVertex3f(0, 0, 0);
148+
glVertex3f(0, 0, 1);
149+
glEnd;
150+
151+
// Zurücksetzen Aller Werte auf Zustand vor Aufruf RenderGizmo
152+
glLineWidth(lw);
153+
glPopMatrix;
154+
glMatrixMode(GL_PROJECTION);
155+
glPopMatrix;
156+
glMatrixMode(GL_MODELVIEW);
157+
glViewport(vp[0], vp[1], vp[2], vp[3]);
158+
End;
159+
160+
Constructor TOpenGLCamera.Create(aPos, aTarget, aUp: TVector3);
161+
Begin
162+
fDefPos := aPos;
163+
fDefTarget := aTarget;
164+
fDefUp := aUp;
165+
End;
166+
167+
Procedure TOpenGLCamera.Reset;
168+
Begin
169+
fPos := fDefPos;
170+
fTarget := fDefTarget;
171+
fup := fDefUp;
172+
End;
173+
174+
Procedure TOpenGLCamera.SetCam;
175+
Begin
176+
// Hauptkamera setzen
177+
gluLookAt(
178+
FPos.x, FPos.y, FPos.z,
179+
FTarget.x, FTarget.y, FTarget.z,
180+
fUp.x, fUp.y, fUp.z
181+
);
182+
End;
183+
184+
Procedure TOpenGLCamera.TranslateByView(x, y, z: Single);
185+
Var
186+
forward, right, up, move: TVector3;
187+
Begin
188+
forward := NormV3(fTarget - fPos);
189+
right := NormV3(CrossV3(forward, fUp));
190+
up := CrossV3(right, forward);
191+
move := right * x + up * y + forward * z;
192+
fPos := fPos + move;
193+
fTarget := fTarget + move;
194+
End;
195+
196+
Procedure TOpenGLCamera.TranslateByWorld(x, y, z: Single);
197+
Var
198+
forward, right, up, move: TVector3;
199+
Begin
200+
forward := NormV3(fTarget - fPos);
201+
right := NormV3(CrossV3(forward, fUp));
202+
up := CrossV3(right, forward);
203+
forward := NormV3(CrossV3(right, fDefUp));
204+
up := NormV3(fDefUp);
205+
move := right * x + up * y + forward * z;
206+
fPos := fPos + move;
207+
fTarget := fTarget + move;
208+
End;
209+
210+
Procedure TOpenGLCamera.Rotate(dx, dy, dz: Single);
211+
Var
212+
offset: TVector3;
213+
pitchAxis, yawAxis: TVector3;
214+
qPitch, qYaw: TQuaternion;
215+
rotation: TMatrix4x4;
216+
forward, right: TVector3;
217+
Begin
218+
// Richtung vom Ziel zur Kamera
219+
offset := fPos - fTarget;
220+
221+
// forward-Vektor (Blickrichtung)
222+
forward := NormV3(fTarget - fPos);
223+
224+
// yaw: immer um Welt-Up (z. B. Y-Achse)
225+
yawAxis := fDefUp;
226+
227+
// pitch: um lokale X-Achse = Right-Vektor
228+
right := NormV3(CrossV3(forward, fDefUp));
229+
pitchAxis := right;
230+
231+
// Erzeuge Quaternionen aus dynamischen Achsen
232+
qPitch := V3ToQ(pitchAxis, dx); // Kamera-X (lokal)
233+
qYaw := V3ToQ(yawAxis, dy); // Welt-Y (global)
234+
235+
// Kombinierte Rotation
236+
rotation := QToM4x4(qYaw * qPitch);
237+
238+
// Versetze Kamera um rotierten Vektor
239+
fPos := rotation * v4(offset, 0) + fTarget;
240+
241+
// Optional: Roll unterdrücken durch Up-Neuberechnung
242+
forward := NormV3(fTarget - fPos);
243+
right := NormV3(CrossV3(forward, fDefUp));
244+
fUp := CrossV3(right, forward); // neue Up-Richtung (orthonormal)
245+
End;
246+
247+
Procedure TOpenGLCamera.Zoom(aZoomValue: Single);
248+
Var
249+
offset: TVector3;
250+
Begin
251+
aZoomValue := Clamp(aZoomValue, 0.1, 10.0);
252+
// Richtung vom Ziel zur Kamera
253+
offset := fPos - fTarget;
254+
// Skaliere den Offset-Vektor
255+
offset := offset * aZoomValue;
256+
// Neue Position
257+
fPos := fTarget + offset;
258+
End;
259+
260+
End.
261+

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Collection of classes and examples that are mainly related to OpenGL implementat
2121
| umapviewer.pas | LCL-Component to make google mapviewer in OpenGL possible |
2222
| uopengl_animation.pas | Class to load and render .ani files (see Animation_Editor) |
2323
| uopengl_ascii_font.pas | DOS-stile ASCII-Font to easily show texts in OpenGL windows |
24+
| uopengl_camera.pas | Helper class to correct set OpenGL modelview matrix in a scene |
2425
| uopengl_font_common.pas | Anchestorclass for TOpenGL_TrueType_Font and TOpenGL_ASCII_Font |
2526
| uopengl_graphikengine.pas | Class to load and render graphics into the OpenGL window |
2627
| uopengl_partikelengine.pas | Class to render thousands of particle graphics into the OpenGL window |

0 commit comments

Comments
 (0)