renderingManager.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. import { Nullable } from "types";
  2. import { RenderingGroupInfo, Scene } from "scene";
  3. import { AbstractMesh, SubMesh } from "Mesh";
  4. import { RenderingGroup } from "Rendering";
  5. import { SmartArray } from "Tools";
  6. import { ISpriteManager } from "Sprites";
  7. import { IParticleSystem } from "Particles";
  8. import { Material } from "Materials";
  9. /**
  10. * Interface describing the different options available in the rendering manager
  11. * regarding Auto Clear between groups.
  12. */
  13. export interface IRenderingManagerAutoClearSetup {
  14. /**
  15. * Defines whether or not autoclear is enable.
  16. */
  17. autoClear: boolean;
  18. /**
  19. * Defines whether or not to autoclear the depth buffer.
  20. */
  21. depth: boolean;
  22. /**
  23. * Defines whether or not to autoclear the stencil buffer.
  24. */
  25. stencil: boolean;
  26. }
  27. /**
  28. * This is the manager responsible of all the rendering for meshes sprites and particles.
  29. * It is enable to manage the different groups as well as the different necessary sort functions.
  30. * This should not be used directly aside of the few static configurations
  31. */
  32. export class RenderingManager {
  33. /**
  34. * The max id used for rendering groups (not included)
  35. */
  36. public static MAX_RENDERINGGROUPS = 4;
  37. /**
  38. * The min id used for rendering groups (included)
  39. */
  40. public static MIN_RENDERINGGROUPS = 0;
  41. /**
  42. * Used to globally prevent autoclearing scenes.
  43. */
  44. public static AUTOCLEAR = true;
  45. /**
  46. * @hidden
  47. */
  48. public _useSceneAutoClearSetup = false;
  49. private _scene: Scene;
  50. private _renderingGroups = new Array<RenderingGroup>();
  51. private _depthStencilBufferAlreadyCleaned: boolean;
  52. private _autoClearDepthStencil: { [id: number]: IRenderingManagerAutoClearSetup } = {};
  53. private _customOpaqueSortCompareFn: { [id: number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
  54. private _customAlphaTestSortCompareFn: { [id: number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
  55. private _customTransparentSortCompareFn: { [id: number]: Nullable<(a: SubMesh, b: SubMesh) => number> } = {};
  56. private _renderingGroupInfo: Nullable<RenderingGroupInfo> = new RenderingGroupInfo();
  57. /**
  58. * Instantiates a new rendering group for a particular scene
  59. * @param scene Defines the scene the groups belongs to
  60. */
  61. constructor(scene: Scene) {
  62. this._scene = scene;
  63. for (let i = RenderingManager.MIN_RENDERINGGROUPS; i < RenderingManager.MAX_RENDERINGGROUPS; i++) {
  64. this._autoClearDepthStencil[i] = { autoClear: true, depth: true, stencil: true };
  65. }
  66. }
  67. private _clearDepthStencilBuffer(depth = true, stencil = true): void {
  68. if (this._depthStencilBufferAlreadyCleaned) {
  69. return;
  70. }
  71. this._scene.getEngine().clear(null, false, depth, stencil);
  72. this._depthStencilBufferAlreadyCleaned = true;
  73. }
  74. /**
  75. * Renders the entire managed groups. This is used by the scene or the different rennder targets.
  76. * @hidden
  77. */
  78. public render(customRenderFunction: Nullable<(opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, depthOnlySubMeshes: SmartArray<SubMesh>) => void>,
  79. activeMeshes: Nullable<AbstractMesh[]>, renderParticles: boolean, renderSprites: boolean): void {
  80. // Update the observable context (not null as it only goes away on dispose)
  81. const info = this._renderingGroupInfo!;
  82. info.scene = this._scene;
  83. info.camera = this._scene.activeCamera;
  84. // Dispatch sprites
  85. if (this._scene.spriteManagers && renderSprites) {
  86. for (let index = 0; index < this._scene.spriteManagers.length; index++) {
  87. var manager = this._scene.spriteManagers[index];
  88. this.dispatchSprites(manager);
  89. }
  90. }
  91. // Render
  92. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  93. this._depthStencilBufferAlreadyCleaned = index === RenderingManager.MIN_RENDERINGGROUPS;
  94. var renderingGroup = this._renderingGroups[index];
  95. if (!renderingGroup) {
  96. continue;
  97. }
  98. let renderingGroupMask = Math.pow(2, index);
  99. info.renderingGroupId = index;
  100. // Before Observable
  101. this._scene.onBeforeRenderingGroupObservable.notifyObservers(info, renderingGroupMask);
  102. // Clear depth/stencil if needed
  103. if (RenderingManager.AUTOCLEAR) {
  104. const autoClear = this._useSceneAutoClearSetup ?
  105. this._scene.getAutoClearDepthStencilSetup(index) :
  106. this._autoClearDepthStencil[index];
  107. if (autoClear && autoClear.autoClear) {
  108. this._clearDepthStencilBuffer(autoClear.depth, autoClear.stencil);
  109. }
  110. }
  111. // Render
  112. for (let step of this._scene._beforeRenderingGroupDrawStage) {
  113. step.action(index);
  114. }
  115. renderingGroup.render(customRenderFunction, renderSprites, renderParticles, activeMeshes);
  116. for (let step of this._scene._afterRenderingGroupDrawStage) {
  117. step.action(index);
  118. }
  119. // After Observable
  120. this._scene.onAfterRenderingGroupObservable.notifyObservers(info, renderingGroupMask);
  121. }
  122. }
  123. /**
  124. * Resets the different information of the group to prepare a new frame
  125. * @hidden
  126. */
  127. public reset(): void {
  128. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  129. var renderingGroup = this._renderingGroups[index];
  130. if (renderingGroup) {
  131. renderingGroup.prepare();
  132. }
  133. }
  134. }
  135. /**
  136. * Dispose and release the group and its associated resources.
  137. * @hidden
  138. */
  139. public dispose(): void {
  140. this.freeRenderingGroups();
  141. this._renderingGroups.length = 0;
  142. this._renderingGroupInfo = null;
  143. }
  144. /**
  145. * Clear the info related to rendering groups preventing retention points during dispose.
  146. */
  147. public freeRenderingGroups(): void {
  148. for (let index = RenderingManager.MIN_RENDERINGGROUPS; index < RenderingManager.MAX_RENDERINGGROUPS; index++) {
  149. var renderingGroup = this._renderingGroups[index];
  150. if (renderingGroup) {
  151. renderingGroup.dispose();
  152. }
  153. }
  154. }
  155. private _prepareRenderingGroup(renderingGroupId: number): void {
  156. if (this._renderingGroups[renderingGroupId] === undefined) {
  157. this._renderingGroups[renderingGroupId] = new RenderingGroup(renderingGroupId, this._scene,
  158. this._customOpaqueSortCompareFn[renderingGroupId],
  159. this._customAlphaTestSortCompareFn[renderingGroupId],
  160. this._customTransparentSortCompareFn[renderingGroupId]
  161. );
  162. }
  163. }
  164. /**
  165. * Add a sprite manager to the rendering manager in order to render it this frame.
  166. * @param spriteManager Define the sprite manager to render
  167. */
  168. public dispatchSprites(spriteManager: ISpriteManager) {
  169. var renderingGroupId = spriteManager.renderingGroupId || 0;
  170. this._prepareRenderingGroup(renderingGroupId);
  171. this._renderingGroups[renderingGroupId].dispatchSprites(spriteManager);
  172. }
  173. /**
  174. * Add a particle system to the rendering manager in order to render it this frame.
  175. * @param particleSystem Define the particle system to render
  176. */
  177. public dispatchParticles(particleSystem: IParticleSystem) {
  178. var renderingGroupId = particleSystem.renderingGroupId || 0;
  179. this._prepareRenderingGroup(renderingGroupId);
  180. this._renderingGroups[renderingGroupId].dispatchParticles(particleSystem);
  181. }
  182. /**
  183. * Add a submesh to the manager in order to render it this frame
  184. * @param subMesh The submesh to dispatch
  185. * @param mesh Optional reference to the submeshes's mesh. Provide if you have an exiting reference to improve performance.
  186. * @param material Optional reference to the submeshes's material. Provide if you have an exiting reference to improve performance.
  187. */
  188. public dispatch(subMesh: SubMesh, mesh?: AbstractMesh, material?: Nullable<Material>): void {
  189. if (mesh === undefined) {
  190. mesh = subMesh.getMesh();
  191. }
  192. var renderingGroupId = mesh.renderingGroupId || 0;
  193. this._prepareRenderingGroup(renderingGroupId);
  194. this._renderingGroups[renderingGroupId].dispatch(subMesh, mesh, material);
  195. }
  196. /**
  197. * Overrides the default sort function applied in the renderging group to prepare the meshes.
  198. * This allowed control for front to back rendering or reversly depending of the special needs.
  199. *
  200. * @param renderingGroupId The rendering group id corresponding to its index
  201. * @param opaqueSortCompareFn The opaque queue comparison function use to sort.
  202. * @param alphaTestSortCompareFn The alpha test queue comparison function use to sort.
  203. * @param transparentSortCompareFn The transparent queue comparison function use to sort.
  204. */
  205. public setRenderingOrder(renderingGroupId: number,
  206. opaqueSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
  207. alphaTestSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null,
  208. transparentSortCompareFn: Nullable<(a: SubMesh, b: SubMesh) => number> = null) {
  209. this._customOpaqueSortCompareFn[renderingGroupId] = opaqueSortCompareFn;
  210. this._customAlphaTestSortCompareFn[renderingGroupId] = alphaTestSortCompareFn;
  211. this._customTransparentSortCompareFn[renderingGroupId] = transparentSortCompareFn;
  212. if (this._renderingGroups[renderingGroupId]) {
  213. var group = this._renderingGroups[renderingGroupId];
  214. group.opaqueSortCompareFn = this._customOpaqueSortCompareFn[renderingGroupId];
  215. group.alphaTestSortCompareFn = this._customAlphaTestSortCompareFn[renderingGroupId];
  216. group.transparentSortCompareFn = this._customTransparentSortCompareFn[renderingGroupId];
  217. }
  218. }
  219. /**
  220. * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
  221. *
  222. * @param renderingGroupId The rendering group id corresponding to its index
  223. * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
  224. * @param depth Automatically clears depth between groups if true and autoClear is true.
  225. * @param stencil Automatically clears stencil between groups if true and autoClear is true.
  226. */
  227. public setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean,
  228. depth = true,
  229. stencil = true): void {
  230. this._autoClearDepthStencil[renderingGroupId] = {
  231. autoClear: autoClearDepthStencil,
  232. depth: depth,
  233. stencil: stencil
  234. };
  235. }
  236. /**
  237. * Gets the current auto clear configuration for one rendering group of the rendering
  238. * manager.
  239. * @param index the rendering group index to get the information for
  240. * @returns The auto clear setup for the requested rendering group
  241. */
  242. public getAutoClearDepthStencilSetup(index: number): IRenderingManagerAutoClearSetup {
  243. return this._autoClearDepthStencil[index];
  244. }
  245. }