babylon.renderingGroup.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. module BABYLON {
  2. export class RenderingGroup {
  3. private _scene: Scene;
  4. private _opaqueSubMeshes = new SmartArray<SubMesh>(256);
  5. private _transparentSubMeshes = new SmartArray<SubMesh>(256);
  6. private _alphaTestSubMeshes = new SmartArray<SubMesh>(256);
  7. private _particleSystems = new SmartArray<ParticleSystem>(256);
  8. private _spriteManagers = new SmartArray<SpriteManager>(256);
  9. private _activeVertices: number;
  10. private _opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number;
  11. private _alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number;
  12. private _transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number;
  13. private _renderOpaque: (subMeshes: SmartArray<SubMesh>) => void;
  14. private _renderAlphaTest: (subMeshes: SmartArray<SubMesh>) => void;
  15. private _renderTransparent: (subMeshes: SmartArray<SubMesh>) => void;
  16. public onBeforeTransparentRendering: () => void;
  17. /**
  18. * Set the opaque sort comparison function.
  19. * If null the sub meshes will be render in the order they were created
  20. */
  21. public set opaqueSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
  22. this._opaqueSortCompareFn = value;
  23. if (value) {
  24. this._renderOpaque = this.renderOpaqueSorted;
  25. }
  26. else {
  27. this._renderOpaque = RenderingGroup.renderUnsorted;
  28. }
  29. }
  30. /**
  31. * Set the alpha test sort comparison function.
  32. * If null the sub meshes will be render in the order they were created
  33. */
  34. public set alphaTestSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
  35. this._alphaTestSortCompareFn = value;
  36. if (value) {
  37. this._renderAlphaTest = this.renderAlphaTestSorted;
  38. }
  39. else {
  40. this._renderAlphaTest = RenderingGroup.renderUnsorted;
  41. }
  42. }
  43. /**
  44. * Set the transparent sort comparison function.
  45. * If null the sub meshes will be render in the order they were created
  46. */
  47. public set transparentSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
  48. if (value) {
  49. this._transparentSortCompareFn = value;
  50. }
  51. else {
  52. this._transparentSortCompareFn = RenderingGroup.defaultTransparentSortCompare;
  53. }
  54. this._renderTransparent = this.renderTransparentSorted;
  55. }
  56. /**
  57. * Creates a new rendering group.
  58. * @param index The rendering group index
  59. * @param opaqueSortCompareFn The opaque sort comparison function. If null no order is applied
  60. * @param alphaTestSortCompareFn The alpha test sort comparison function. If null no order is applied
  61. * @param transparentSortCompareFn The transparent sort comparison function. If null back to front + alpha index sort is applied
  62. */
  63. constructor(public index: number, scene: Scene,
  64. opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
  65. alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
  66. transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null) {
  67. this._scene = scene;
  68. this.opaqueSortCompareFn = opaqueSortCompareFn;
  69. this.alphaTestSortCompareFn = alphaTestSortCompareFn;
  70. this.transparentSortCompareFn = transparentSortCompareFn;
  71. }
  72. /**
  73. * Render all the sub meshes contained in the group.
  74. * @param customRenderFunction Used to override the default render behaviour of the group.
  75. * @returns true if rendered some submeshes.
  76. */
  77. public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void, renderSprites: boolean, renderParticles: boolean, activeMeshes: AbstractMesh[]): void {
  78. if (customRenderFunction) {
  79. customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes);
  80. return;
  81. }
  82. var engine = this._scene.getEngine();
  83. // Opaque
  84. if (this._opaqueSubMeshes.length !== 0) {
  85. this._renderOpaque(this._opaqueSubMeshes);
  86. }
  87. // Alpha test
  88. if (this._alphaTestSubMeshes.length !== 0) {
  89. engine.setAlphaTesting(true);
  90. this._renderAlphaTest(this._alphaTestSubMeshes);
  91. engine.setAlphaTesting(false);
  92. }
  93. var stencilState = engine.getStencilBuffer();
  94. engine.setStencilBuffer(false);
  95. // Sprites
  96. if (renderSprites) {
  97. this._renderSprites();
  98. }
  99. // Particles
  100. if (renderParticles) {
  101. this._renderParticles(activeMeshes);
  102. }
  103. if (this.onBeforeTransparentRendering) {
  104. this.onBeforeTransparentRendering();
  105. }
  106. // Transparent
  107. if (this._transparentSubMeshes.length !== 0) {
  108. this._renderTransparent(this._transparentSubMeshes);
  109. engine.setAlphaMode(Engine.ALPHA_DISABLE);
  110. }
  111. engine.setStencilBuffer(stencilState);
  112. }
  113. /**
  114. * Renders the opaque submeshes in the order from the opaqueSortCompareFn.
  115. * @param subMeshes The submeshes to render
  116. */
  117. private renderOpaqueSorted(subMeshes: SmartArray<SubMesh>): void {
  118. return RenderingGroup.renderSorted(subMeshes, this._opaqueSortCompareFn, this._scene.activeCamera.globalPosition, false);
  119. }
  120. /**
  121. * Renders the opaque submeshes in the order from the alphatestSortCompareFn.
  122. * @param subMeshes The submeshes to render
  123. */
  124. private renderAlphaTestSorted(subMeshes: SmartArray<SubMesh>): void {
  125. return RenderingGroup.renderSorted(subMeshes, this._alphaTestSortCompareFn, this._scene.activeCamera.globalPosition, false);
  126. }
  127. /**
  128. * Renders the opaque submeshes in the order from the transparentSortCompareFn.
  129. * @param subMeshes The submeshes to render
  130. */
  131. private renderTransparentSorted(subMeshes: SmartArray<SubMesh>): void {
  132. return RenderingGroup.renderSorted(subMeshes, this._transparentSortCompareFn, this._scene.activeCamera.globalPosition, true);
  133. }
  134. /**
  135. * Renders the submeshes in a specified order.
  136. * @param subMeshes The submeshes to sort before render
  137. * @param sortCompareFn The comparison function use to sort
  138. * @param cameraPosition The camera position use to preprocess the submeshes to help sorting
  139. * @param transparent Specifies to activate blending if true
  140. */
  141. private static renderSorted(subMeshes: SmartArray<SubMesh>, sortCompareFn: (a: SubMesh, b: SubMesh) => number, cameraPosition: Vector3, transparent: boolean): void {
  142. let subIndex = 0;
  143. let subMesh;
  144. for (; subIndex < subMeshes.length; subIndex++) {
  145. subMesh = subMeshes.data[subIndex];
  146. subMesh._alphaIndex = subMesh.getMesh().alphaIndex;
  147. subMesh._distanceToCamera = subMesh.getBoundingInfo().boundingSphere.centerWorld.subtract(cameraPosition).length();
  148. }
  149. let sortedArray = subMeshes.data.slice(0, subMeshes.length);
  150. sortedArray.sort(sortCompareFn);
  151. for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
  152. subMesh = sortedArray[subIndex];
  153. subMesh.render(transparent);
  154. }
  155. }
  156. /**
  157. * Renders the submeshes in the order they were dispatched (no sort applied).
  158. * @param subMeshes The submeshes to render
  159. */
  160. private static renderUnsorted(subMeshes: SmartArray<SubMesh>): void {
  161. for (var subIndex = 0; subIndex < subMeshes.length; subIndex++) {
  162. let submesh = subMeshes.data[subIndex];
  163. submesh.render(false);
  164. }
  165. }
  166. /**
  167. * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
  168. * are rendered back to front if in the same alpha index.
  169. *
  170. * @param a The first submesh
  171. * @param b The second submesh
  172. * @returns The result of the comparison
  173. */
  174. public static defaultTransparentSortCompare(a: SubMesh, b:SubMesh) : number {
  175. // Alpha index first
  176. if (a._alphaIndex > b._alphaIndex) {
  177. return 1;
  178. }
  179. if (a._alphaIndex < b._alphaIndex) {
  180. return -1;
  181. }
  182. // Then distance to camera
  183. return RenderingGroup.backToFrontSortCompare(a, b);
  184. }
  185. /**
  186. * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
  187. * are rendered back to front.
  188. *
  189. * @param a The first submesh
  190. * @param b The second submesh
  191. * @returns The result of the comparison
  192. */
  193. public static backToFrontSortCompare(a: SubMesh, b:SubMesh) : number {
  194. // Then distance to camera
  195. if (a._distanceToCamera < b._distanceToCamera) {
  196. return 1;
  197. }
  198. if (a._distanceToCamera > b._distanceToCamera) {
  199. return -1;
  200. }
  201. return 0;
  202. }
  203. /**
  204. * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
  205. * are rendered front to back (prevent overdraw).
  206. *
  207. * @param a The first submesh
  208. * @param b The second submesh
  209. * @returns The result of the comparison
  210. */
  211. public static frontToBackSortCompare(a: SubMesh, b:SubMesh) : number {
  212. // Then distance to camera
  213. if (a._distanceToCamera < b._distanceToCamera) {
  214. return -1;
  215. }
  216. if (a._distanceToCamera > b._distanceToCamera) {
  217. return 1;
  218. }
  219. return 0;
  220. }
  221. /**
  222. * Resets the different lists of submeshes to prepare a new frame.
  223. */
  224. public prepare(): void {
  225. this._opaqueSubMeshes.reset();
  226. this._transparentSubMeshes.reset();
  227. this._alphaTestSubMeshes.reset();
  228. this._particleSystems.reset();
  229. this._spriteManagers.reset();
  230. }
  231. public dispose(): void {
  232. this._opaqueSubMeshes.dispose();
  233. this._transparentSubMeshes.dispose();
  234. this._alphaTestSubMeshes.dispose();
  235. this._particleSystems.dispose();
  236. this._spriteManagers.dispose();
  237. }
  238. /**
  239. * Inserts the submesh in its correct queue depending on its material.
  240. * @param subMesh The submesh to dispatch
  241. */
  242. public dispatch(subMesh: SubMesh): void {
  243. var material = subMesh.getMaterial();
  244. var mesh = subMesh.getMesh();
  245. if (material.needAlphaBlending() || mesh.visibility < 1.0 || mesh.hasVertexAlpha) { // Transparent
  246. this._transparentSubMeshes.push(subMesh);
  247. } else if (material.needAlphaTesting()) { // Alpha test
  248. this._alphaTestSubMeshes.push(subMesh);
  249. } else {
  250. this._opaqueSubMeshes.push(subMesh); // Opaque
  251. }
  252. }
  253. public dispatchSprites(spriteManager: SpriteManager) {
  254. this._spriteManagers.push(spriteManager);
  255. }
  256. public dispatchParticles(particleSystem: ParticleSystem) {
  257. this._particleSystems.push(particleSystem);
  258. }
  259. private _renderParticles(activeMeshes: AbstractMesh[]): void {
  260. if (this._particleSystems.length === 0) {
  261. return;
  262. }
  263. // Particles
  264. var activeCamera = this._scene.activeCamera;
  265. this._scene._particlesDuration.beginMonitoring();
  266. for (var particleIndex = 0; particleIndex < this._scene._activeParticleSystems.length; particleIndex++) {
  267. var particleSystem = this._scene._activeParticleSystems.data[particleIndex];
  268. if ((activeCamera.layerMask & particleSystem.layerMask) === 0) {
  269. continue;
  270. }
  271. if (!particleSystem.emitter.position || !activeMeshes || activeMeshes.indexOf(particleSystem.emitter) !== -1) {
  272. this._scene._activeParticles.addCount(particleSystem.render(), false);
  273. }
  274. }
  275. this._scene._particlesDuration.endMonitoring(false);
  276. }
  277. private _renderSprites(): void {
  278. if (!this._scene.spritesEnabled || this._spriteManagers.length === 0) {
  279. return;
  280. }
  281. // Sprites
  282. var activeCamera = this._scene.activeCamera;
  283. this._scene._spritesDuration.beginMonitoring();
  284. for (var id = 0; id < this._spriteManagers.length; id++) {
  285. var spriteManager = this._spriteManagers.data[id];
  286. if (((activeCamera.layerMask & spriteManager.layerMask) !== 0)) {
  287. spriteManager.render();
  288. }
  289. }
  290. this._scene._spritesDuration.endMonitoring(false);
  291. }
  292. }
  293. }