instancedMesh.ts 12 KB

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