GLSkyBox.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLSkyBox;
  5. (*
  6. A TGLImmaterialSceneObject drawing 6 quads (plus another quad as "Cloud" plane)
  7. for use as a skybox always centered on the camera.
  8. *)
  9. interface
  10. {$I GLScene.inc}
  11. uses
  12. Winapi.OpenGL,
  13. System.Classes,
  14. GLScene,
  15. GLMaterial,
  16. GLVectorGeometry,
  17. OpenGLTokens,
  18. XOpenGL,
  19. GLRenderContextInfo,
  20. GLVectorTypes;
  21. type
  22. TGLSkyBoxStyle = (sbsFull, sbsTopHalf, sbsBottomHalf, sbTopTwoThirds,
  23. sbsTopHalfClamped);
  24. TGLSkyBox = class(TGLCameraInvariantObject, IGLMaterialLibrarySupported)
  25. private
  26. FMatNameTop: string;
  27. FMatNameRight: string;
  28. FMatNameFront: string;
  29. FMatNameLeft: string;
  30. FMatNameBack: string;
  31. FMatNameBottom: string;
  32. FMatNameClouds: string;
  33. FMaterialLibrary: TGLMaterialLibrary;
  34. FCloudsPlaneOffset: Single;
  35. FCloudsPlaneSize: Single;
  36. FStyle: TGLSkyBoxStyle;
  37. //implementing IGLMaterialLibrarySupported
  38. function GetMaterialLibrary: TGLAbstractMaterialLibrary;
  39. protected
  40. procedure SetMaterialLibrary(const Value: TGLMaterialLibrary);
  41. procedure SetMatNameBack(const Value: string);
  42. procedure SetMatNameBottom(const Value: string);
  43. procedure SetMatNameFront(const Value: string);
  44. procedure SetMatNameLeft(const Value: string);
  45. procedure SetMatNameRight(const Value: string);
  46. procedure SetMatNameTop(const Value: string);
  47. procedure SetMatNameClouds(const Value: string);
  48. procedure SetCloudsPlaneOffset(const Value: single);
  49. procedure SetCloudsPlaneSize(const Value: single);
  50. procedure SetStyle(const value: TGLSkyBoxStyle);
  51. public
  52. constructor Create(AOwner: TComponent); override;
  53. destructor Destroy; override;
  54. procedure DoRender(var ARci: TGLRenderContextInfo;
  55. ARenderSelf, ARenderChildren: Boolean); override;
  56. procedure BuildList(var ARci: TGLRenderContextInfo); override;
  57. procedure Notification(AComponent: TComponent; Operation: TOperation);
  58. override;
  59. published
  60. property MaterialLibrary: TGLMaterialLibrary read FMaterialLibrary write
  61. SetMaterialLibrary;
  62. property MatNameTop: TGLLibMaterialName read FMatNameTop write
  63. SetMatNameTop;
  64. property MatNameBottom: TGLLibMaterialName read FMatNameBottom write
  65. SetMatNameBottom;
  66. property MatNameLeft: TGLLibMaterialName read FMatNameLeft write
  67. SetMatNameLeft;
  68. property MatNameRight: TGLLibMaterialName read FMatNameRight write
  69. SetMatNameRight;
  70. property MatNameFront: TGLLibMaterialName read FMatNameFront write
  71. SetMatNameFront;
  72. property MatNameBack: TGLLibMaterialName read FMatNameBack write
  73. SetMatNameBack;
  74. property MatNameClouds: TGLLibMaterialName read FMatNameClouds write
  75. SetMatNameClouds;
  76. property CloudsPlaneOffset: Single read FCloudsPlaneOffset write
  77. SetCloudsPlaneOffset;
  78. property CloudsPlaneSize: Single read FCloudsPlaneSize write
  79. SetCloudsPlaneSize;
  80. property Style: TGLSkyBoxStyle read FStyle write FStyle default sbsFull;
  81. end;
  82. // ------------------------------------------------------------------
  83. implementation
  84. // ------------------------------------------------------------------
  85. uses
  86. GLContext,
  87. GLState;
  88. // ------------------
  89. // ------------------ TGLSkyBox ------------------
  90. // ------------------
  91. constructor TGLSkyBox.Create(AOwner: TComponent);
  92. begin
  93. inherited Create(AOwner);
  94. CamInvarianceMode := cimPosition;
  95. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  96. FCloudsPlaneOffset := 0.2;
  97. // this should be set far enough to avoid near plane clipping
  98. FCloudsPlaneSize := 32;
  99. // the bigger, the more this extends the clouds cap to the horizon
  100. end;
  101. destructor TGLSkyBox.Destroy;
  102. begin
  103. inherited;
  104. end;
  105. function TGLSkyBox.GetMaterialLibrary: TGLAbstractMaterialLibrary;
  106. begin
  107. Result := FMaterialLibrary;
  108. end;
  109. procedure TGLSkyBox.Notification(AComponent: TComponent; Operation: TOperation);
  110. begin
  111. if (Operation = opRemove) and (AComponent = FMaterialLibrary) then
  112. MaterialLibrary := nil;
  113. inherited;
  114. end;
  115. procedure TGLSkyBox.DoRender(var ARci: TGLRenderContextInfo; ARenderSelf,
  116. ARenderChildren: Boolean);
  117. begin
  118. // We want children of the sky box to appear far away too
  119. // (note: simply not writing to depth buffer may not make this not work,
  120. // child objects may need the depth buffer to render themselves properly,
  121. // this may require depth buffer cleared after that. - DanB)
  122. Arci.GLStates.DepthWriteMask := False;
  123. Arci.ignoreDepthRequests := true;
  124. inherited;
  125. Arci.ignoreDepthRequests := False;
  126. end;
  127. procedure TGLSkyBox.BuildList(var ARci: TGLRenderContextInfo);
  128. var
  129. f, cps, cof1: Single;
  130. oldStates: TGLStates;
  131. libMat: TGLLibMaterial;
  132. begin
  133. if FMaterialLibrary = nil then
  134. Exit;
  135. with ARci.GLStates do
  136. begin
  137. oldStates := States;
  138. Disable(stDepthTest);
  139. Disable(stLighting);
  140. Disable(stFog);
  141. end;
  142. gl.PushMatrix;
  143. f := ARci.rcci.farClippingDistance * 0.5;
  144. gl.Scalef(f, f, f);
  145. try
  146. case Style of
  147. sbsFull: ;
  148. sbsTopHalf, sbsTopHalfClamped:
  149. begin
  150. gl.Translatef(0, 0.5, 0);
  151. gl.Scalef(1, 0.5, 1);
  152. end;
  153. sbsBottomHalf:
  154. begin
  155. gl.Translatef(0, -0.5, 0);
  156. gl.Scalef(1, 0.5, 1);
  157. end;
  158. sbTopTwoThirds:
  159. begin
  160. gl.Translatef(0, 1 / 3, 0);
  161. gl.Scalef(1, 2 / 3, 1);
  162. end;
  163. end;
  164. // FRONT
  165. libMat := MaterialLibrary.LibMaterialByName(FMatNameFront);
  166. if libMat <> nil then
  167. begin
  168. libMat.Apply(ARci);
  169. repeat
  170. gl.Begin_(GL_QUADS);
  171. xgl.TexCoord2f(0.002, 0.998);
  172. gl.Vertex3f(-1, 1, -1);
  173. xgl.TexCoord2f(0.002, 0.002);
  174. gl.Vertex3f(-1, -1, -1);
  175. xgl.TexCoord2f(0.998, 0.002);
  176. gl.Vertex3f(1, -1, -1);
  177. xgl.TexCoord2f(0.998, 0.998);
  178. gl.Vertex3f(1, 1, -1);
  179. if Style = sbsTopHalfClamped then
  180. begin
  181. xgl.TexCoord2f(0.002, 0.002);
  182. gl.Vertex3f(-1, -1, -1);
  183. xgl.TexCoord2f(0.002, 0.002);
  184. gl.Vertex3f(-1, -3, -1);
  185. xgl.TexCoord2f(0.998, 0.002);
  186. gl.Vertex3f(1, -3, -1);
  187. xgl.TexCoord2f(0.998, 0.002);
  188. gl.Vertex3f(1, -1, -1);
  189. end;
  190. gl.End_;
  191. until not libMat.UnApply(ARci);
  192. end;
  193. // BACK
  194. libMat := MaterialLibrary.LibMaterialByName(FMatNameBack);
  195. if libMat <> nil then
  196. begin
  197. libMat.Apply(ARci);
  198. repeat
  199. gl.Begin_(GL_QUADS);
  200. xgl.TexCoord2f(0.002, 0.998);
  201. gl.Vertex3f(1, 1, 1);
  202. xgl.TexCoord2f(0.002, 0.002);
  203. gl.Vertex3f(1, -1, 1);
  204. xgl.TexCoord2f(0.998, 0.002);
  205. gl.Vertex3f(-1, -1, 1);
  206. xgl.TexCoord2f(0.998, 0.998);
  207. gl.Vertex3f(-1, 1, 1);
  208. if Style = sbsTopHalfClamped then
  209. begin
  210. xgl.TexCoord2f(0.002, 0.002);
  211. gl.Vertex3f(1, -1, 1);
  212. xgl.TexCoord2f(0.002, 0.002);
  213. gl.Vertex3f(1, -3, 1);
  214. xgl.TexCoord2f(0.998, 0.002);
  215. gl.Vertex3f(-1, -3, 1);
  216. xgl.TexCoord2f(0.998, 0.002);
  217. gl.Vertex3f(-1, -1, 1);
  218. end;
  219. gl.End_;
  220. until not libMat.UnApply(ARci);
  221. end;
  222. // TOP
  223. libMat := MaterialLibrary.LibMaterialByName(FMatNameTop);
  224. if libMat <> nil then
  225. begin
  226. libMat.Apply(ARci);
  227. repeat
  228. gl.Begin_(GL_QUADS);
  229. xgl.TexCoord2f(0.002, 0.998);
  230. gl.Vertex3f(-1, 1, 1);
  231. xgl.TexCoord2f(0.002, 0.002);
  232. gl.Vertex3f(-1, 1, -1);
  233. xgl.TexCoord2f(0.998, 0.002);
  234. gl.Vertex3f(1, 1, -1);
  235. xgl.TexCoord2f(0.998, 0.998);
  236. gl.Vertex3f(1, 1, 1);
  237. gl.End_;
  238. until not libMat.UnApply(ARci);
  239. end;
  240. // BOTTOM
  241. libMat := MaterialLibrary.LibMaterialByName(FMatNameBottom);
  242. if libMat <> nil then
  243. begin
  244. libMat.Apply(ARci);
  245. repeat
  246. gl.Begin_(GL_QUADS);
  247. xgl.TexCoord2f(0.002, 0.998);
  248. gl.Vertex3f(-1, -1, -1);
  249. xgl.TexCoord2f(0.002, 0.002);
  250. gl.Vertex3f(-1, -1, 1);
  251. xgl.TexCoord2f(0.998, 0.002);
  252. gl.Vertex3f(1, -1, 1);
  253. xgl.TexCoord2f(0.998, 0.998);
  254. gl.Vertex3f(1, -1, -1);
  255. gl.End_;
  256. until not libMat.UnApply(ARci);
  257. end;
  258. // LEFT
  259. libMat := MaterialLibrary.LibMaterialByName(FMatNameLeft);
  260. if libMat <> nil then
  261. begin
  262. libMat.Apply(ARci);
  263. repeat
  264. gl.Begin_(GL_QUADS);
  265. xgl.TexCoord2f(0.002, 0.998);
  266. gl.Vertex3f(-1, 1, 1);
  267. xgl.TexCoord2f(0.002, 0.002);
  268. gl.Vertex3f(-1, -1, 1);
  269. xgl.TexCoord2f(0.998, 0.002);
  270. gl.Vertex3f(-1, -1, -1);
  271. xgl.TexCoord2f(0.998, 0.998);
  272. gl.Vertex3f(-1, 1, -1);
  273. if Style = sbsTopHalfClamped then
  274. begin
  275. xgl.TexCoord2f(0.002, 0.002);
  276. gl.Vertex3f(-1, -1, 1);
  277. xgl.TexCoord2f(0.002, 0.002);
  278. gl.Vertex3f(-1, -3, 1);
  279. xgl.TexCoord2f(0.998, 0.002);
  280. gl.Vertex3f(-1, -3, -1);
  281. xgl.TexCoord2f(0.998, 0.002);
  282. gl.Vertex3f(-1, -1, -1);
  283. end;
  284. gl.End_;
  285. until not libMat.UnApply(ARci);
  286. end;
  287. // RIGHT
  288. libMat := MaterialLibrary.LibMaterialByName(FMatNameRight);
  289. if libMat <> nil then
  290. begin
  291. libMat.Apply(ARci);
  292. repeat
  293. gl.Begin_(GL_QUADS);
  294. xgl.TexCoord2f(0.002, 0.998);
  295. gl.Vertex3f(1, 1, -1);
  296. xgl.TexCoord2f(0.002, 0.002);
  297. gl.Vertex3f(1, -1, -1);
  298. xgl.TexCoord2f(0.998, 0.002);
  299. gl.Vertex3f(1, -1, 1);
  300. xgl.TexCoord2f(0.998, 0.998);
  301. gl.Vertex3f(1, 1, 1);
  302. if Style = sbsTopHalfClamped then
  303. begin
  304. xgl.TexCoord2f(0.002, 0.002);
  305. gl.Vertex3f(1, -1, -1);
  306. xgl.TexCoord2f(0.002, 0.002);
  307. gl.Vertex3f(1, -3, -1);
  308. xgl.TexCoord2f(0.998, 0.002);
  309. gl.Vertex3f(1, -3, 1);
  310. xgl.TexCoord2f(0.998, 0.002);
  311. gl.Vertex3f(1, -1, 1);
  312. end;
  313. gl.End_;
  314. until not libMat.UnApply(ARci);
  315. end;
  316. // CLOUDS CAP PLANE
  317. libMat := MaterialLibrary.LibMaterialByName(FMatNameClouds);
  318. if libMat <> nil then
  319. begin
  320. // pre-calculate possible values to speed up
  321. cps := FCloudsPlaneSize * 0.5;
  322. cof1 := FCloudsPlaneOffset;
  323. libMat.Apply(ARci);
  324. repeat
  325. gl.Begin_(GL_QUADS);
  326. xgl.TexCoord2f(0, 1);
  327. gl.Vertex3f(-cps, cof1, cps);
  328. xgl.TexCoord2f(0, 0);
  329. gl.Vertex3f(-cps, cof1, -cps);
  330. xgl.TexCoord2f(1, 0);
  331. gl.Vertex3f(cps, cof1, -cps);
  332. xgl.TexCoord2f(1, 1);
  333. gl.Vertex3f(cps, cof1, cps);
  334. gl.End_;
  335. until not libMat.UnApply(ARci);
  336. end;
  337. gl.PopMatrix;
  338. if stLighting in oldStates then
  339. ARci.GLStates.Enable(stLighting);
  340. if stFog in oldStates then
  341. ARci.GLStates.Enable(stFog);
  342. if stDepthTest in oldStates then
  343. ARci.GLStates.Enable(stDepthTest);
  344. finally
  345. end;
  346. end;
  347. procedure TGLSkyBox.SetCloudsPlaneOffset(const Value: single);
  348. begin
  349. FCloudsPlaneOffset := Value;
  350. StructureChanged;
  351. end;
  352. procedure TGLSkyBox.SetCloudsPlaneSize(const Value: single);
  353. begin
  354. FCloudsPlaneSize := Value;
  355. StructureChanged;
  356. end;
  357. procedure TGLSkyBox.SetStyle(const value: TGLSkyBoxStyle);
  358. begin
  359. FStyle := value;
  360. StructureChanged;
  361. end;
  362. procedure TGLSkyBox.SetMaterialLibrary(const value: TGLMaterialLibrary);
  363. begin
  364. FMaterialLibrary := value;
  365. StructureChanged;
  366. end;
  367. procedure TGLSkyBox.SetMatNameBack(const Value: string);
  368. begin
  369. FMatNameBack := Value;
  370. StructureChanged;
  371. end;
  372. procedure TGLSkyBox.SetMatNameBottom(const Value: string);
  373. begin
  374. FMatNameBottom := Value;
  375. StructureChanged;
  376. end;
  377. procedure TGLSkyBox.SetMatNameClouds(const Value: string);
  378. begin
  379. FMatNameClouds := Value;
  380. StructureChanged;
  381. end;
  382. procedure TGLSkyBox.SetMatNameFront(const Value: string);
  383. begin
  384. FMatNameFront := Value;
  385. StructureChanged;
  386. end;
  387. procedure TGLSkyBox.SetMatNameLeft(const Value: string);
  388. begin
  389. FMatNameLeft := Value;
  390. StructureChanged;
  391. end;
  392. procedure TGLSkyBox.SetMatNameRight(const Value: string);
  393. begin
  394. FMatNameRight := Value;
  395. StructureChanged;
  396. end;
  397. procedure TGLSkyBox.SetMatNameTop(const Value: string);
  398. begin
  399. FMatNameTop := Value;
  400. StructureChanged;
  401. end;
  402. // ------------------------------------------------------------------
  403. initialization
  404. // ------------------------------------------------------------------
  405. RegisterClass(TGLSkyBox);
  406. end.