renderingManager.ts 12 KB

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