GLShadowVolume.pas 30 KB

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