您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

371 行
13 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. fInvertPos: TgluMatrix4f;
  66. fInvertValid: Boolean;
  67. function GetInvertPos: TgluMatrix4f;
  68. function GetPositionPtr: Pointer;
  69. procedure SetPosition(aValue: TgluMatrix4f);
  70. public
  71. property Position: TgluMatrix4f read fPosition write SetPosition;
  72. property InvertPos: TgluMatrix4f read GetInvertPos;
  73. property PositionPtr: Pointer read GetPositionPtr;
  74. procedure Move(const aVec: TgluVector3f);
  75. procedure Tilt(const aAngle: Single);
  76. procedure Turn(const aAngle: Single);
  77. procedure Roll(const aAngle: Single);
  78. procedure Activate;
  79. function GetRay(const aPos: TgluVector2f): TgluRayf;
  80. constructor Create;
  81. end;
  82. implementation
  83. uses
  84. Math, {$IFNDEF OPENGL_ES}dglOpenGL{$ELSE}dglOpenGLES{$ENDIF};
  85. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. //TglcFrustum///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. procedure TglcFrustum.UpdateProjMatrix;
  89. begin
  90. if fIsOrthogonal then begin
  91. fProjMatrix[maAxisX] := gluVector4f(
  92. 2 / (fRight - fLeft),
  93. 0,
  94. 0,
  95. 0);
  96. fProjMatrix[maAxisY] := gluVector4f(
  97. 0,
  98. 2 / (fTop - fBottom),
  99. 0,
  100. 0);
  101. fProjMatrix[maAxisZ] := gluVector4f(
  102. 0,
  103. 0,
  104. -2 / (fFar - fNear),
  105. 0);
  106. fProjMatrix[maPos] := gluVector4f(
  107. -(fRight + fLeft) / (fRight - fLeft),
  108. -(fTop + fBottom) / (fTop - fBottom),
  109. -(fFar + fNear) / (fFar - fNear),
  110. 1);
  111. end else begin
  112. fProjMatrix[maAxisX] := gluVector4f(
  113. 2 * fNear / (fRight - fLeft),
  114. 0,
  115. 0,
  116. 0);
  117. fProjMatrix[maAxisY] := gluVector4f(
  118. 0,
  119. 2 * fNear / (fTop - fBottom),
  120. 0,
  121. 0);
  122. fProjMatrix[maAxisZ] := gluVector4f(
  123. (fRight + fLeft) / (fRight - fLeft),
  124. (fTop + fBottom) / (fTop - fBottom),
  125. -(fFar + fNear) / (fFar - fNear),
  126. -1);
  127. fProjMatrix[maPos] := gluVector4f(
  128. 0,
  129. 0,
  130. -2 * fFar * fNear / (fFar - fNear),
  131. 0);
  132. end;
  133. end;
  134. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  135. function TglcFrustum.GetWidth: Single;
  136. begin
  137. result := (fRight - fLeft);
  138. end;
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. function TglcFrustum.GetProjMatrixPtr: Pointer;
  141. begin
  142. result := @fProjMatrix[0, 0];
  143. end;
  144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  145. function TglcFrustum.GetHeight: Single;
  146. begin
  147. result := (fTop - fBottom);
  148. end;
  149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. function TglcFrustum.GetFOVAngle: Single;
  151. begin
  152. result := arctan2(Height/2, fNear)/Pi*360;
  153. end;
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. function TglcFrustum.GetAspectRatio: Single;
  156. begin
  157. result := Height / Width;
  158. end;
  159. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  160. procedure TglcFrustum.Frustum(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
  161. begin
  162. fIsOrthogonal := false;
  163. fTop := aRight;
  164. fBottom := aLeft;
  165. fLeft := aBottom;
  166. fRight := aTop;
  167. fNear := aNear;
  168. fFar := aFar;
  169. UpdateProjMatrix;
  170. end;
  171. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  172. procedure TglcFrustum.Perspective(const aFOVAngle, aAspectRatio, aNear, aFar: Single);
  173. begin
  174. fIsOrthogonal := false;
  175. fNear := aNear;
  176. fFar := aFar;
  177. fTop := fNear * tan(aFOVAngle / 360 * Pi);
  178. fBottom := -fTop;
  179. fRight := aAspectRatio * fTop;
  180. fLeft := -fRight;
  181. UpdateProjMatrix;
  182. end;
  183. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  184. procedure TglcFrustum.Ortho(const aLeft, aRight, aBottom, aTop, aNear, aFar: Single);
  185. begin
  186. fIsOrthogonal := true;
  187. fLeft := aLeft;
  188. fRight := aRight;
  189. fTop := aTop;
  190. fBottom := aBottom;
  191. fNear := aNear;
  192. fFar := aFar;
  193. UpdateProjMatrix;
  194. end;
  195. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  196. procedure TglcFrustum.Activate;
  197. begin
  198. glMatrixMode(GL_PROJECTION);
  199. glLoadIdentity;
  200. if fIsOrthogonal then
  201. {$IFNDEF OPENGL_ES}glOrtho{$ELSE}glOrthof{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar)
  202. else
  203. {$IFNDEF OPENGL_ES}glFrustum{$ELSE}glFrustumf{$ENDIF}(fLeft, fRight, fBottom, fTop, fNear, fFar);
  204. glMatrixMode(GL_MODELVIEW);
  205. end;
  206. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. {$IFNDEF OPENGL_ES}
  208. procedure TglcFrustum.Render;
  209. var
  210. min, max: TgluVector2f;
  211. begin
  212. min[0] := fLeft / fNear * fFar;
  213. min[1] := fBottom / fNear * fFar;
  214. max[0] := fRight / fNear * fFar;
  215. max[1] := fTop / fNear * fFar;
  216. glBegin(GL_LINE_LOOP);
  217. glVertex3f(fLeft, fTop, -fNear);
  218. glVertex3f(fLeft, fBottom, -fNear);
  219. glVertex3f(fRight, fBottom, -fNear);
  220. glVertex3f(fRight, fTop, -fNear);
  221. glEnd;
  222. glBegin(GL_LINE_LOOP);
  223. glVertex3f(min[0], min[0], -fFar);
  224. glVertex3f(min[0], max[0], -fFar);
  225. glVertex3f(max[0], max[0], -fFar);
  226. glVertex3f(max[0], min[0], -fFar);
  227. glEnd;
  228. glBegin(GL_LINES);
  229. glVertex3f(0, 0, 0); glVertex3f(min[0], min[0], -fFar);
  230. glVertex3f(0, 0, 0); glVertex3f(min[0], max[0], -fFar);
  231. glVertex3f(0, 0, 0); glVertex3f(max[0], max[0], -fFar);
  232. glVertex3f(0, 0, 0); glVertex3f(max[0], min[0], -fFar);
  233. glEnd;
  234. end;
  235. {$ENDIF}
  236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. constructor TglcFrustum.Create;
  238. begin
  239. inherited Create;
  240. fTop := 0;
  241. fBottom := 0;
  242. fLeft := 0;
  243. fRight := 0;
  244. fNear := 0;
  245. fFar := 0;
  246. end;
  247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. //TglcCamera////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  250. function TglcCamera.GetPositionPtr: Pointer;
  251. begin
  252. result := @fPosition[0, 0];
  253. end;
  254. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  255. function TglcCamera.GetInvertPos: TgluMatrix4f;
  256. begin
  257. if not fInvertValid then begin
  258. fInvertValid := true;
  259. fInvertPos := gluMatrixInvert(fPosition);
  260. end;
  261. result := fInvertPos;
  262. end;
  263. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  264. procedure TglcCamera.SetPosition(aValue: TgluMatrix4f);
  265. begin
  266. fPosition := aValue;
  267. fInvertValid := false;
  268. end;
  269. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  270. procedure TglcCamera.Move(const aVec: TgluVector3f);
  271. begin
  272. fPosition := gluMatrixMult(gluMatrixTranslate(aVec), fPosition);
  273. end;
  274. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  275. procedure TglcCamera.Tilt(const aAngle: Single);
  276. begin
  277. fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(1,0,0), aAngle), fPosition);
  278. end;
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  280. procedure TglcCamera.Turn(const aAngle: Single);
  281. begin
  282. fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,1,0), aAngle), fPosition);
  283. end;
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. procedure TglcCamera.Roll(const aAngle: Single);
  286. begin
  287. fPosition := gluMatrixMult(gluMatrixRotate(gluVector3f(0,0,1), aAngle), fPosition);
  288. end;
  289. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  290. procedure TglcCamera.Activate;
  291. begin
  292. inherited Activate;
  293. glLoadMatrixf(@fPosition[0, 0]);
  294. end;
  295. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  296. function TglcCamera.GetRay(const aPos: TgluVector2f): TgluRayf;
  297. var
  298. p: TgluVector3f;
  299. begin
  300. if (aPos[0] < 0) then
  301. p[0] := -aPos[0] * fLeft
  302. else
  303. p[0] := aPos[0] * fRight;
  304. if (aPos[1] < 0) then
  305. p[1] := -aPos[1] * fBottom
  306. else
  307. p[1] := aPos[1] * fTop;
  308. if (fIsOrthogonal) then begin
  309. p[2] := 0;
  310. result.p := fPosition * p;
  311. result.v := fPosition * gluVector3f(0, 0, -1);
  312. end else begin
  313. p[2] := -fNear;
  314. result.p := gluVector3f(0, 0, 0);
  315. result.v := fPosition * p;
  316. end;
  317. result := gluRayNormalize(result);
  318. end;
  319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  320. constructor TglcCamera.Create;
  321. begin
  322. inherited Create;
  323. fPosition := gluMatrixIdentity;
  324. fInvertValid := false
  325. end;
  326. end.