babylon.instancedMesh.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. module BABYLON {
  2. /**
  3. * Creates an instance based on a source mesh.
  4. */
  5. export class InstancedMesh extends AbstractMesh {
  6. private _sourceMesh: Mesh;
  7. private _currentLOD: Mesh;
  8. /** @hidden */
  9. public _indexInSourceMeshInstanceArray = -1;
  10. constructor(name: string, source: Mesh) {
  11. super(name, source.getScene());
  12. source.addInstance(this);
  13. this._sourceMesh = source;
  14. this.position.copyFrom(source.position);
  15. this.rotation.copyFrom(source.rotation);
  16. this.scaling.copyFrom(source.scaling);
  17. if (source.rotationQuaternion) {
  18. this.rotationQuaternion = source.rotationQuaternion.clone();
  19. }
  20. this.infiniteDistance = source.infiniteDistance;
  21. this.setPivotMatrix(source.getPivotMatrix());
  22. this.refreshBoundingInfo();
  23. this._syncSubMeshes();
  24. }
  25. /**
  26. * Returns the string "InstancedMesh".
  27. */
  28. public getClassName(): string {
  29. return "InstancedMesh";
  30. }
  31. // Methods
  32. /**
  33. * If the source mesh receives shadows
  34. */
  35. public get receiveShadows(): boolean {
  36. return this._sourceMesh.receiveShadows;
  37. }
  38. /**
  39. * The material of the source mesh
  40. */
  41. public get material(): Nullable<Material> {
  42. return this._sourceMesh.material;
  43. }
  44. /**
  45. * Visibility of the source mesh
  46. */
  47. public get visibility(): number {
  48. return this._sourceMesh.visibility;
  49. }
  50. /**
  51. * Skeleton of the source mesh
  52. */
  53. public get skeleton(): Nullable<Skeleton> {
  54. return this._sourceMesh.skeleton;
  55. }
  56. /**
  57. * Rendering ground id of the source mesh
  58. */
  59. public get renderingGroupId(): number {
  60. return this._sourceMesh.renderingGroupId;
  61. }
  62. public set renderingGroupId(value: number) {
  63. if (!this._sourceMesh || value === this._sourceMesh.renderingGroupId) {
  64. return;
  65. }
  66. //no-op with warning
  67. Tools.Warn("Note - setting renderingGroupId of an instanced mesh has no effect on the scene");
  68. }
  69. /**
  70. * Returns the total number of vertices (integer).
  71. */
  72. public getTotalVertices(): number {
  73. return this._sourceMesh.getTotalVertices();
  74. }
  75. /**
  76. * Returns a positive integer : the total number of indices in this mesh geometry.
  77. * @returns the numner of indices or zero if the mesh has no geometry.
  78. */
  79. public getTotalIndices(): number {
  80. return this._sourceMesh.getTotalIndices();
  81. }
  82. /**
  83. * The source mesh of the instance
  84. */
  85. public get sourceMesh(): Mesh {
  86. return this._sourceMesh;
  87. }
  88. /**
  89. * Is this node ready to be used/rendered
  90. * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
  91. * @return {boolean} is it ready
  92. */
  93. public isReady(completeCheck = false): boolean {
  94. return this._sourceMesh.isReady(completeCheck, true);
  95. }
  96. /**
  97. * Returns an array of integers or a typed array (Int32Array, Uint32Array, Uint16Array) populated with the mesh indices.
  98. * @param kind kind of verticies to retreive (eg. positons, normals, uvs, etc.)
  99. * @param copyWhenShared If true (default false) and and if the mesh geometry is shared among some other meshes, the returned array is a copy of the internal one.
  100. * @returns a float array or a Float32Array of the requested kind of data : positons, normals, uvs, etc.
  101. */
  102. public getVerticesData(kind: string, copyWhenShared?: boolean): Nullable<FloatArray> {
  103. return this._sourceMesh.getVerticesData(kind, copyWhenShared);
  104. }
  105. /**
  106. * Sets the vertex data of the mesh geometry for the requested `kind`.
  107. * If the mesh has no geometry, a new Geometry object is set to the mesh and then passed this vertex data.
  108. * The `data` are either a numeric array either a Float32Array.
  109. * The parameter `updatable` is passed as is to the underlying Geometry object constructor (if initianilly none) or updater.
  110. * The parameter `stride` is an optional positive integer, it is usually automatically deducted from the `kind` (3 for positions or normals, 2 for UV, etc).
  111. * Note that a new underlying VertexBuffer object is created each call.
  112. * If the `kind` is the `PositionKind`, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
  113. *
  114. * Possible `kind` values :
  115. * - BABYLON.VertexBuffer.PositionKind
  116. * - BABYLON.VertexBuffer.UVKind
  117. * - BABYLON.VertexBuffer.UV2Kind
  118. * - BABYLON.VertexBuffer.UV3Kind
  119. * - BABYLON.VertexBuffer.UV4Kind
  120. * - BABYLON.VertexBuffer.UV5Kind
  121. * - BABYLON.VertexBuffer.UV6Kind
  122. * - BABYLON.VertexBuffer.ColorKind
  123. * - BABYLON.VertexBuffer.MatricesIndicesKind
  124. * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
  125. * - BABYLON.VertexBuffer.MatricesWeightsKind
  126. * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
  127. *
  128. * Returns the Mesh.
  129. */
  130. public setVerticesData(kind: string, data: FloatArray, updatable?: boolean, stride?: number): Mesh {
  131. if (this.sourceMesh) {
  132. this.sourceMesh.setVerticesData(kind, data, updatable, stride);
  133. }
  134. return this.sourceMesh;
  135. }
  136. /**
  137. * Updates the existing vertex data of the mesh geometry for the requested `kind`.
  138. * If the mesh has no geometry, it is simply returned as it is.
  139. * The `data` are either a numeric array either a Float32Array.
  140. * No new underlying VertexBuffer object is created.
  141. * If the `kind` is the `PositionKind` and if `updateExtends` is true, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
  142. * If the parameter `makeItUnique` is true, a new global geometry is created from this positions and is set to the mesh.
  143. *
  144. * Possible `kind` values :
  145. * - BABYLON.VertexBuffer.PositionKind
  146. * - BABYLON.VertexBuffer.UVKind
  147. * - BABYLON.VertexBuffer.UV2Kind
  148. * - BABYLON.VertexBuffer.UV3Kind
  149. * - BABYLON.VertexBuffer.UV4Kind
  150. * - BABYLON.VertexBuffer.UV5Kind
  151. * - BABYLON.VertexBuffer.UV6Kind
  152. * - BABYLON.VertexBuffer.ColorKind
  153. * - BABYLON.VertexBuffer.MatricesIndicesKind
  154. * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
  155. * - BABYLON.VertexBuffer.MatricesWeightsKind
  156. * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
  157. *
  158. * Returns the Mesh.
  159. */
  160. public updateVerticesData(kind: string, data: FloatArray, updateExtends?: boolean, makeItUnique?: boolean): Mesh {
  161. if (this.sourceMesh) {
  162. this.sourceMesh.updateVerticesData(kind, data, updateExtends, makeItUnique);
  163. }
  164. return this.sourceMesh;
  165. }
  166. /**
  167. * Sets the mesh indices.
  168. * Expects an array populated with integers or a typed array (Int32Array, Uint32Array, Uint16Array).
  169. * If the mesh has no geometry, a new Geometry object is created and set to the mesh.
  170. * This method creates a new index buffer each call.
  171. * Returns the Mesh.
  172. */
  173. public setIndices(indices: IndicesArray, totalVertices: Nullable<number> = null): Mesh {
  174. if (this.sourceMesh) {
  175. this.sourceMesh.setIndices(indices, totalVertices);
  176. }
  177. return this.sourceMesh;
  178. }
  179. /**
  180. * Boolean : True if the mesh owns the requested kind of data.
  181. */
  182. public isVerticesDataPresent(kind: string): boolean {
  183. return this._sourceMesh.isVerticesDataPresent(kind);
  184. }
  185. /**
  186. * Returns an array of indices (IndicesArray).
  187. */
  188. public getIndices(): Nullable<IndicesArray> {
  189. return this._sourceMesh.getIndices();
  190. }
  191. public get _positions(): Nullable<Vector3[]> {
  192. return this._sourceMesh._positions;
  193. }
  194. /**
  195. * This method recomputes and sets a new BoundingInfo to the mesh unless it is locked.
  196. * This means the mesh underlying bounding box and sphere are recomputed.
  197. * @param applySkeleton defines whether to apply the skeleton before computing the bounding info
  198. * @returns the current mesh
  199. */
  200. public refreshBoundingInfo(applySkeleton: boolean = false): InstancedMesh {
  201. if (this._boundingInfo && this._boundingInfo.isLocked) {
  202. return this;
  203. }
  204. const bias = this._sourceMesh.geometry ? this._sourceMesh.geometry.boundingBias : null;
  205. this._refreshBoundingInfo(this._sourceMesh._getPositionData(applySkeleton), bias);
  206. return this;
  207. }
  208. /** @hidden */
  209. public _preActivate(): InstancedMesh {
  210. if (this._currentLOD) {
  211. this._currentLOD._preActivate();
  212. }
  213. return this;
  214. }
  215. /** @hidden */
  216. public _activate(renderId: number): InstancedMesh {
  217. if (this._currentLOD) {
  218. this._currentLOD._registerInstanceForRenderId(this, renderId);
  219. }
  220. return this;
  221. }
  222. /**
  223. * Returns the current associated LOD AbstractMesh.
  224. */
  225. public getLOD(camera: Camera): AbstractMesh {
  226. if (!camera) {
  227. return this;
  228. }
  229. let boundingInfo = this.getBoundingInfo();
  230. this._currentLOD = <Mesh>this.sourceMesh.getLOD(camera, boundingInfo.boundingSphere);
  231. if (this._currentLOD === this.sourceMesh) {
  232. return this;
  233. }
  234. return this._currentLOD;
  235. }
  236. /** @hidden */
  237. public _syncSubMeshes(): InstancedMesh {
  238. this.releaseSubMeshes();
  239. if (this._sourceMesh.subMeshes) {
  240. for (var index = 0; index < this._sourceMesh.subMeshes.length; index++) {
  241. this._sourceMesh.subMeshes[index].clone(this, this._sourceMesh);
  242. }
  243. }
  244. return this;
  245. }
  246. /** @hidden */
  247. public _generatePointsArray(): boolean {
  248. return this._sourceMesh._generatePointsArray();
  249. }
  250. /**
  251. * Creates a new InstancedMesh from the current mesh.
  252. * - name (string) : the cloned mesh name
  253. * - newParent (optional Node) : the optional Node to parent the clone to.
  254. * - doNotCloneChildren (optional boolean, default `false`) : if `true` the model children aren't cloned.
  255. *
  256. * Returns the clone.
  257. */
  258. public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): InstancedMesh {
  259. var result = this._sourceMesh.createInstance(name);
  260. // Deep copy
  261. Tools.DeepCopy(this, result, ["name", "subMeshes", "uniqueId"], []);
  262. // Bounding info
  263. this.refreshBoundingInfo();
  264. // Parent
  265. if (newParent) {
  266. result.parent = newParent;
  267. }
  268. if (!doNotCloneChildren) {
  269. // Children
  270. for (var index = 0; index < this.getScene().meshes.length; index++) {
  271. var mesh = this.getScene().meshes[index];
  272. if (mesh.parent === this) {
  273. mesh.clone(mesh.name, result);
  274. }
  275. }
  276. }
  277. result.computeWorldMatrix(true);
  278. return result;
  279. }
  280. /**
  281. * Disposes the InstancedMesh.
  282. * Returns nothing.
  283. */
  284. public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
  285. // Remove from mesh
  286. this._sourceMesh.removeInstance(this);
  287. super.dispose(doNotRecurse, disposeMaterialAndTextures);
  288. }
  289. }
  290. }