babylon.renderingGroup.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  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 _activeVertices: number;
  8. private _opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number;
  9. private _alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number;
  10. private _transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number;
  11. private _renderOpaque: (subMeshes: SmartArray<SubMesh>) => void;
  12. private _renderAlphaTest: (subMeshes: SmartArray<SubMesh>) => void;
  13. private _renderTransparent: (subMeshes: SmartArray<SubMesh>) => void;
  14. public onBeforeTransparentRendering: () => void;
  15. /**
  16. * Set the opaque sort comparison function.
  17. * If null the sub meshes will be render in the order they were created
  18. */
  19. public set opaqueSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
  20. this._opaqueSortCompareFn = value;
  21. if (value) {
  22. this._renderOpaque = this.renderOpaqueSorted;
  23. }
  24. else {
  25. this._renderOpaque = RenderingGroup.renderUnsorted;
  26. }
  27. }
  28. /**
  29. * Set the alpha test sort comparison function.
  30. * If null the sub meshes will be render in the order they were created
  31. */
  32. public set alphaTestSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
  33. this._alphaTestSortCompareFn = value;
  34. if (value) {
  35. this._renderAlphaTest = this.renderAlphaTestSorted;
  36. }
  37. else {
  38. this._renderAlphaTest = RenderingGroup.renderUnsorted;
  39. }
  40. }
  41. /**
  42. * Set the transparent sort comparison function.
  43. * If null the sub meshes will be render in the order they were created
  44. */
  45. public set transparentSortCompareFn(value: (a: SubMesh, b: SubMesh) => number) {
  46. if (value) {
  47. this._transparentSortCompareFn = value;
  48. }
  49. else {
  50. this._transparentSortCompareFn = RenderingGroup.defaultTransparentSortCompare;
  51. }
  52. this._renderTransparent = this.renderTransparentSorted;
  53. }
  54. /**
  55. * Creates a new rendering group.
  56. * @param index The rendering group index
  57. * @param opaqueSortCompareFn The opaque sort comparison function. If null no order is applied
  58. * @param alphaTestSortCompareFn The alpha test sort comparison function. If null no order is applied
  59. * @param transparentSortCompareFn The transparent sort comparison function. If null back to front + alpha index sort is applied
  60. */
  61. constructor(public index: number, scene: Scene,
  62. opaqueSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
  63. alphaTestSortCompareFn: (a: SubMesh, b: SubMesh) => number = null,
  64. transparentSortCompareFn: (a: SubMesh, b: SubMesh) => number = null) {
  65. this._scene = scene;
  66. this.opaqueSortCompareFn = opaqueSortCompareFn;
  67. this.alphaTestSortCompareFn = alphaTestSortCompareFn;
  68. this.transparentSortCompareFn = transparentSortCompareFn;
  69. }
  70. /**
  71. * Render all the sub meshes contained in the group.
  72. * @param customRenderFunction Used to override the default render behaviour of the group.
  73. * @returns true if rendered some submeshes.
  74. */
  75. public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>) => void): boolean {
  76. if (customRenderFunction) {
  77. customRenderFunction(this._opaqueSubMeshes, this._alphaTestSubMeshes, this._transparentSubMeshes);
  78. return true;
  79. }
  80. if (this._opaqueSubMeshes.length === 0 && this._alphaTestSubMeshes.length === 0 && this._transparentSubMeshes.length === 0) {
  81. if (this.onBeforeTransparentRendering) {
  82. this.onBeforeTransparentRendering();
  83. }
  84. return false;
  85. }
  86. var engine = this._scene.getEngine();
  87. // Opaque
  88. this._renderOpaque(this._opaqueSubMeshes);
  89. // Alpha test
  90. engine.setAlphaTesting(true);
  91. this._renderAlphaTest(this._alphaTestSubMeshes);
  92. engine.setAlphaTesting(false);
  93. if (this.onBeforeTransparentRendering) {
  94. this.onBeforeTransparentRendering();
  95. }
  96. // Transparent
  97. this._renderTransparent(this._transparentSubMeshes);
  98. engine.setAlphaMode(Engine.ALPHA_DISABLE);
  99. return true;
  100. }
  101. /**
  102. * Renders the opaque submeshes in the order from the opaqueSortCompareFn.
  103. * @param subMeshes The submeshes to render
  104. */
  105. private renderOpaqueSorted(subMeshes: SmartArray<SubMesh>): void {
  106. return RenderingGroup.renderSorted(subMeshes, this._opaqueSortCompareFn, this._scene.activeCamera.globalPosition, false);
  107. }
  108. /**
  109. * Renders the opaque submeshes in the order from the alphatestSortCompareFn.
  110. * @param subMeshes The submeshes to render
  111. */
  112. private renderAlphaTestSorted(subMeshes: SmartArray<SubMesh>): void {
  113. return RenderingGroup.renderSorted(subMeshes, this._alphaTestSortCompareFn, this._scene.activeCamera.globalPosition, false);
  114. }
  115. /**
  116. * Renders the opaque submeshes in the order from the transparentSortCompareFn.
  117. * @param subMeshes The submeshes to render
  118. */
  119. private renderTransparentSorted(subMeshes: SmartArray<SubMesh>): void {
  120. return RenderingGroup.renderSorted(subMeshes, this._transparentSortCompareFn, this._scene.activeCamera.globalPosition, true);
  121. }
  122. /**
  123. * Renders the submeshes in a specified order.
  124. * @param subMeshes The submeshes to sort before render
  125. * @param sortCompareFn The comparison function use to sort
  126. * @param cameraPosition The camera position use to preprocess the submeshes to help sorting
  127. * @param transparent Specifies to activate blending if true
  128. */
  129. private static renderSorted(subMeshes: SmartArray<SubMesh>, sortCompareFn: (a: SubMesh, b: SubMesh) => number, cameraPosition: Vector3, transparent: boolean): void {
  130. let subIndex = 0;
  131. let subMesh;
  132. for (; subIndex < subMeshes.length; subIndex++) {
  133. subMesh = subMeshes.data[subIndex];
  134. subMesh._alphaIndex = subMesh.getMesh().alphaIndex;
  135. subMesh._distanceToCamera = subMesh.getBoundingInfo().boundingSphere.centerWorld.subtract(cameraPosition).length();
  136. }
  137. let sortedArray = subMeshes.data.slice(0, subMeshes.length);
  138. sortedArray.sort(sortCompareFn);
  139. for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
  140. subMesh = sortedArray[subIndex];
  141. subMesh.render(transparent);
  142. }
  143. }
  144. /**
  145. * Renders the submeshes in the order they were dispatched (no sort applied).
  146. * @param subMeshes The submeshes to render
  147. */
  148. private static renderUnsorted(subMeshes: SmartArray<SubMesh>): void {
  149. for (var subIndex = 0; subIndex < subMeshes.length; subIndex++) {
  150. let submesh = subMeshes.data[subIndex];
  151. submesh.render(false);
  152. }
  153. }
  154. /**
  155. * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
  156. * are rendered back to front if in the same alpha index.
  157. *
  158. * @param a The first submesh
  159. * @param b The second submesh
  160. * @returns The result of the comparison
  161. */
  162. public static defaultTransparentSortCompare(a: SubMesh, b:SubMesh) : number {
  163. // Alpha index first
  164. if (a._alphaIndex > b._alphaIndex) {
  165. return 1;
  166. }
  167. if (a._alphaIndex < b._alphaIndex) {
  168. return -1;
  169. }
  170. // Then distance to camera
  171. return RenderingGroup.backToFrontSortCompare(a, b);
  172. }
  173. /**
  174. * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
  175. * are rendered back to front.
  176. *
  177. * @param a The first submesh
  178. * @param b The second submesh
  179. * @returns The result of the comparison
  180. */
  181. public static backToFrontSortCompare(a: SubMesh, b:SubMesh) : number {
  182. // Then distance to camera
  183. if (a._distanceToCamera < b._distanceToCamera) {
  184. return 1;
  185. }
  186. if (a._distanceToCamera > b._distanceToCamera) {
  187. return -1;
  188. }
  189. return 0;
  190. }
  191. /**
  192. * Build in function which can be applied to ensure meshes of a special queue (opaque, alpha test, transparent)
  193. * are rendered front to back (prevent overdraw).
  194. *
  195. * @param a The first submesh
  196. * @param b The second submesh
  197. * @returns The result of the comparison
  198. */
  199. public static frontToBackSortCompare(a: SubMesh, b:SubMesh) : number {
  200. // Then distance to camera
  201. if (a._distanceToCamera < b._distanceToCamera) {
  202. return -1;
  203. }
  204. if (a._distanceToCamera > b._distanceToCamera) {
  205. return 1;
  206. }
  207. return 0;
  208. }
  209. /**
  210. * Resets the different lists of submeshes to prepare a new frame.
  211. */
  212. public prepare(): void {
  213. this._opaqueSubMeshes.reset();
  214. this._transparentSubMeshes.reset();
  215. this._alphaTestSubMeshes.reset();
  216. }
  217. /**
  218. * Inserts the submesh in its correct queue depending on its material.
  219. * @param subMesh The submesh to dispatch
  220. */
  221. public dispatch(subMesh: SubMesh): void {
  222. var material = subMesh.getMaterial();
  223. var mesh = subMesh.getMesh();
  224. if (material.needAlphaBlending() || mesh.visibility < 1.0 || mesh.hasVertexAlpha) { // Transparent
  225. this._transparentSubMeshes.push(subMesh);
  226. } else if (material.needAlphaTesting()) { // Alpha test
  227. this._alphaTestSubMeshes.push(subMesh);
  228. } else {
  229. this._opaqueSubMeshes.push(subMesh); // Opaque
  230. }
  231. }
  232. }
  233. }