GLS.Mirror.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.Mirror;
  5. (*
  6. Implements a basic, stencil-based mirror (as in Mark Kilgard's demo).
  7. It is strongly recommended to read and understand the explanations in the
  8. materials/mirror demo before using this component.
  9. *)
  10. interface
  11. {$I GLScene.inc}
  12. uses
  13. Winapi.OpenGL,
  14. System.Classes,
  15. GLS.OpenGLTokens,
  16. GLS.OpenGLAdapter,
  17. GLS.Scene,
  18. GLS.VectorGeometry,
  19. GLS.Context,
  20. GLS.Material,
  21. GLS.Color,
  22. GLS.RenderContextInfo,
  23. GLS.State,
  24. GLS.VectorTypes,
  25. GLS.PersistentClasses,
  26. GLS.PipelineTransformation,
  27. GLS.XCollection,
  28. GLS.Texture;
  29. type
  30. TGLMirrorOption = (moUseStencil, moOpaque, moMirrorPlaneClip, moClearZBuffer);
  31. TGLMirrorOptions = set of TGLMirrorOption;
  32. const
  33. cDefaultMirrorOptions = [moUseStencil];
  34. type
  35. TMirrorShapes = (msRect, msDisk);
  36. (* A simple plane mirror.
  37. This mirror requires a stencil buffer for optimal rendering!
  38. The object is a mix between a plane and a proxy object, in that the plane
  39. defines the mirror's surface, while the proxy part is used to reference
  40. the objects that should be mirrored (it is legal to self-mirror, but no
  41. self-mirror visuals will be rendered).
  42. It is strongly recommended to read and understand the explanations in the
  43. materials/mirror demo before using this component. *)
  44. TGLMirror = class(TGLSceneObject)
  45. private
  46. FRendering: Boolean;
  47. FMirrorObject: TGLBaseSceneObject;
  48. FWidth, FHeight: Single;
  49. FMirrorOptions: TGLMirrorOptions;
  50. FOnBeginRenderingMirrors, FOnEndRenderingMirrors: TNotifyEvent;
  51. FShape: TMirrorShapes; //ORL
  52. FRadius: Single; //ORL
  53. FSlices: Integer; //ORL
  54. protected
  55. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  56. procedure SetMirrorObject(const val: TGLBaseSceneObject);
  57. procedure SetMirrorOptions(const val: TGLMirrorOptions);
  58. procedure ClearZBufferArea(aBuffer: TGLSceneBuffer);
  59. procedure SetHeight(AValue: Single);
  60. procedure SetWidth(AValue: Single);
  61. procedure SetRadius(const aValue: Single); //ORL
  62. procedure SetSlices(const aValue: Integer); //ORL
  63. procedure SetShape(aValue: TMirrorShapes); //ORL
  64. function GetRadius: Single; //ORL
  65. function GetSlices: Integer; //ORL
  66. public
  67. constructor Create(AOwner: TComponent); override;
  68. procedure DoRender(var ARci: TGLRenderContextInfo;
  69. ARenderSelf, ARenderChildren: Boolean); override;
  70. procedure BuildList(var ARci: TGLRenderContextInfo); override;
  71. procedure Assign(Source: TPersistent); override;
  72. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  73. published
  74. // Selects the object to mirror. If nil, the whole scene is mirrored
  75. property MirrorObject: TGLBaseSceneObject read FMirrorObject write
  76. SetMirrorObject;
  77. (* Controls rendering options.
  78. moUseStencil: mirror area is stenciled, prevents reflected
  79. objects to be visible on the sides of the mirror (stencil buffer
  80. must be active in the viewer)
  81. moOpaque: mirror is opaque (ie. painted with background color)
  82. moMirrorPlaneClip: a ClipPlane is defined to prevent reflections
  83. from popping out of the mirror (for objects behind or halfway through)
  84. moClearZBuffer: mirror area's ZBuffer is cleared so that background
  85. objects don't interfere with reflected objects (reflected objects
  86. must be rendered AFTER the mirror in the hierarchy). Works only
  87. along with stenciling. *)
  88. property MirrorOptions: TGLMirrorOptions read FMirrorOptions write
  89. SetMirrorOptions default cDefaultMirrorOptions;
  90. property Height: Single read FHeight write SetHeight;
  91. property Width: Single read FWidth write SetWidth;
  92. // Fired before the object's mirror images are rendered.
  93. property OnBeginRenderingMirrors: TNotifyEvent read FOnBeginRenderingMirrors
  94. write FOnBeginRenderingMirrors;
  95. // Fired after the object's mirror images are rendered.
  96. property OnEndRenderingMirrors: TNotifyEvent read FOnEndRenderingMirrors
  97. write FOnEndRenderingMirrors;
  98. property Radius: Single read FRadius write SetRadius; //ORL
  99. property Slices: Integer read FSlices write SetSlices default 16; //ORL
  100. property Shape: TMirrorShapes read FShape write SetShape default msRect;
  101. //ORL
  102. end;
  103. //-------------------------------------------------------------
  104. implementation
  105. //-------------------------------------------------------------
  106. // ------------------
  107. // ------------------ TGLMirror ------------------
  108. // ------------------
  109. constructor TGLMirror.Create(AOwner: Tcomponent);
  110. begin
  111. inherited Create(AOwner);
  112. FWidth := 1;
  113. FHeight := 1;
  114. FMirrorOptions := cDefaultMirrorOptions;
  115. ObjectStyle := ObjectStyle + [osDirectDraw];
  116. Material.FrontProperties.Diffuse.Initialize(VectorMake(1, 1, 1, 0.1));
  117. Material.BlendingMode := bmTransparency;
  118. FRadius := 1; //ORL
  119. FSlices := 16; //ORL
  120. Shape := msRect; //ORL
  121. end;
  122. procedure TGLMirror.DoRender(var ARci: TGLRenderContextInfo;
  123. ARenderSelf, ARenderChildren: Boolean);
  124. var
  125. oldProxySubObject: Boolean;
  126. refMat, curMat, ModelMat: TGLMatrix;
  127. clipPlane: TDoubleHmgPlane;
  128. bgColor: TGLColorVector;
  129. cameraPosBackup, cameraDirectionBackup: TGLVector;
  130. CurrentBuffer: TGLSceneBuffer;
  131. begin
  132. if FRendering then
  133. Exit;
  134. FRendering := True;
  135. try
  136. oldProxySubObject := ARci.proxySubObject;
  137. ARci.proxySubObject := True;
  138. CurrentBuffer := TGLSceneBuffer(ARci.buffer);
  139. if VectorDotProduct(VectorSubtract(ARci.cameraPosition, AbsolutePosition),
  140. AbsoluteDirection) > 0 then
  141. with ARci.GLStates do
  142. begin
  143. // "Render" stencil mask
  144. if MirrorOptions <> [] then
  145. begin
  146. if (moUseStencil in MirrorOptions) then
  147. begin
  148. Enable(stStencilTest);
  149. ARci.GLStates.StencilClearValue := 0;
  150. gl.Clear(GL_STENCIL_BUFFER_BIT);
  151. SetStencilFunc(cfAlways, 1, 1);
  152. SetStencilOp(soReplace, soZero, soReplace);
  153. end;
  154. if (moOpaque in MirrorOptions) then
  155. begin
  156. bgColor := ConvertWinColor(CurrentBuffer.BackgroundColor);
  157. ARci.GLStates.SetGLMaterialColors(cmFront, bgColor, clrBlack,
  158. clrBlack, clrBlack, 0);
  159. end
  160. else
  161. SetGLColorWriting(False);
  162. Enable(stDepthTest);
  163. DepthWriteMask := False;
  164. BuildList(ARci);
  165. DepthWriteMask := True;
  166. if (moUseStencil in MirrorOptions) then
  167. begin
  168. SetStencilFunc(cfEqual, 1, 1);
  169. SetStencilOp(soKeep, soKeep, soKeep);
  170. end;
  171. if (moClearZBuffer in MirrorOptions) then
  172. ClearZBufferArea(CurrentBuffer);
  173. if not (moOpaque in MirrorOptions) then
  174. SetGLColorWriting(True);
  175. end;
  176. ARci.PipelineTransformation.Push;
  177. ARci.PipelineTransformation.SetModelMatrix(IdentityHmgMatrix);
  178. Disable(stCullFace);
  179. Enable(stNormalize);
  180. if moMirrorPlaneClip in MirrorOptions then
  181. begin
  182. gl.Enable(GL_CLIP_PLANE0);
  183. SetPlane(clipPlane, PlaneMake(AffineVectorMake(AbsolutePosition),
  184. VectorNegate(AffineVectorMake(AbsoluteDirection))));
  185. gl.ClipPlane(GL_CLIP_PLANE0, @clipPlane);
  186. end;
  187. // Mirror lights
  188. refMat := MakeReflectionMatrix(
  189. AffineVectorMake(AbsolutePosition),
  190. AffineVectorMake(AbsoluteDirection));
  191. curMat := MatrixMultiply(refMat, ARci.PipelineTransformation.ViewMatrix^);
  192. ARci.PipelineTransformation.SetViewMatrix(curMat);
  193. Scene.SetupLights(CurrentBuffer.LimitOf[limLights]);
  194. // mirror geometry and render master
  195. cameraPosBackup := ARci.cameraPosition;
  196. cameraDirectionBackup := ARci.cameraDirection;
  197. ARci.cameraPosition := VectorTransform(ARci.cameraPosition, refMat);
  198. ARci.cameraDirection := VectorTransform(ARci.cameraDirection, refMat);
  199. // temporary fix? (some objects don't respect culling options, or ?)
  200. CullFaceMode := cmFront;
  201. if Assigned(FOnBeginRenderingMirrors) then
  202. FOnBeginRenderingMirrors(Self);
  203. if Assigned(FMirrorObject) then
  204. begin
  205. ModelMat := IdentityHmgMatrix;
  206. if FMirrorObject.Parent <> nil then
  207. MatrixMultiply(ModelMat, FMirrorObject.Parent.AbsoluteMatrix, ModelMat);
  208. MatrixMultiply(ModelMat, FMirrorObject.LocalMatrix^, ModelMat);
  209. ARci.PipelineTransformation.SetModelMatrix(ModelMat);
  210. FMirrorObject.DoRender(ARci, ARenderSelf, FMirrorObject.Count > 0);
  211. end
  212. else
  213. begin
  214. Scene.Objects.DoRender(ARci, ARenderSelf, True);
  215. end;
  216. if Assigned(FOnEndRenderingMirrors) then
  217. FOnEndRenderingMirrors(Self);
  218. // Restore to "normal"
  219. ARci.cameraPosition := cameraPosBackup;
  220. ARci.cameraDirection := cameraDirectionBackup;
  221. ARci.GLStates.CullFaceMode := cmBack;
  222. ARci.PipelineTransformation.ReplaceFromStack;
  223. Scene.SetupLights(CurrentBuffer.LimitOf[limLights]);
  224. ARci.PipelineTransformation.Pop;
  225. if moMirrorPlaneClip in MirrorOptions then
  226. gl.Disable(GL_CLIP_PLANE0);
  227. ARci.GLStates.Disable(stStencilTest);
  228. ARci.proxySubObject := oldProxySubObject;
  229. // start rendering self
  230. if ARenderSelf then
  231. begin
  232. Material.Apply(ARci);
  233. repeat
  234. BuildList(ARci);
  235. until not Material.UnApply(ARci);
  236. end;
  237. end;
  238. if ARenderChildren then
  239. Self.RenderChildren(0, Count - 1, ARci);
  240. if Assigned(FMirrorObject) then
  241. FMirrorObject.Effects.RenderPostEffects(ARci);
  242. finally
  243. FRendering := False;
  244. end;
  245. end;
  246. procedure TGLMirror.BuildList(var ARci: TGLRenderContextInfo);
  247. var
  248. hw, hh: Single;
  249. quadric: PGLUquadricObj;
  250. begin
  251. if msRect = FShape then
  252. begin
  253. hw := FWidth * 0.5;
  254. hh := FHeight * 0.5;
  255. gl.Normal3fv(@ZVector);
  256. gl.Begin_(GL_QUADS);
  257. gl.Vertex3f(hw, hh, 0);
  258. gl.Vertex3f(-hw, hh, 0);
  259. gl.Vertex3f(-hw, -hh, 0);
  260. gl.Vertex3f(hw, -hh, 0);
  261. gl.End_;
  262. end
  263. else
  264. begin
  265. quadric := gluNewQuadric;
  266. gluDisk(Quadric, 0, FRadius, FSlices, 1); //radius. slices, loops
  267. end;
  268. end;
  269. procedure TGLMirror.ClearZBufferArea(aBuffer: TGLSceneBuffer);
  270. var
  271. worldMat: TGLMatrix;
  272. p: TAffineVector;
  273. begin
  274. with aBuffer do
  275. begin
  276. gl.PushMatrix;
  277. worldMat := Self.AbsoluteMatrix;
  278. gl.MatrixMode(GL_PROJECTION);
  279. gl.PushMatrix;
  280. gl.LoadIdentity;
  281. gl.Ortho(0, Width, 0, Height, 1, -1);
  282. gl.MatrixMode(GL_MODELVIEW);
  283. gl.LoadIdentity;
  284. with aBuffer.RenderingContext.GLStates do
  285. begin
  286. DepthFunc := cfAlways;
  287. SetGLColorWriting(False);
  288. end;
  289. gl.Begin_(GL_QUADS);
  290. p := WorldToScreen(VectorTransform(AffineVectorMake(Self.Width * 0.5,
  291. Self.Height * 0.5, 0), worldMat));
  292. gl.Vertex3f(p.X, p.Y, 0.999);
  293. p := WorldToScreen(VectorTransform(AffineVectorMake(-Self.Width * 0.5,
  294. Self.Height * 0.5, 0), worldMat));
  295. gl.Vertex3f(p.X, p.Y, 0.999);
  296. p := WorldToScreen(VectorTransform(AffineVectorMake(-Self.Width * 0.5,
  297. -Self.Height * 0.5, 0), worldMat));
  298. gl.Vertex3f(p.X, p.Y, 0.999);
  299. p := WorldToScreen(VectorTransform(AffineVectorMake(Self.Width * 0.5,
  300. -Self.Height * 0.5, 0), worldMat));
  301. gl.Vertex3f(p.X, p.Y, 0.999);
  302. gl.End_;
  303. with aBuffer.RenderingContext.GLStates do
  304. begin
  305. DepthFunc := cfLess;
  306. SetGLColorWriting(True);
  307. end;
  308. gl.MatrixMode(GL_PROJECTION);
  309. gl.PopMatrix;
  310. gl.MatrixMode(GL_MODELVIEW);
  311. gl.PopMatrix;
  312. end;
  313. end;
  314. procedure TGLMirror.Notification(AComponent: TComponent; Operation: TOperation);
  315. begin
  316. if (Operation = opRemove) and (AComponent = FMirrorObject) then
  317. MirrorObject := nil;
  318. inherited;
  319. end;
  320. procedure TGLMirror.SetMirrorObject(const val: TGLBaseSceneObject);
  321. begin
  322. if FMirrorObject <> val then
  323. begin
  324. if Assigned(FMirrorObject) then
  325. FMirrorObject.RemoveFreeNotification(Self);
  326. FMirrorObject := val;
  327. if Assigned(FMirrorObject) then
  328. FMirrorObject.FreeNotification(Self);
  329. NotifyChange(Self);
  330. end;
  331. end;
  332. procedure TGLMirror.SetWidth(AValue: Single);
  333. begin
  334. if AValue <> FWidth then
  335. begin
  336. FWidth := AValue;
  337. NotifyChange(Self);
  338. end;
  339. end;
  340. procedure TGLMirror.SetHeight(AValue: Single);
  341. begin
  342. if AValue <> FHeight then
  343. begin
  344. FHeight := AValue;
  345. NotifyChange(Self);
  346. end;
  347. end;
  348. procedure TGLMirror.Assign(Source: TPersistent);
  349. begin
  350. if Assigned(Source) and (Source is TGLMirror) then
  351. begin
  352. FWidth := TGLMirror(Source).FWidth;
  353. FHeight := TGLMirror(Source).FHeight;
  354. FMirrorOptions := TGLMirror(Source).FMirrorOptions;
  355. MirrorObject := TGLMirror(Source).MirrorObject;
  356. end;
  357. inherited Assign(Source);
  358. end;
  359. function TGLMirror.AxisAlignedDimensionsUnscaled: TGLVector;
  360. begin
  361. Result := VectorMake(0.5 * Abs(FWidth),
  362. 0.5 * Abs(FHeight), 0);
  363. end;
  364. procedure TGLMirror.SetMirrorOptions(const val: TGLMirrorOptions);
  365. begin
  366. if FMirrorOptions <> val then
  367. begin
  368. FMirrorOptions := val;
  369. NotifyChange(Self);
  370. end;
  371. end;
  372. //ORL add-ons
  373. procedure TGLMirror.SetRadius(const aValue: Single);
  374. begin
  375. if aValue <> FRadius then
  376. begin
  377. FRadius := aValue;
  378. StructureChanged;
  379. end;
  380. end;
  381. function TGLMirror.GetRadius: single;
  382. begin
  383. result := FRadius;
  384. end;
  385. procedure TGLMirror.SetSlices(const aValue: Integer);
  386. begin
  387. if aValue <> FSlices then
  388. begin
  389. if aValue > 2 then
  390. FSlices := aValue;
  391. StructureChanged;
  392. end
  393. else
  394. begin
  395. end;
  396. end;
  397. function TGLMirror.GetSlices: Integer;
  398. begin
  399. result := FSlices;
  400. end;
  401. procedure TGLMirror.SetShape(aValue: TMirrorShapes);
  402. begin
  403. if aValue <> FShape then
  404. begin
  405. FShape := aValue;
  406. StructureChanged;
  407. end;
  408. end;
  409. //-------------------------------------------------------------
  410. initialization
  411. //-------------------------------------------------------------
  412. RegisterClasses([TGLMirror]);
  413. end.