GLS.ShadowVolume.pas 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.ShadowVolume;
  5. (*
  6. Implements basic shadow volumes support.
  7. Be aware that only objects that support silhouette determination have a chance
  8. to cast correct shadows. Transparent/blended/shader objects among the receivers
  9. or the casters will be rendered incorrectly.
  10. *)
  11. interface
  12. {$I Stage.Defines.inc}
  13. uses
  14. Winapi.OpenGL,
  15. System.Classes,
  16. System.SysUtils,
  17. Stage.OpenGLTokens,
  18. GLS.Scene,
  19. Stage.VectorGeometry,
  20. GLS.Context,
  21. GLS.Silhouette,
  22. GLS.PersistentClasses,
  23. GLS.Coordinates,
  24. Stage.PipelineTransform,
  25. GLS.GeometryBB,
  26. GLS.Color,
  27. GLS.Selection,
  28. GLS.RenderContextInfo,
  29. GLS.VectorLists,
  30. GLS.State,
  31. Stage.VectorTypes,
  32. Stage.Logger;
  33. type
  34. TGLShadowVolume = class;
  35. (*
  36. Determines when a shadow volume should generate a cap at the beginning and
  37. end of the volume. This is ONLY necessary when there's a chance that the
  38. camera could end up inside the shadow _or_ between the light source and
  39. the camera. If those two situations can't occur then not using capping is
  40. the best option.
  41. Note that if you use the capping, you must either set the depth of view of
  42. your camera to something very large (f.i. 1e9), or you could use the infinite
  43. mode (csInfinitePerspective) of your camera.
  44. svcDefault : Default behaviour
  45. svcAlways : Always generates caps
  46. svcNever : Never generates caps
  47. *)
  48. TGLShadowVolumeCapping = (svcDefault, svcAlways, svcNever);
  49. (*
  50. Determines when a caster should actually produce a shadow;
  51. scmAlways : Caster always produces a shadow, ignoring visibility
  52. scmVisible : Caster casts shadow if the object has visible=true
  53. scmRecursivelyVisible : Caster casts shadow if ancestors up the hierarchy
  54. all have visible=true
  55. scmParentVisible : Caster produces shadow if parent has visible=true
  56. scmParentRecursivelyVisible : Caster casts shadow if ancestors up the hierarchy
  57. all have visible=true, starting from the parent (ignoring own visible setting)
  58. *)
  59. TGLShadowCastingMode = (scmAlways, scmVisible, scmRecursivelyVisible,
  60. scmParentVisible, scmParentRecursivelyVisible);
  61. // Specifies an individual shadow caster. Can be a light or an opaque object.
  62. TGLShadowVolumeCaster = class(TCollectionItem)
  63. private
  64. FCaster: TGLBaseSceneObject;
  65. FEffectiveRadius: Single;
  66. FCapping: TGLShadowVolumeCapping;
  67. FCastingMode: TGLShadowCastingMode;
  68. protected
  69. procedure SetCaster(const val: TGLBaseSceneObject);
  70. function GetGLShadowVolume: TGLShadowVolume;
  71. procedure RemoveNotification(aComponent: TComponent);
  72. function GetDisplayName: string; override;
  73. public
  74. constructor Create(ACollection: TCollection); override;
  75. destructor Destroy; override;
  76. procedure Assign(Source: TPersistent); override;
  77. // Shadow casting object. Can be an opaque object or a lightsource.
  78. property Caster: TGLBaseSceneObject read FCaster write SetCaster;
  79. property GLShadowVolume: TGLShadowVolume read GetGLShadowVolume;
  80. published
  81. (*
  82. Radius beyond which the caster can be ignored.
  83. Zero (default value) means the caster can never be ignored.
  84. *)
  85. property EffectiveRadius: Single read FEffectiveRadius write FEffectiveRadius;
  86. (*
  87. Specifies if the shadow volume should be capped.
  88. Capping helps solve shadowing artefacts, at the cost of performance.
  89. *)
  90. property Capping: TGLShadowVolumeCapping read FCapping write FCapping default svcDefault;
  91. (*
  92. Determines when an object should cast a shadow or not. Typically, objects
  93. should only cast shadows when recursively visible. But if you're using
  94. dummy shadow casters which are less complex than their parent objects,
  95. you should use scmParentRecursivelyVisible.
  96. *)
  97. property CastingMode: TGLShadowCastingMode read FCastingMode write
  98. FCastingMode default scmRecursivelyVisible;
  99. end;
  100. // Specifies an individual shadow casting occluder.
  101. TGLShadowVolumeOccluder = class(TGLShadowVolumeCaster)
  102. published
  103. property Caster;
  104. end;
  105. // Specifies an individual shadow casting light.
  106. TGLShadowVolumeLight = class(TGLShadowVolumeCaster)
  107. private
  108. FSilhouettes: TGLPersistentObjectList;
  109. protected
  110. function GetLightSource: TGLLightSource;
  111. procedure SetLightSource(const ls: TGLLightSource);
  112. function GetCachedSilhouette(AIndex: Integer): TGLSilhouette; inline;
  113. procedure StoreCachedSilhouette(AIndex: Integer; ASil: TGLSilhouette);
  114. {Compute and setup scissor clipping rect for the light.
  115. Returns true if a scissor rect was setup }
  116. function SetupScissorRect(worldAABB: PAABB; var rci: TGLRenderContextInfo): Boolean;
  117. public
  118. constructor Create(ACollection: TCollection); override;
  119. destructor Destroy; override;
  120. procedure FlushSilhouetteCache;
  121. published
  122. // Shadow casting lightsource.
  123. property LightSource: TGLLightSource read GetLightSource write SetLightSource;
  124. end;
  125. // Collection of TGLShadowVolumeCaster.
  126. TGLShadowVolumeCasters = class(TOwnedCollection)
  127. protected
  128. function GetItems(index: Integer): TGLShadowVolumeCaster;
  129. procedure RemoveNotification(aComponent: TComponent);
  130. public
  131. function AddCaster(obj: TGLBaseSceneObject; effectiveRadius: Single = 0;
  132. CastingMode: TGLShadowCastingMode = scmRecursivelyVisible):
  133. TGLShadowVolumeCaster;
  134. procedure RemoveCaster(obj: TGLBaseSceneObject);
  135. function IndexOfCaster(obj: TGLBaseSceneObject): Integer;
  136. property Items[index: Integer]: TGLShadowVolumeCaster read GetItems; default;
  137. end;
  138. (*
  139. Shadow volume rendering options/optimizations.
  140. svoShowVolumes : make the shadow volumes visible
  141. svoDesignVisible : the shadow are visible at design-time
  142. svoCacheSilhouettes : cache shadow volume silhouettes, beneficial when
  143. some objects are static relatively to their light(s)
  144. svoScissorClips : use scissor clipping per light, beneficial when
  145. lights are attenuated and don't illuminate the whole scene
  146. svoWorldScissorClip : use scissor clipping for the world, beneficial
  147. when shadow receivers don't cover the whole viewer surface
  148. *)
  149. TGLShadowVolumeOption = (svoShowVolumes, svoCacheSilhouettes, svoScissorClips,
  150. svoWorldScissorClip, svoDesignVisible);
  151. TGLShadowVolumeOptions = set of TGLShadowVolumeOption;
  152. (*
  153. Shadow rendering modes.
  154. svmAccurate : will render the scene with ambient lighting only, then
  155. for each light will make a diffuse+specular pass
  156. svmDarkening : renders the scene with lighting on as usual, then darkens
  157. shadowed areas (i.e. inaccurate lighting, but will "shadow" objects
  158. that don't honour to diffuse or specular lighting)
  159. svmOff : no shadowing will take place
  160. *)
  161. TGLShadowVolumeMode = (svmAccurate, svmDarkening, svmOff);
  162. (*
  163. Simple shadow volumes.
  164. Shadow receiving objects are the ShadowVolume's children, shadow casters
  165. (opaque objects or lights) must be explicitly specified in the Casters
  166. collection.
  167. Shadow volumes require that the buffer allows stencil buffers,
  168. GLSceneViewer.Buffer.ContextOptions contain roStencinBuffer. Without stencil
  169. buffers, shadow volumes will not work properly.
  170. Another issue to look out for is the fact that shadow volume capping requires
  171. that the camera depth of view is either very high (fi 1e9) or that the
  172. camera style is csInfinitePerspective.
  173. *)
  174. TGLShadowVolume = class(TGLImmaterialSceneObject)
  175. private
  176. FActive: Boolean;
  177. FRendering: Boolean;
  178. FLights: TGLShadowVolumeCasters;
  179. FOccluders: TGLShadowVolumeCasters;
  180. FCapping: TGLShadowVolumeCapping;
  181. FOptions: TGLShadowVolumeOptions;
  182. FMode: TGLShadowVolumeMode;
  183. FDarkeningColor: TGLColor;
  184. protected
  185. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  186. procedure SetActive(const val: Boolean);
  187. procedure SetLights(const val: TGLShadowVolumeCasters);
  188. procedure SetOccluders(const val: TGLShadowVolumeCasters);
  189. procedure SetOptions(const val: TGLShadowVolumeOptions);
  190. procedure SetMode(const val: TGLShadowVolumeMode);
  191. procedure SetDarkeningColor(const val: TGLColor);
  192. public
  193. constructor Create(AOwner: TComponent); override;
  194. destructor Destroy; override;
  195. procedure DoRender(var ARci: TGLRenderContextInfo;
  196. ARenderSelf, ARenderChildren: Boolean); override;
  197. procedure Assign(Source: TPersistent); override;
  198. procedure FlushSilhouetteCache;
  199. published
  200. {Determines if shadow volume rendering is active.
  201. When set to false, children will be rendered without any shadowing
  202. or multipass lighting. }
  203. property Active: Boolean read FActive write SetActive default True;
  204. // Lights that cast shadow volumes.
  205. property Lights: TGLShadowVolumeCasters read FLights write SetLights;
  206. // Occluders that cast shadow volumes.
  207. property Occluders: TGLShadowVolumeCasters read FOccluders write SetOccluders;
  208. {Specifies if the shadow volume should be capped.
  209. Capping helps solve shadowing artefacts, at the cost of performance. }
  210. property Capping: TGLShadowVolumeCapping read FCapping write FCapping default
  211. svcAlways;
  212. // Shadow volume rendering options.
  213. property Options: TGLShadowVolumeOptions read FOptions write SetOptions
  214. default [svoCacheSilhouettes, svoScissorClips];
  215. // Shadow rendering mode.
  216. property Mode: TGLShadowVolumeMode read FMode write SetMode default svmAccurate;
  217. // Darkening color used in svmDarkening mode.
  218. property DarkeningColor: TGLColor read FDarkeningColor write SetDarkeningColor;
  219. end;
  220. //-------------------------------------------------------------
  221. implementation
  222. //-------------------------------------------------------------
  223. // ------------------
  224. // ------------------ TGLShadowVolumeCaster ------------------
  225. // ------------------
  226. constructor TGLShadowVolumeCaster.Create(ACollection: TCollection);
  227. begin
  228. inherited Create(ACollection);
  229. FCapping := svcDefault;
  230. FCastingMode := scmRecursivelyVisible;
  231. end;
  232. type
  233. // Required for Delphi 5 support ?
  234. THackOwnedCollection = class(TOwnedCollection);
  235. function TGLShadowVolumeCaster.GetGLShadowVolume: TGLShadowVolume;
  236. begin
  237. Result := TGLShadowVolume(THackOwnedCollection(Collection).GetOwner);
  238. end;
  239. destructor TGLShadowVolumeCaster.Destroy;
  240. begin
  241. if Assigned(FCaster) then
  242. FCaster.RemoveFreeNotification(GLShadowVolume);
  243. inherited;
  244. end;
  245. procedure TGLShadowVolumeCaster.Assign(Source: TPersistent);
  246. begin
  247. if Source is TGLShadowVolumeCaster then
  248. begin
  249. FCaster := TGLShadowVolumeCaster(Source).FCaster;
  250. FEffectiveRadius := TGLShadowVolumeCaster(Source).FEffectiveRadius;
  251. FCapping := TGLShadowVolumeCaster(Source).FCapping;
  252. GetGLShadowVolume.StructureChanged;
  253. end;
  254. inherited;
  255. end;
  256. procedure TGLShadowVolumeCaster.SetCaster(const val: TGLBaseSceneObject);
  257. begin
  258. if FCaster <> val then
  259. begin
  260. if FCaster <> nil then
  261. FCaster.RemoveFreeNotification(GLShadowVolume);
  262. FCaster := val;
  263. if FCaster <> nil then
  264. FCaster.FreeNotification(GLShadowVolume);
  265. GetGLShadowVolume.StructureChanged;
  266. end;
  267. end;
  268. procedure TGLShadowVolumeCaster.RemoveNotification(aComponent: TComponent);
  269. begin
  270. if aComponent = FCaster then
  271. begin
  272. // No point in keeping the TGLShadowVolumeCaster once the FCaster has been
  273. // destroyed.
  274. FCaster := nil;
  275. Free;
  276. end;
  277. end;
  278. function TGLShadowVolumeCaster.GetDisplayName: string;
  279. begin
  280. if Assigned(FCaster) then
  281. begin
  282. if FCaster is TGLLightSource then
  283. Result := '[Light]'
  284. else
  285. Result := '[Object]';
  286. Result := Result + ' ' + FCaster.Name;
  287. if EffectiveRadius > 0 then
  288. Result := Result + Format(' (%.1f)', [EffectiveRadius]);
  289. end
  290. else
  291. Result := 'nil';
  292. end;
  293. // ------------------
  294. // ------------------ TGLShadowVolumeLight ------------------
  295. // ------------------
  296. constructor TGLShadowVolumeLight.Create(ACollection: TCollection);
  297. begin
  298. inherited Create(ACollection);
  299. FSilhouettes := TGLPersistentObjectList.Create;
  300. end;
  301. destructor TGLShadowVolumeLight.Destroy;
  302. begin
  303. FlushSilhouetteCache;
  304. FSilhouettes.Free;
  305. inherited;
  306. end;
  307. procedure TGLShadowVolumeLight.FlushSilhouetteCache;
  308. begin
  309. FSilhouettes.Clean;
  310. end;
  311. function TGLShadowVolumeLight.GetLightSource: TGLLightSource;
  312. begin
  313. Result := TGLLightSource(Caster);
  314. end;
  315. procedure TGLShadowVolumeLight.SetLightSource(const ls: TGLLightSource);
  316. begin
  317. SetCaster(ls);
  318. end;
  319. function TGLShadowVolumeLight.GetCachedSilhouette(AIndex: Integer):
  320. TGLSilhouette;
  321. begin
  322. if AIndex < FSilhouettes.Count then
  323. Result := TGLSilhouette(FSilhouettes[AIndex])
  324. else
  325. Result := nil;
  326. end;
  327. procedure TGLShadowVolumeLight.StoreCachedSilhouette(AIndex: Integer; ASil:
  328. TGLSilhouette);
  329. begin
  330. while AIndex >= FSilhouettes.Count do
  331. FSilhouettes.Add(nil);
  332. if ASil <> FSilhouettes[AIndex] then
  333. begin
  334. if assigned(FSilhouettes[AIndex]) then
  335. FSilhouettes[AIndex].Free;
  336. FSilhouettes[AIndex] := ASil;
  337. end;
  338. end;
  339. function TGLShadowVolumeLight.SetupScissorRect(worldAABB: PAABB; var rci:
  340. TGLRenderContextInfo): Boolean;
  341. var
  342. mvp: TGLMatrix;
  343. ls: TGLLightSource;
  344. aabb: TAABB;
  345. clipRect: TGClipRect;
  346. begin
  347. ls := LightSource;
  348. if (EffectiveRadius <= 0) or (not ls.Attenuated) then
  349. begin
  350. // non attenuated lights can't be clipped
  351. if not Assigned(worldAABB) then
  352. begin
  353. Result := False;
  354. Exit;
  355. end
  356. else
  357. aabb := worldAABB^;
  358. end
  359. else
  360. begin
  361. aabb := BSphereToAABB(ls.AbsolutePosition, EffectiveRadius);
  362. if Assigned(worldAABB) then
  363. aabb := AABBIntersection(aabb, worldAABB^);
  364. end;
  365. if PointInAABB(rci.cameraPosition, aabb) then
  366. begin
  367. // camera inside light volume radius, can't clip
  368. Result := False;
  369. Exit;
  370. end;
  371. // Calculate the window-space bounds of the light's bounding box.
  372. mvp := rci.PipelineTransformation.ViewProjectionMatrix^;
  373. clipRect := AABBToClipRect(aabb, mvp, rci.viewPortSize.cx,
  374. rci.viewPortSize.cy);
  375. if (clipRect.Right < 0) or (clipRect.Left > rci.viewPortSize.cx)
  376. or (clipRect.Top < 0) or (clipRect.Bottom > rci.viewPortSize.cy) then
  377. begin
  378. Result := False;
  379. Exit;
  380. end;
  381. with clipRect do
  382. gl.Scissor(Round(Left), Round(Top), Round(Right - Left), Round(Bottom -
  383. Top));
  384. Result := True;
  385. end;
  386. // ------------------
  387. // ------------------ TGLShadowVolumeCasters ------------------
  388. // ------------------
  389. procedure TGLShadowVolumeCasters.RemoveNotification(aComponent: TComponent);
  390. var
  391. i: Integer;
  392. begin
  393. for i := Count - 1 downto 0 do
  394. Items[i].RemoveNotification(aComponent);
  395. end;
  396. function TGLShadowVolumeCasters.GetItems(index: Integer): TGLShadowVolumeCaster;
  397. begin
  398. Result := TGLShadowVolumeCaster(inherited Items[index]);
  399. end;
  400. function TGLShadowVolumeCasters.AddCaster(obj: TGLBaseSceneObject;
  401. effectiveRadius: Single = 0;
  402. CastingMode: TGLShadowCastingMode = scmRecursivelyVisible):
  403. TGLShadowVolumeCaster;
  404. var
  405. newCaster: TGLShadowVolumeCaster;
  406. begin
  407. newCaster := TGLShadowVolumeCaster(Add);
  408. newCaster.Caster := obj;
  409. newCaster.EffectiveRadius := effectiveRadius;
  410. newCaster.CastingMode := CastingMode;
  411. result := newCaster;
  412. end;
  413. procedure TGLShadowVolumeCasters.RemoveCaster(obj: TGLBaseSceneObject);
  414. var
  415. i: Integer;
  416. begin
  417. i := IndexOfCaster(obj);
  418. if i >= 0 then
  419. Delete(i);
  420. end;
  421. function TGLShadowVolumeCasters.IndexOfCaster(obj: TGLBaseSceneObject): Integer;
  422. var
  423. i: Integer;
  424. begin
  425. for i := 0 to Count - 1 do
  426. begin
  427. if Items[i].Caster = obj then
  428. begin
  429. Result := i;
  430. Exit;
  431. end;
  432. end;
  433. Result := -1;
  434. end;
  435. // ------------------
  436. // ------------------ TGLShadowVolume ------------------
  437. // ------------------
  438. constructor TGLShadowVolume.Create(AOwner: Tcomponent);
  439. begin
  440. inherited Create(AOwner);
  441. ObjectStyle := ObjectStyle - [osDirectDraw] + [osNoVisibilityCulling];
  442. FActive := True;
  443. FLights := TGLShadowVolumeCasters.Create(self, TGLShadowVolumeLight);
  444. FOccluders := TGLShadowVolumeCasters.Create(self, TGLShadowVolumeOccluder);
  445. FCapping := svcAlways;
  446. FMode := svmAccurate;
  447. FOptions := [svoCacheSilhouettes, svoScissorClips];
  448. FDarkeningColor := TGLColor.CreateInitialized(Self, VectorMake(0, 0, 0, 0.5));
  449. end;
  450. destructor TGLShadowVolume.Destroy;
  451. begin
  452. inherited;
  453. FDarkeningColor.Free;
  454. FLights.Free;
  455. FOccluders.Free;
  456. end;
  457. procedure TGLShadowVolume.Notification(AComponent: TComponent; Operation:
  458. TOperation);
  459. begin
  460. if Operation = opRemove then
  461. begin
  462. FLights.RemoveNotification(AComponent);
  463. FOccluders.RemoveNotification(AComponent);
  464. end;
  465. inherited;
  466. end;
  467. procedure TGLShadowVolume.Assign(Source: TPersistent);
  468. begin
  469. if Assigned(Source) and (Source is TGLShadowVolume) then
  470. begin
  471. FLights.Assign(TGLShadowVolume(Source).Lights);
  472. FOccluders.Assign(TGLShadowVolume(Source).Occluders);
  473. FCapping := TGLShadowVolume(Source).FCapping;
  474. StructureChanged;
  475. end;
  476. inherited Assign(Source);
  477. end;
  478. procedure TGLShadowVolume.FlushSilhouetteCache;
  479. var
  480. i: Integer;
  481. begin
  482. for i := 0 to Lights.Count - 1 do
  483. (Lights[i] as TGLShadowVolumeLight).FlushSilhouetteCache;
  484. end;
  485. procedure TGLShadowVolume.SetActive(const val: Boolean);
  486. begin
  487. if FActive <> val then
  488. begin
  489. FActive := val;
  490. StructureChanged;
  491. end;
  492. end;
  493. procedure TGLShadowVolume.SetLights(const val: TGLShadowVolumeCasters);
  494. begin
  495. Assert(val.ItemClass = TGLShadowVolumeLight);
  496. FLights.Assign(val);
  497. StructureChanged;
  498. end;
  499. procedure TGLShadowVolume.SetOccluders(const val: TGLShadowVolumeCasters);
  500. begin
  501. Assert(val.ItemClass = TGLShadowVolumeOccluder);
  502. FOccluders.Assign(val);
  503. StructureChanged;
  504. end;
  505. procedure TGLShadowVolume.SetOptions(const val: TGLShadowVolumeOptions);
  506. begin
  507. if FOptions <> val then
  508. begin
  509. FOptions := val;
  510. if not (svoCacheSilhouettes in FOptions) then
  511. FlushSilhouetteCache;
  512. StructureChanged;
  513. end;
  514. end;
  515. procedure TGLShadowVolume.SetMode(const val: TGLShadowVolumeMode);
  516. begin
  517. if FMode <> val then
  518. begin
  519. FMode := val;
  520. StructureChanged;
  521. end;
  522. end;
  523. procedure TGLShadowVolume.SetDarkeningColor(const val: TGLColor);
  524. begin
  525. FDarkeningColor.Assign(val);
  526. end;
  527. procedure TGLShadowVolume.DoRender(var ARci: TGLRenderContextInfo;
  528. ARenderSelf, ARenderChildren: Boolean);
  529. // Function that determines if an object is "recursively visible". It halts when
  530. // * it finds an invisible ancestor (=> invisible)
  531. // * it finds the root (=> visible)
  532. // * it finds the shadow volume as an ancestor (=> visible)
  533. //
  534. // This does _not_ mean that the object is actually visible on the screen
  535. function DirectHierarchicalVisibility(obj: TGLBaseSceneObject; self: TGLShadowVolume): boolean; inline;
  536. var
  537. p: TGLBaseSceneObject;
  538. begin
  539. if not Assigned(obj) then
  540. begin
  541. Result := True;
  542. exit;
  543. end;
  544. if not obj.Visible then
  545. begin
  546. Result := False;
  547. Exit;
  548. end;
  549. p := obj.Parent;
  550. while Assigned(p) and (p <> obj) and (p <> Self) do
  551. begin
  552. if not p.Visible then
  553. begin
  554. Result := False;
  555. Exit;
  556. end;
  557. p := p.Parent;
  558. end;
  559. Result := True;
  560. end;
  561. var
  562. i, k: Integer;
  563. lightSource: TGLLightSource;
  564. lightCaster: TGLShadowVolumeLight;
  565. sil: TGLSilhouette;
  566. lightID: Cardinal;
  567. obj: TGLBaseSceneObject;
  568. caster: TGLShadowVolumeCaster;
  569. opaques, opaqueCapping: TList;
  570. silParams: TGLSilhouetteParameters;
  571. worldAABB: TAABB;
  572. pWorldAABB: PAABB;
  573. PM: TGLMatrix;
  574. begin
  575. if not Active then
  576. begin
  577. inherited;
  578. Exit;
  579. end;
  580. if FRendering then
  581. Exit;
  582. if not (ARenderSelf or ARenderChildren) then
  583. Exit;
  584. ClearStructureChanged;
  585. if ((csDesigning in ComponentState) and not (svoDesignVisible in Options))
  586. or (Mode = svmOff)
  587. or (ARci.drawState = dsPicking) then
  588. begin
  589. inherited;
  590. Exit;
  591. end;
  592. if svoWorldScissorClip in Options then
  593. begin
  594. // compute shadow receiving world AABB in absolute coordinates
  595. worldAABB := Self.AxisAlignedBoundingBox;
  596. AABBTransform(worldAABB, AbsoluteMatrix);
  597. pWorldAABB := @worldAABB;
  598. end
  599. else
  600. pWorldAABB := nil;
  601. opaques := TList.Create;
  602. opaqueCapping := TList.Create;
  603. FRendering := True;
  604. try
  605. // collect visible casters
  606. for i := 0 to Occluders.Count - 1 do
  607. begin
  608. caster := Occluders[i];
  609. obj := caster.Caster;
  610. if Assigned(obj)
  611. and
  612. // Determine when to render this object or not
  613. (
  614. (Caster.CastingMode = scmAlways) or
  615. ((Caster.CastingMode = scmVisible) and obj.Visible) or
  616. ((Caster.CastingMode = scmRecursivelyVisible) and
  617. DirectHierarchicalVisibility(obj, Self)) or
  618. ((Caster.CastingMode = scmParentRecursivelyVisible) and
  619. DirectHierarchicalVisibility(obj.Parent, Self)) or
  620. ((Caster.CastingMode = scmParentVisible) and (not Assigned(obj.Parent)
  621. or
  622. obj.Parent.Visible))
  623. )
  624. and ((caster.EffectiveRadius <= 0)
  625. or (obj.DistanceTo(ARci.cameraPosition) < caster.EffectiveRadius)) then
  626. begin
  627. opaques.Add(obj);
  628. opaqueCapping.Add(Pointer(Cardinal(ord((caster.Capping = svcAlways)
  629. or ((caster.Capping = svcDefault)
  630. and (Capping = svcAlways))))));
  631. end
  632. else
  633. begin
  634. opaques.Add(nil);
  635. opaqueCapping.Add(nil);
  636. end;
  637. end;
  638. // render the shadow volumes
  639. with ARci.GLStates do
  640. begin
  641. if Mode = svmAccurate then
  642. begin
  643. // first turn off all the shadow casting lights diffuse and specular
  644. for i := 0 to Lights.Count - 1 do
  645. begin
  646. lightCaster := TGLShadowVolumeLight(Lights[i]);
  647. lightSource := lightCaster.LightSource;
  648. if Assigned(lightSource) and (lightSource.Shining) then
  649. begin
  650. lightID := lightSource.LightID;
  651. LightDiffuse[lightID] := NullHmgVector;
  652. LightSpecular[lightID] := NullHmgVector;
  653. end;
  654. end;
  655. end;
  656. // render shadow receivers with ambient lighting
  657. // DanB - not sure why this doesn't render properly with these statements
  658. // where they were originally (after the RenderChildren call).
  659. Self.RenderChildren(0, Count - 1, ARci);
  660. ARci.ignoreBlendingRequests := True;
  661. ARci.ignoreDepthRequests := True;
  662. DepthWriteMask := False;
  663. Enable(stDepthTest);
  664. SetBlendFunc(bfSrcAlpha, bfOne);
  665. Disable(stAlphaTest);
  666. Enable(stStencilTest);
  667. // Disable all client states
  668. if gl.ARB_vertex_buffer_object then
  669. begin
  670. VertexArrayBinding := 0;
  671. ArrayBufferBinding := 0;
  672. ElementBufferBinding := 0;
  673. end;
  674. // turn off *all* lights
  675. for i := 0 to TGLScene(ARci.scene).Lights.Count - 1 do
  676. begin
  677. lightSource := (TGLScene(ARci.scene).Lights.Items[i]) as TGLLightSource;
  678. if Assigned(lightSource) and lightSource.Shining then
  679. LightEnabling[lightSource.LightID] := False;
  680. end;
  681. gl.LightModelfv(GL_LIGHT_MODEL_AMBIENT, @NullHmgPoint);
  682. ARci.PipelineTransformation.Push;
  683. // render contribution of all shadow casting lights
  684. for i := 0 to Lights.Count - 1 do
  685. begin
  686. lightCaster := TGLShadowVolumeLight(lights[i]);
  687. lightSource := lightCaster.LightSource;
  688. if (not Assigned(lightSource)) or (not lightSource.Shining) then
  689. Continue;
  690. lightID := lightSource.LightID;
  691. SetVector(silParams.LightDirection,
  692. lightSource.SpotDirection.DirectVector);
  693. case lightSource.LightStyle of
  694. lsParallel: silParams.Style := ssParallel
  695. else
  696. silParams.Style := ssOmni;
  697. end;
  698. silParams.CappingRequired := True;
  699. if Assigned(pWorldAABB) or (svoScissorClips in Options) then
  700. begin
  701. if lightCaster.SetupScissorRect(pWorldAABB, ARci) then
  702. Enable(stScissorTest)
  703. else
  704. Disable(stScissorTest);
  705. end;
  706. // clear the stencil and prepare for shadow volume pass
  707. gl.Clear(GL_STENCIL_BUFFER_BIT);
  708. SetStencilFunc(cfAlways, 0, 255);
  709. DepthFunc := cfLess;
  710. if svoShowVolumes in Options then
  711. begin
  712. gl.Color3f(0.05 * i, 0.1, 0);
  713. Enable(stBlend);
  714. end
  715. else
  716. begin
  717. SetColorWriting(False);
  718. Disable(stBlend);
  719. end;
  720. Enable(stCullFace);
  721. Disable(stLighting);
  722. gl.EnableClientState(GL_VERTEX_ARRAY);
  723. SetPolygonOffset(1, 1);
  724. // for all opaque shadow casters
  725. for k := 0 to opaques.Count - 1 do
  726. begin
  727. obj := TGLBaseSceneObject(opaques[k]);
  728. if obj = nil then
  729. Continue;
  730. SetVector(silParams.SeenFrom, obj.AbsoluteToLocal(lightSource.AbsolutePosition));
  731. sil := lightCaster.GetCachedSilhouette(k);
  732. if (not Assigned(sil)) or (not CompareMem(@sil.Parameters, @silParams,
  733. SizeOf(silParams))) then
  734. begin
  735. sil := obj.GenerateSilhouette(silParams);
  736. sil.Parameters := silParams;
  737. // extrude vertices to infinity
  738. sil.ExtrudeVerticesToInfinity(silParams.SeenFrom);
  739. end;
  740. if Assigned(sil) then
  741. try
  742. // render the silhouette
  743. ARci.PipelineTransformation.SetModelMatrix(obj.AbsoluteMatrix);
  744. gl.VertexPointer(4, GL_FLOAT, 0, sil.Vertices.List);
  745. if Boolean(Cardinal(opaqueCapping[k])) then
  746. begin
  747. // z-fail
  748. if gl.EXT_compiled_vertex_array then
  749. gl.LockArrays(0, sil.Vertices.Count);
  750. CullFaceMode := cmFront;
  751. SetStencilOp(soKeep, soIncr, soKeep);
  752. with sil do
  753. begin
  754. gl.DrawElements(GL_QUADS, Indices.Count, GL_UNSIGNED_INT,
  755. Indices.List);
  756. Enable(stPolygonOffsetFill);
  757. gl.DrawElements(GL_TRIANGLES, CapIndices.Count,
  758. GL_UNSIGNED_INT,
  759. CapIndices.List);
  760. Disable(stPolygonOffsetFill);
  761. end;
  762. CullFaceMode := cmBack;
  763. SetStencilOp(soKeep, soDecr, soKeep);
  764. with sil do
  765. begin
  766. gl.DrawElements(GL_QUADS, Indices.Count, GL_UNSIGNED_INT,
  767. Indices.List);
  768. Enable(stPolygonOffsetFill);
  769. gl.DrawElements(GL_TRIANGLES, CapIndices.Count,
  770. GL_UNSIGNED_INT,
  771. CapIndices.List);
  772. Disable(stPolygonOffsetFill);
  773. end;
  774. if gl.EXT_compiled_vertex_array then
  775. gl.UnlockArrays;
  776. end
  777. else
  778. begin
  779. // z-pass
  780. CullFaceMode := cmBack;
  781. SetStencilOp(soKeep, soKeep, soIncr);
  782. gl.DrawElements(GL_QUADS, sil.Indices.Count, GL_UNSIGNED_INT,
  783. sil.Indices.List);
  784. CullFaceMode := cmFront;
  785. SetStencilOp(soKeep, soKeep, soDecr);
  786. gl.DrawElements(GL_QUADS, sil.Indices.Count, GL_UNSIGNED_INT,
  787. sil.Indices.List);
  788. end;
  789. finally
  790. if (svoCacheSilhouettes in Options) and (not (osDirectDraw in
  791. ObjectStyle)) then
  792. lightCaster.StoreCachedSilhouette(k, sil)
  793. else
  794. sil.Free;
  795. end;
  796. end;
  797. gl.DisableClientState(GL_VERTEX_ARRAY);
  798. // re-enable light's diffuse and specular, but no ambient
  799. LightEnabling[LightID] := True;
  800. LightAmbient[LightID] := NullHmgVector;
  801. LightDiffuse[LightID] := lightSource.Diffuse.Color;
  802. LightSpecular[LightID] := lightSource.Specular.Color;
  803. SetColorWriting(True);
  804. SetStencilOp(soKeep, soKeep, soKeep);
  805. Enable(stBlend);
  806. CullFaceMode := cmBack;
  807. if Mode = svmAccurate then
  808. begin
  809. SetStencilFunc(cfEqual, 0, 255);
  810. DepthFunc := cfEqual;
  811. Self.RenderChildren(0, Count - 1, ARci);
  812. end
  813. else
  814. begin
  815. SetStencilFunc(cfNotEqual, 0, 255);
  816. DepthFunc := cfAlways;
  817. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  818. gl.PushMatrix;
  819. gl.LoadIdentity;
  820. gl.MatrixMode(GL_PROJECTION);
  821. gl.PushMatrix;
  822. PM := CreateOrthoMatrix(0, 1, 1, 0, -1, 1);
  823. gl.LoadMatrixf(PGLFloat(@PM));
  824. gl.Color4fv(FDarkeningColor.AsAddress);
  825. gl.Begin_(GL_QUADS);
  826. gl.Vertex2f(0, 0);
  827. gl.Vertex2f(0, 1);
  828. gl.Vertex2f(1, 1);
  829. gl.Vertex2f(1, 0);
  830. gl.End_;
  831. gl.PopMatrix;
  832. gl.MatrixMode(GL_MODELVIEW);
  833. gl.PopMatrix;
  834. SetBlendFunc(bfSrcAlpha, bfOne);
  835. end;
  836. // disable light, but restore its ambient component
  837. LightEnabling[lightID] := False;
  838. LightAmbient[lightID] := lightSource.Ambient.Color;
  839. end; // for i
  840. ARci.PipelineTransformation.Pop;
  841. // restore OpenGL state
  842. gl.LightModelfv(GL_LIGHT_MODEL_AMBIENT, @ARci.sceneAmbientColor);
  843. Scene.SetupLights(ARci.GLStates.MaxLights);
  844. Disable(stStencilTest);
  845. SetPolygonOffset(0, 0);
  846. ARci.ignoreBlendingRequests := False;
  847. ARci.ignoreDepthRequests := False;
  848. end; // of with
  849. finally
  850. FRendering := False;
  851. opaques.Free;
  852. opaqueCapping.Free;
  853. end;
  854. end;
  855. //-------------------------------------------------------------
  856. initialization
  857. //-------------------------------------------------------------
  858. RegisterClasses([TGLShadowVolume]);
  859. end.