renderingManager.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import { RenderingGroup } from "./renderingGroup.js";
  2. /**
  3. * This class is used by the onRenderingGroupObservable
  4. */
  5. export class RenderingGroupInfo {
  6. }
  7. /**
  8. * This is the manager responsible of all the rendering for meshes sprites and particles.
  9. * It is enable to manage the different groups as well as the different necessary sort functions.
  10. * This should not be used directly aside of the few static configurations
  11. */
  12. export class RenderingManager {
  13. /**
  14. * Gets or sets a boolean indicating that the manager will not reset between frames.
  15. * This means that if a mesh becomes invisible or transparent it will not be visible until this boolean is set to false again.
  16. * By default, the rendering manager will dispatch all active meshes per frame (moving them to the transparent, opaque or alpha testing lists).
  17. * By turning this property on, you will accelerate the rendering by keeping all these lists unchanged between frames.
  18. */
  19. get maintainStateBetweenFrames() {
  20. return this._maintainStateBetweenFrames;
  21. }
  22. set maintainStateBetweenFrames(value) {
  23. if (value === this._maintainStateBetweenFrames) {
  24. return;
  25. }
  26. this._maintainStateBetweenFrames = value;
  27. if (!this._maintainStateBetweenFrames) {
  28. this.restoreDispachedFlags();
  29. }
  30. }
  31. /**
  32. * Restore wasDispatched flags on the lists of elements to render.
  33. */
  34. restoreDispachedFlags() {
  35. for (const mesh of this._scene.meshes) {
  36. if (mesh.subMeshes) {
  37. for (const subMesh of mesh.subMeshes) {
  38. subMesh._wasDispatched = false;
  39. }
  40. }
  41. }
  42. if (this._scene.spriteManagers) {
  43. for (const spriteManager of this._scene.spriteManagers) {
  44. spriteManager._wasDispatched = false;
  45. }
  46. }
  47. for (const particleSystem of this._scene.particleSystems) {
  48. particleSystem._wasDispatched = false;
  49. }
  50. }
  51. /**
  52. * Instantiates a new rendering group for a particular scene
  53. * @param scene Defines the scene the groups belongs to
  54. */
  55. constructor(scene) {
  56. /**
  57. * @internal
  58. */
  59. this._useSceneAutoClearSetup = false;
  60. this._renderingGroups = new Array();
  61. this._autoClearDepthStencil = {};
  62. this._customOpaqueSortCompareFn = {};
  63. this._customAlphaTestSortCompareFn = {};
  64. this._customTransparentSortCompareFn = {};
  65. this._renderingGroupInfo = new RenderingGroupInfo();
  66. this._maintainStateBetweenFrames = false;
  67. this._scene = scene;
  68. for (let i = RenderingManager.MIN_RENDERINGGROUPS; i < RenderingManager.MAX_RENDERINGGROUPS; i++) {
  69. this._autoClearDepthStencil[i] = { autoClear: true, depth: true, stencil: true };
  70. }
  71. }
  72. /**
  73. * @returns the rendering group with the specified id.
  74. * @param id the id of the rendering group (0 by default)
  75. */
  76. getRenderingGroup(id) {
  77. const renderingGroupId = id || 0;
  78. this._prepareRenderingGroup(renderingGroupId);
  79. return this._renderingGroups[renderingGroupId];
  80. }
  81. _clearDepthStencilBuffer(depth = true, stencil = true) {
  82. if (this._depthStencilBufferAlreadyCleaned) {
  83. return;
  84. }
  85. this._scene.getEngine().clear(null, false, depth, stencil);
  86. this._depthStencilBufferAlreadyCleaned = true;
  87. }
  88. /**
  89. * Renders the entire managed groups. This is used by the scene or the different render targets.
  90. * @internal
  91. */
  92. render(customRenderFunction, activeMeshes, renderParticles, renderSprites) {
  93. // Update the observable context (not null as it only goes away on dispose)
  94. const info = this._renderingGroupInfo;
  95. info.scene = this._scene;
  96. info.camera = this._scene.activeCamera;
  97. // Dispatch sprites
  98. if (this._scene.spriteManagers && renderSprites) {
  99. for (let index = 0; index < this._scene.spriteManagers.length; index++) {
  100. const manager = this._scene.spriteManagers[index];
  101. this.dispatchSprites(manager);
  102. }
  103. }
  104. // Render
  105. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  106. this._depthStencilBufferAlreadyCleaned = index === RenderingManager.MIN_RENDERINGGROUPS;
  107. const renderingGroup = this._renderingGroups[index];
  108. if (!renderingGroup || renderingGroup._empty) {
  109. continue;
  110. }
  111. const renderingGroupMask = 1 << index;
  112. info.renderingGroupId = index;
  113. // Before Observable
  114. this._scene.onBeforeRenderingGroupObservable.notifyObservers(info, renderingGroupMask);
  115. // Clear depth/stencil if needed
  116. if (RenderingManager.AUTOCLEAR) {
  117. const autoClear = this._useSceneAutoClearSetup ? this._scene.getAutoClearDepthStencilSetup(index) : this._autoClearDepthStencil[index];
  118. if (autoClear && autoClear.autoClear) {
  119. this._clearDepthStencilBuffer(autoClear.depth, autoClear.stencil);
  120. }
  121. }
  122. // Render
  123. for (const step of this._scene._beforeRenderingGroupDrawStage) {
  124. step.action(index);
  125. }
  126. renderingGroup.render(customRenderFunction, renderSprites, renderParticles, activeMeshes);
  127. for (const step of this._scene._afterRenderingGroupDrawStage) {
  128. step.action(index);
  129. }
  130. // After Observable
  131. this._scene.onAfterRenderingGroupObservable.notifyObservers(info, renderingGroupMask);
  132. }
  133. }
  134. /**
  135. * Resets the different information of the group to prepare a new frame
  136. * @internal
  137. */
  138. reset() {
  139. if (this.maintainStateBetweenFrames) {
  140. return;
  141. }
  142. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  143. const renderingGroup = this._renderingGroups[index];
  144. if (renderingGroup) {
  145. renderingGroup.prepare();
  146. }
  147. }
  148. }
  149. /**
  150. * Resets the sprites information of the group to prepare a new frame
  151. * @internal
  152. */
  153. resetSprites() {
  154. if (this.maintainStateBetweenFrames) {
  155. return;
  156. }
  157. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  158. const renderingGroup = this._renderingGroups[index];
  159. if (renderingGroup) {
  160. renderingGroup.prepareSprites();
  161. }
  162. }
  163. }
  164. /**
  165. * Dispose and release the group and its associated resources.
  166. * @internal
  167. */
  168. dispose() {
  169. this.freeRenderingGroups();
  170. this._renderingGroups.length = 0;
  171. this._renderingGroupInfo = null;
  172. }
  173. /**
  174. * Clear the info related to rendering groups preventing retention points during dispose.
  175. */
  176. freeRenderingGroups() {
  177. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  178. const renderingGroup = this._renderingGroups[index];
  179. if (renderingGroup) {
  180. renderingGroup.dispose();
  181. }
  182. }
  183. }
  184. _prepareRenderingGroup(renderingGroupId) {
  185. if (this._renderingGroups[renderingGroupId] === undefined) {
  186. this._renderingGroups[renderingGroupId] = new RenderingGroup(renderingGroupId, this._scene, this._customOpaqueSortCompareFn[renderingGroupId], this._customAlphaTestSortCompareFn[renderingGroupId], this._customTransparentSortCompareFn[renderingGroupId]);
  187. }
  188. }
  189. /**
  190. * Add a sprite manager to the rendering manager in order to render it this frame.
  191. * @param spriteManager Define the sprite manager to render
  192. */
  193. dispatchSprites(spriteManager) {
  194. if (this.maintainStateBetweenFrames && spriteManager._wasDispatched) {
  195. return;
  196. }
  197. spriteManager._wasDispatched = true;
  198. this.getRenderingGroup(spriteManager.renderingGroupId).dispatchSprites(spriteManager);
  199. }
  200. /**
  201. * Add a particle system to the rendering manager in order to render it this frame.
  202. * @param particleSystem Define the particle system to render
  203. */
  204. dispatchParticles(particleSystem) {
  205. if (this.maintainStateBetweenFrames && particleSystem._wasDispatched) {
  206. return;
  207. }
  208. particleSystem._wasDispatched = true;
  209. this.getRenderingGroup(particleSystem.renderingGroupId).dispatchParticles(particleSystem);
  210. }
  211. /**
  212. * Add a submesh to the manager in order to render it this frame
  213. * @param subMesh The submesh to dispatch
  214. * @param mesh Optional reference to the submeshes's mesh. Provide if you have an exiting reference to improve performance.
  215. * @param material Optional reference to the submeshes's material. Provide if you have an exiting reference to improve performance.
  216. */
  217. dispatch(subMesh, mesh, material) {
  218. if (mesh === undefined) {
  219. mesh = subMesh.getMesh();
  220. }
  221. if (this.maintainStateBetweenFrames && subMesh._wasDispatched) {
  222. return;
  223. }
  224. subMesh._wasDispatched = true;
  225. this.getRenderingGroup(mesh.renderingGroupId).dispatch(subMesh, mesh, material);
  226. }
  227. /**
  228. * Overrides the default sort function applied in the rendering group to prepare the meshes.
  229. * This allowed control for front to back rendering or reversely depending of the special needs.
  230. *
  231. * @param renderingGroupId The rendering group id corresponding to its index
  232. * @param opaqueSortCompareFn The opaque queue comparison function use to sort.
  233. * @param alphaTestSortCompareFn The alpha test queue comparison function use to sort.
  234. * @param transparentSortCompareFn The transparent queue comparison function use to sort.
  235. */
  236. setRenderingOrder(renderingGroupId, opaqueSortCompareFn = null, alphaTestSortCompareFn = null, transparentSortCompareFn = null) {
  237. this._customOpaqueSortCompareFn[renderingGroupId] = opaqueSortCompareFn;
  238. this._customAlphaTestSortCompareFn[renderingGroupId] = alphaTestSortCompareFn;
  239. this._customTransparentSortCompareFn[renderingGroupId] = transparentSortCompareFn;
  240. if (this._renderingGroups[renderingGroupId]) {
  241. const group = this._renderingGroups[renderingGroupId];
  242. group.opaqueSortCompareFn = this._customOpaqueSortCompareFn[renderingGroupId];
  243. group.alphaTestSortCompareFn = this._customAlphaTestSortCompareFn[renderingGroupId];
  244. group.transparentSortCompareFn = this._customTransparentSortCompareFn[renderingGroupId];
  245. }
  246. }
  247. /**
  248. * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
  249. *
  250. * @param renderingGroupId The rendering group id corresponding to its index
  251. * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
  252. * @param depth Automatically clears depth between groups if true and autoClear is true.
  253. * @param stencil Automatically clears stencil between groups if true and autoClear is true.
  254. */
  255. setRenderingAutoClearDepthStencil(renderingGroupId, autoClearDepthStencil, depth = true, stencil = true) {
  256. this._autoClearDepthStencil[renderingGroupId] = {
  257. autoClear: autoClearDepthStencil,
  258. depth: depth,
  259. stencil: stencil,
  260. };
  261. }
  262. /**
  263. * Gets the current auto clear configuration for one rendering group of the rendering
  264. * manager.
  265. * @param index the rendering group index to get the information for
  266. * @returns The auto clear setup for the requested rendering group
  267. */
  268. getAutoClearDepthStencilSetup(index) {
  269. return this._autoClearDepthStencil[index];
  270. }
  271. }
  272. /**
  273. * The max id used for rendering groups (not included)
  274. */
  275. RenderingManager.MAX_RENDERINGGROUPS = 4;
  276. /**
  277. * The min id used for rendering groups (included)
  278. */
  279. RenderingManager.MIN_RENDERINGGROUPS = 0;
  280. /**
  281. * Used to globally prevent autoclearing scenes.
  282. */
  283. RenderingManager.AUTOCLEAR = true;
  284. //# sourceMappingURL=renderingManager.js.map