You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

347 lines
12 KiB

  1. unit uglcCamera;
  2. { Package: OpenGLCore
  3. Prefix: glc - OpenGL Core
  4. Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Frustum und Kamera
  5. Beispiel:
  6. var
  7. camera: TglcCamera;
  8. camera := TglcCamera.Create;
  9. try
  10. camera.Perspective(45, 0.01, 100, 800/600); // define perspective view
  11. camera.Move(gluVector(2, 3, -5)); // move 2 right, 3 up and 5 back
  12. camera.Tilt(-25); // turn 25 degrees down
  13. camera.Turn(-10); // turn 10 degrees left
  14. camera.Activate; // activate camera
  15. // do normal rendering
  16. finally
  17. FreeAndNil(camera);
  18. end; }
  19. {$mode objfpc}{$H+}
  20. interface
  21. uses
  22. Classes, SysUtils,
  23. ugluVector, ugluMatrix;
  24. type
  25. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. TglcFrustum = class(TObject)
  27. private
  28. fProjMatrix: TgluMatrix4f;
  29. function GetProjMatrixPtr: Pointer;
  30. function GetWidth: Single;
  31. function GetHeight: Single;
  32. function GetFOVAngle: Single;
  33. function GetAspectRatio: Single;
  34. procedure UpdateProjMatrix;
  35. protected
  36. fIsOrthogonal: Boolean;
  37. fTop, fBottom, fLeft, fRight, fNear, fFar: Single;
  38. public
  39. property Top: Single read fTop;
  40. property Bottom: Single read fBottom;
  41. property Left: Single read fLeft;
  42. property Right: Single read fRight;
  43. property Near: Single read fNear;
  44. property Far: Single read fFar;
  45. property Width: Single read GetWidth;
  46. property Height: Single read GetHeight;
  47. property FOVAngle: Single read GetFOVAngle;
  48. property AspectRatio: Single read GetAspectRatio;
  49. property IsOrthogonal: Boolean read fIsOrthogonal;
  50. property ProjMatrix: TgluMatrix4f read fProjMatrix;
  51. property ProjMatrixPtr: Pointer read GetProjMatrixPtr;
  52. procedure Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
  53. procedure Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single);
  54. procedure Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
  55. procedure Activate;
  56. {$IFNDEF OPENGL_ES}
  57. procedure Render;
  58. {$ENDIF}
  59. constructor Create;
  60. end;
  61. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  62. TglcCamera = class(TglcFrustum)
  63. private
  64. fPosition: TgluMatrix4f;
  65. function GetPositionPtr: Pointer;
  66. public
  67. property Position: TgluMatrix4f read fPosition write fPosition;
  68. property PositionPtr: Pointer read GetPositionPtr;
  69. procedure Move(const aVec: TgluVector3f);
  70. procedure Tilt(const aAngle: Single);
  71. procedure Turn(const aAngle: Single);
  72. procedure Roll(const aAngle: Single);
  73. procedure Activate;
  74. function GetRay(const aPos: TgluVector2f): TgluRayf;
  75. constructor Create;
  76. end;
  77. implementation
  78. uses
  79. Math, {$IFNDEF OPENGL_ES}dglOpenGL{$ELSE}dglOpenGLES{$ENDIF};
  80. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. //TglcFrustum///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  83. procedure TglcFrustum.UpdateProjMatrix;
  84. begin
  85. if fIsOrthogonal then begin
  86. fProjMatrix[maAxisX] := gluVector4f(
  87. 2 / (fRight - fLeft),
  88. 0,
  89. 0,
  90. 0);
  91. fProjMatrix[maAxisY] := gluVector4f(
  92. 0,
  93. 2 / (fTop - fBottom),
  94. 0,
  95. 0);
  96. fProjMatrix[maAxisZ] := gluVector4f(
  97. 0,
  98. 0,
  99. -2 / (fFar - fNear),
  100. 0);
  101. fProjMatrix[maPos] := gluVector4f(
  102. -(fRight + fLeft) / (fRight - fLeft),
  103. -(fTop + fBottom) / (fTop - fBottom),
  104. -(fFar + fNear) / (fFar - fNear),
  105. 1);
  106. end else begin
  107. fProjMatrix[maAxisX] := gluVector4f(
  108. 2 * fNear / (fRight - fLeft),
  109. 0,
  110. 0,
  111. 0);
  112. fProjMatrix[maAxisY] := gluVector4f(
  113. 0,
  114. 2 * fNear / (fTop - fBottom),
  115. 0,
  116. 0);
  117. fProjMatrix[maAxisZ] := gluVector4f(
  118. (fRight + fLeft) / (fRight - fLeft),
  119. (fTop + fBottom) / (fTop - fBottom),
  120. -(fFar + fNear) / (fFar - fNear),
  121. -1);
  122. fProjMatrix[maPos] := gluVector4f(
  123. 0,
  124. 0,
  125. -2 * fFar * fNear / (fFar - fNear),
  126. 0);
  127. end;
  128. end;
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  130. function TglcFrustum.GetWidth: Single;
  131. begin
  132. result := (fRight - fLeft);
  133. end;
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. function TglcFrustum.GetProjMatrixPtr: Pointer;
  136. begin
  137. result := @fProjMatrix[0, 0];
  138. end;
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. function TglcFrustum.GetHeight: Single;
  141. begin
  142. result := (fTop - fBottom);
  143. end;
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. function TglcFrustum.GetFOVAngle: Single;
  146. begin
  147. result := arctan2(Height/2, fNear)/Pi*360;
  148. end;
  149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. function TglcFrustum.GetAspectRatio: Single;
  151. begin
  152. result := Height / Width;
  153. end;
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. procedure TglcFrustum.Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
  156. begin
  157. fIsOrthogonal := false;
  158. fTop := aRight;
  159. fBottom := aLeft;
  160. fLeft := aBottom;
  161. fRight := aTop;
  162. fNear := aNear;
  163. fFar := aFar;
  164. UpdateProjMatrix;
  165. end;
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. procedure TglcFrustum.Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single);
  168. begin
  169. fIsOrthogonal := false;
  170. fNear := aNear;
  171. fFar := aFar;
  172. fTop := fNear * tan(aFOVAngle / 360 * Pi);
  173. fBottom := -fTop;
  174. fRight := aAspectRatio * fTop;
  175. fLeft := -fRight;
  176. UpdateProjMatrix;
  177. end;
  178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  179. procedure TglcFrustum.Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
  180. begin
  181. fIsOrthogonal := true;
  182. fLeft := aLeft;
  183. fRight := aRight;
  184. fTop := aTop;
  185. fBottom := aBottom;
  186. fNear := aNear;
  187. fFar := aFar;
  188. UpdateProjMatrix;
  189. end;
  190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  191. procedure TglcFrustum.Activate;
  192. begin
  193. glMatrixMode(GL_PROJECTION);
  194. glLoadIdentity;
  195. if fIsOrthogonal then
  196. {$IFNDEF OPENGL_ES}glOrtho{$ELSE}glOrthof{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar)
  197. else
  198. {$IFNDEF OPENGL_ES}glFrustum{$ELSE}glFrustumf{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar);
  199. glMatrixMode(GL_MODELVIEW);
  200. end;
  201. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  202. {$IFNDEF OPENGL_ES}
  203. procedure TglcFrustum.Render;
  204. var
  205. min, max: TgluVector2f;
  206. begin
  207. min[0] := fLeft / fNear * fFar;
  208. min[1] := fBottom / fNear * fFar;
  209. max[0] := fRight / fNear * fFar;
  210. max[1] := fTop / fNear * fFar;
  211. glBegin(GL_LINE_LOOP);
  212. glVertex3f(fLeft, fTop, -fNear);
  213. glVertex3f(fLeft, fBottom, -fNear);
  214. glVertex3f(fRight, fBottom, -fNear);
  215. glVertex3f(fRight, fTop, -fNear);
  216. glEnd;
  217. glBegin(GL_LINE_LOOP);
  218. glVertex3f(min[0], min[0], -fFar);
  219. glVertex3f(min[0], max[0], -fFar);
  220. glVertex3f(max[0], max[0], -fFar);
  221. glVertex3f(max[0], min[0], -fFar);
  222. glEnd;
  223. glBegin(GL_LINES);
  224. glVertex3f(0, 0, 0); glVertex3f(min[0], min[0], -fFar);
  225. glVertex3f(0, 0, 0); glVertex3f(min[0], max[0], -fFar);
  226. glVertex3f(0, 0, 0); glVertex3f(max[0], max[0], -fFar);
  227. glVertex3f(0, 0, 0); glVertex3f(max[0], min[0], -fFar);
  228. glEnd;
  229. end;
  230. {$ENDIF}
  231. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  232. constructor TglcFrustum.Create;
  233. begin
  234. inherited Create;
  235. fTop := 0;
  236. fBottom := 0;
  237. fLeft := 0;
  238. fRight := 0;
  239. fNear := 0;
  240. fFar := 0;
  241. end;
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. //TglcCamera////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  244. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  245. function TglcCamera.GetPositionPtr: Pointer;
  246. begin
  247. result := @fPosition[0, 0];
  248. end;
  249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  250. procedure TglcCamera.Move(const aVec: TgluVector3f);
  251. begin
  252. fPosition := gluMatrixMult(gluMatrixTranslate(aVec), fPosition);
  253. end;
  254. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  255. procedure TglcCamera.Tilt(const aAngle: Single);
  256. begin
  257. fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(1,0,0), aAngle), fPosition);
  258. end;
  259. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  260. procedure TglcCamera.Turn(const aAngle: Single);
  261. begin
  262. fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,1,0), aAngle), fPosition);
  263. end;
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. procedure TglcCamera.Roll(const aAngle: Single);
  266. begin
  267. fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,0,1), aAngle), fPosition);
  268. end;
  269. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  270. procedure TglcCamera.Activate;
  271. begin
  272. inherited Activate;
  273. glLoadMatrixf(@fPosition[0, 0]);
  274. end;
  275. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. function TglcCamera.GetRay(const aPos: TgluVector2f): TgluRayf;
  277. var
  278. p: TgluVector3f;
  279. begin
  280. if (aPos[0] < 0) then
  281. p[0] := -aPos[0] * fLeft
  282. else
  283. p[0] := aPos[0] * fRight;
  284. if (aPos[1] < 0) then
  285. p[1] := -aPos[1] * fBottom
  286. else
  287. p[1] := aPos[1] * fTop;
  288. if (fIsOrthogonal) then begin
  289. p[2] := 0;
  290. result.p := fPosition * p;
  291. result.v := fPosition * gluVector3f(0, 0, -1);
  292. end else begin
  293. p[2] := -fNear;
  294. result.p := gluVector3f(0, 0, 0);
  295. result.v := fPosition * p;
  296. end;
  297. result := gluRayNormalize(result);
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. constructor TglcCamera.Create;
  301. begin
  302. inherited Create;
  303. fPosition := gluMatrixIdentity;
  304. end;
  305. end.