babylon.instancedMesh.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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. * The source mesh of the instance
  77. */
  78. public get sourceMesh(): Mesh {
  79. return this._sourceMesh;
  80. }
  81. /**
  82. * Is this node ready to be used/rendered
  83. * @param completeCheck defines if a complete check (including materials and lights) has to be done (false by default)
  84. * @return {boolean} is it ready
  85. */
  86. public isReady(completeCheck = false): boolean {
  87. return this._sourceMesh.isReady(completeCheck, true);
  88. }
  89. /**
  90. * Returns an array of integers or a typed array (Int32Array, Uint32Array, Uint16Array) populated with the mesh indices.
  91. * @param kind kind of verticies to retreive (eg. positons, normals, uvs, etc.)
  92. * @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.
  93. * @returns a float array or a Float32Array of the requested kind of data : positons, normals, uvs, etc.
  94. */
  95. public getVerticesData(kind: string, copyWhenShared?: boolean): Nullable<FloatArray> {
  96. return this._sourceMesh.getVerticesData(kind, copyWhenShared);
  97. }
  98. /**
  99. * Sets the vertex data of the mesh geometry for the requested `kind`.
  100. * If the mesh has no geometry, a new Geometry object is set to the mesh and then passed this vertex data.
  101. * The `data` are either a numeric array either a Float32Array.
  102. * The parameter `updatable` is passed as is to the underlying Geometry object constructor (if initianilly none) or updater.
  103. * 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).
  104. * Note that a new underlying VertexBuffer object is created each call.
  105. * If the `kind` is the `PositionKind`, the mesh BoundingInfo is renewed, so the bounding box and sphere, and the mesh World Matrix is recomputed.
  106. *
  107. * Possible `kind` values :
  108. * - BABYLON.VertexBuffer.PositionKind
  109. * - BABYLON.VertexBuffer.UVKind
  110. * - BABYLON.VertexBuffer.UV2Kind
  111. * - BABYLON.VertexBuffer.UV3Kind
  112. * - BABYLON.VertexBuffer.UV4Kind
  113. * - BABYLON.VertexBuffer.UV5Kind
  114. * - BABYLON.VertexBuffer.UV6Kind
  115. * - BABYLON.VertexBuffer.ColorKind
  116. * - BABYLON.VertexBuffer.MatricesIndicesKind
  117. * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
  118. * - BABYLON.VertexBuffer.MatricesWeightsKind
  119. * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
  120. *
  121. * Returns the Mesh.
  122. */
  123. public setVerticesData(kind: string, data: FloatArray, updatable?: boolean, stride?: number): Mesh {
  124. if (this.sourceMesh) {
  125. this.sourceMesh.setVerticesData(kind, data, updatable, stride);
  126. }
  127. return this.sourceMesh;
  128. }
  129. /**
  130. * Updates the existing vertex data of the mesh geometry for the requested `kind`.
  131. * If the mesh has no geometry, it is simply returned as it is.
  132. * The `data` are either a numeric array either a Float32Array.
  133. * No new underlying VertexBuffer object is created.
  134. * 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.
  135. * If the parameter `makeItUnique` is true, a new global geometry is created from this positions and is set to the mesh.
  136. *
  137. * Possible `kind` values :
  138. * - BABYLON.VertexBuffer.PositionKind
  139. * - BABYLON.VertexBuffer.UVKind
  140. * - BABYLON.VertexBuffer.UV2Kind
  141. * - BABYLON.VertexBuffer.UV3Kind
  142. * - BABYLON.VertexBuffer.UV4Kind
  143. * - BABYLON.VertexBuffer.UV5Kind
  144. * - BABYLON.VertexBuffer.UV6Kind
  145. * - BABYLON.VertexBuffer.ColorKind
  146. * - BABYLON.VertexBuffer.MatricesIndicesKind
  147. * - BABYLON.VertexBuffer.MatricesIndicesExtraKind
  148. * - BABYLON.VertexBuffer.MatricesWeightsKind
  149. * - BABYLON.VertexBuffer.MatricesWeightsExtraKind
  150. *
  151. * Returns the Mesh.
  152. */
  153. public updateVerticesData(kind: string, data: FloatArray, updateExtends?: boolean, makeItUnique?: boolean): Mesh {
  154. if (this.sourceMesh) {
  155. this.sourceMesh.updateVerticesData(kind, data, updateExtends, makeItUnique);
  156. }
  157. return this.sourceMesh;
  158. }
  159. /**
  160. * Sets the mesh indices.
  161. * Expects an array populated with integers or a typed array (Int32Array, Uint32Array, Uint16Array).
  162. * If the mesh has no geometry, a new Geometry object is created and set to the mesh.
  163. * This method creates a new index buffer each call.
  164. * Returns the Mesh.
  165. */
  166. public setIndices(indices: IndicesArray, totalVertices: Nullable<number> = null): Mesh {
  167. if (this.sourceMesh) {
  168. this.sourceMesh.setIndices(indices, totalVertices);
  169. }
  170. return this.sourceMesh;
  171. }
  172. /**
  173. * Boolean : True if the mesh owns the requested kind of data.
  174. */
  175. public isVerticesDataPresent(kind: string): boolean {
  176. return this._sourceMesh.isVerticesDataPresent(kind);
  177. }
  178. /**
  179. * Returns an array of indices (IndicesArray).
  180. */
  181. public getIndices(): Nullable<IndicesArray> {
  182. return this._sourceMesh.getIndices();
  183. }
  184. public get _positions(): Nullable<Vector3[]> {
  185. return this._sourceMesh._positions;
  186. }
  187. /**
  188. * reconstructs and updates the BoundingInfo of the mesh.
  189. * @returns the mesh.
  190. */
  191. public refreshBoundingInfo(): InstancedMesh {
  192. var meshBB = this._sourceMesh.getBoundingInfo();
  193. if (this._boundingInfo) {
  194. this._boundingInfo.reConstruct(meshBB.minimum, meshBB.maximum, undefined, meshBB.extraWorldExtent);
  195. }
  196. else {
  197. this._boundingInfo = new BoundingInfo(meshBB.minimum, meshBB.maximum, undefined, meshBB.extraWorldExtent);
  198. }
  199. this._updateBoundingInfo();
  200. return this;
  201. }
  202. /** @hidden */
  203. public _preActivate(): InstancedMesh {
  204. if (this._currentLOD) {
  205. this._currentLOD._preActivate();
  206. }
  207. return this;
  208. }
  209. /** @hidden */
  210. public _activate(renderId: number): InstancedMesh {
  211. if (this._currentLOD) {
  212. this._currentLOD._registerInstanceForRenderId(this, renderId);
  213. }
  214. return this;
  215. }
  216. /**
  217. * Returns the current associated LOD AbstractMesh.
  218. */
  219. public getLOD(camera: Camera): AbstractMesh {
  220. if (!camera) {
  221. return this;
  222. }
  223. let boundingInfo = this.getBoundingInfo();
  224. this._currentLOD = <Mesh>this.sourceMesh.getLOD(camera, boundingInfo.boundingSphere);
  225. if (this._currentLOD === this.sourceMesh) {
  226. return this;
  227. }
  228. return this._currentLOD;
  229. }
  230. /** @hidden */
  231. public _syncSubMeshes(): InstancedMesh {
  232. this.releaseSubMeshes();
  233. if (this._sourceMesh.subMeshes) {
  234. for (var index = 0; index < this._sourceMesh.subMeshes.length; index++) {
  235. this._sourceMesh.subMeshes[index].clone(this, this._sourceMesh);
  236. }
  237. }
  238. return this;
  239. }
  240. /** @hidden */
  241. public _generatePointsArray(): boolean {
  242. return this._sourceMesh._generatePointsArray();
  243. }
  244. /**
  245. * Creates a new InstancedMesh from the current mesh.
  246. * - name (string) : the cloned mesh name
  247. * - newParent (optional Node) : the optional Node to parent the clone to.
  248. * - doNotCloneChildren (optional boolean, default `false`) : if `true` the model children aren't cloned.
  249. *
  250. * Returns the clone.
  251. */
  252. public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): InstancedMesh {
  253. var result = this._sourceMesh.createInstance(name);
  254. // Deep copy
  255. Tools.DeepCopy(this, result, ["name", "subMeshes", "uniqueId"], []);
  256. // Bounding info
  257. this.refreshBoundingInfo();
  258. // Parent
  259. if (newParent) {
  260. result.parent = newParent;
  261. }
  262. if (!doNotCloneChildren) {
  263. // Children
  264. for (var index = 0; index < this.getScene().meshes.length; index++) {
  265. var mesh = this.getScene().meshes[index];
  266. if (mesh.parent === this) {
  267. mesh.clone(mesh.name, result);
  268. }
  269. }
  270. }
  271. result.computeWorldMatrix(true);
  272. return result;
  273. }
  274. /**
  275. * Disposes the InstancedMesh.
  276. * Returns nothing.
  277. */
  278. public dispose(doNotRecurse?: boolean, disposeMaterialAndTextures = false): void {
  279. // Remove from mesh
  280. this._sourceMesh.removeInstance(this);
  281. super.dispose(doNotRecurse, disposeMaterialAndTextures);
  282. }
  283. }
  284. }