babylon.abstractMesh.ts 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. module BABYLON {
  2. export class AbstractMesh extends Node implements IDisposable {
  3. // Statics
  4. private static _BILLBOARDMODE_NONE = 0;
  5. private static _BILLBOARDMODE_X = 1;
  6. private static _BILLBOARDMODE_Y = 2;
  7. private static _BILLBOARDMODE_Z = 4;
  8. private static _BILLBOARDMODE_ALL = 7;
  9. public static get BILLBOARDMODE_NONE(): number {
  10. return AbstractMesh._BILLBOARDMODE_NONE;
  11. }
  12. public static get BILLBOARDMODE_X(): number {
  13. return AbstractMesh._BILLBOARDMODE_X;
  14. }
  15. public static get BILLBOARDMODE_Y(): number {
  16. return AbstractMesh._BILLBOARDMODE_Y;
  17. }
  18. public static get BILLBOARDMODE_Z(): number {
  19. return AbstractMesh._BILLBOARDMODE_Z;
  20. }
  21. public static get BILLBOARDMODE_ALL(): number {
  22. return AbstractMesh._BILLBOARDMODE_ALL;
  23. }
  24. // Events
  25. /**
  26. * An event triggered when the mesh is disposed.
  27. * @type {BABYLON.Observable}
  28. */
  29. public onDisposeObservable = new Observable<AbstractMesh>();
  30. private _onDisposeObserver: Observer<AbstractMesh>;
  31. public set onDispose(callback: () => void) {
  32. if (this._onDisposeObserver) {
  33. this.onDisposeObservable.remove(this._onDisposeObserver);
  34. }
  35. this._onDisposeObserver = this.onDisposeObservable.add(callback);
  36. }
  37. /**
  38. * An event triggered when this mesh collides with another one
  39. * @type {BABYLON.Observable}
  40. */
  41. public onCollideObservable = new Observable<AbstractMesh>();
  42. private _onCollideObserver: Observer<AbstractMesh>;
  43. public set onCollide(callback: () => void) {
  44. if (this._onCollideObserver) {
  45. this.onCollideObservable.remove(this._onCollideObserver);
  46. }
  47. this._onCollideObserver = this.onCollideObservable.add(callback);
  48. }
  49. /**
  50. * An event triggered when the collision's position changes
  51. * @type {BABYLON.Observable}
  52. */
  53. public onCollisionPositionChangeObservable = new Observable<Vector3>();
  54. private _onCollisionPositionChangeObserver: Observer<Vector3>;
  55. public set onCollisionPositionChange(callback: () => void) {
  56. if (this._onCollisionPositionChangeObserver) {
  57. this.onCollisionPositionChangeObservable.remove(this._onCollisionPositionChangeObserver);
  58. }
  59. this._onCollisionPositionChangeObserver = this.onCollisionPositionChangeObservable.add(callback);
  60. }
  61. /**
  62. * An event triggered after the world matrix is updated
  63. * @type {BABYLON.Observable}
  64. */
  65. public onAfterWorldMatrixUpdateObservable = new Observable<AbstractMesh>();
  66. // Properties
  67. public definedFacingForward = true; // orientation for POV movement & rotation
  68. public position = new Vector3(0, 0, 0);
  69. private _rotation = new Vector3(0, 0, 0);
  70. public _rotationQuaternion: Quaternion;
  71. private _scaling = new Vector3(1, 1, 1);
  72. public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
  73. public visibility = 1.0;
  74. public alphaIndex = Number.MAX_VALUE;
  75. public infiniteDistance = false;
  76. public isVisible = true;
  77. public isPickable = true;
  78. public showBoundingBox = false;
  79. public showSubMeshesBoundingBox = false;
  80. public isBlocker = false;
  81. public renderingGroupId = 0;
  82. public material: Material;
  83. public receiveShadows = false;
  84. public renderOutline = false;
  85. public outlineColor = Color3.Red();
  86. public outlineWidth = 0.02;
  87. public renderOverlay = false;
  88. public overlayColor = Color3.Red();
  89. public overlayAlpha = 0.5;
  90. public hasVertexAlpha = false;
  91. public useVertexColors = true;
  92. public applyFog = true;
  93. public computeBonesUsingShaders = true;
  94. public scalingDeterminant = 1;
  95. public numBoneInfluencers = 4;
  96. public useOctreeForRenderingSelection = true;
  97. public useOctreeForPicking = true;
  98. public useOctreeForCollisions = true;
  99. public layerMask: number = 0x0FFFFFFF;
  100. public alwaysSelectAsActiveMesh = false;
  101. // Actions
  102. private _actionManager: ActionManager;
  103. /**
  104. * This scene's action manager
  105. * @type {BABYLON.ActionManager}
  106. */
  107. public get actionManager(): ActionManager {
  108. if (!this._actionManager) {
  109. this.actionManager = new ActionManager(this.getScene());
  110. }
  111. return this._actionManager;
  112. }
  113. /**
  114. * This scene's action manager
  115. * @type {BABYLON.ActionManager}
  116. */
  117. public set actionManager(value: ActionManager) {
  118. this._actionManager = value;
  119. }
  120. // Physics
  121. public physicsImpostor: BABYLON.PhysicsImpostor;
  122. //Deprecated, Legacy support
  123. public onPhysicsCollide: (collidedMesh: AbstractMesh, contact: any) => void;
  124. // Collisions
  125. private _checkCollisions = false;
  126. public ellipsoid = new Vector3(0.5, 1, 0.5);
  127. public ellipsoidOffset = new Vector3(0, 0, 0);
  128. private _collider = new Collider();
  129. private _oldPositionForCollisions = new Vector3(0, 0, 0);
  130. private _diffPositionForCollisions = new Vector3(0, 0, 0);
  131. private _newPositionForCollisions = new Vector3(0, 0, 0);
  132. // Attach to bone
  133. private _meshToBoneReferal: AbstractMesh;
  134. // Edges
  135. public edgesWidth = 1;
  136. public edgesColor = new Color4(1, 0, 0, 1);
  137. public _edgesRenderer: EdgesRenderer;
  138. // Cache
  139. private _localWorld = Matrix.Zero();
  140. public _worldMatrix = Matrix.Zero();
  141. private _rotateYByPI = Matrix.RotationY(Math.PI);
  142. private _absolutePosition = Vector3.Zero();
  143. private _collisionsTransformMatrix = Matrix.Zero();
  144. private _collisionsScalingMatrix = Matrix.Zero();
  145. public _positions: Vector3[];
  146. private _isDirty = false;
  147. public _masterMesh: AbstractMesh;
  148. public _materialDefines: MaterialDefines;
  149. public _boundingInfo: BoundingInfo;
  150. private _pivotMatrix = Matrix.Identity();
  151. public _isDisposed = false;
  152. public _renderId = 0;
  153. public subMeshes: SubMesh[];
  154. public _submeshesOctree: Octree<SubMesh>;
  155. public _intersectionsInProgress = new Array<AbstractMesh>();
  156. private _isWorldMatrixFrozen = false;
  157. public _unIndexed = false;
  158. public _poseMatrix: Matrix;
  159. // Loading properties
  160. public _waitingActions: any;
  161. public _waitingFreezeWorldMatrix: boolean;
  162. // Skeleton
  163. private _skeleton: Skeleton;
  164. public _bonesTransformMatrices: Float32Array;
  165. public set skeleton(value: Skeleton) {
  166. if (this._skeleton && this._skeleton.needInitialSkinMatrix) {
  167. this._skeleton._unregisterMeshWithPoseMatrix(this);
  168. }
  169. if (value && value.needInitialSkinMatrix) {
  170. value._registerMeshWithPoseMatrix(this);
  171. }
  172. this._skeleton = value;
  173. if (!this._skeleton) {
  174. this._bonesTransformMatrices = null;
  175. }
  176. }
  177. public get skeleton(): Skeleton {
  178. return this._skeleton;
  179. }
  180. // Constructor
  181. constructor(name: string, scene: Scene) {
  182. super(name, scene);
  183. scene.addMesh(this);
  184. }
  185. /**
  186. * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
  187. */
  188. public toString(fullDetails?: boolean): string {
  189. var ret = "Name: " + this.name + ", isInstance: " + (this instanceof InstancedMesh ? "YES" : "NO");
  190. ret += ", # of submeshes: " + (this.subMeshes ? this.subMeshes.length : 0);
  191. if (this._skeleton) {
  192. ret += ", skeleton: " + this._skeleton.name;
  193. }
  194. if (fullDetails) {
  195. ret += ", billboard mode: " + (["NONE", "X", "Y", null, "Z", null, null, "ALL"])[this.billboardMode];
  196. ret += ", freeze wrld mat: " + (this._isWorldMatrixFrozen || this._waitingFreezeWorldMatrix ? "YES" : "NO");
  197. }
  198. return ret;
  199. }
  200. /**
  201. * Getting the rotation object.
  202. * If rotation quaternion is set, this vector will (almost always) be the Zero vector!
  203. */
  204. public get rotation(): Vector3 {
  205. return this._rotation;
  206. }
  207. public set rotation(newRotation: Vector3) {
  208. this._rotation = newRotation;
  209. }
  210. public get scaling(): Vector3 {
  211. return this._scaling;
  212. }
  213. public set scaling(newScaling: Vector3) {
  214. this._scaling = newScaling;
  215. if (this.physicsImpostor) {
  216. this.physicsImpostor.forceUpdate();
  217. }
  218. }
  219. public get rotationQuaternion() {
  220. return this._rotationQuaternion;
  221. }
  222. public set rotationQuaternion(quaternion: Quaternion) {
  223. this._rotationQuaternion = quaternion;
  224. //reset the rotation vector.
  225. if (quaternion && this.rotation.length()) {
  226. this.rotation.copyFromFloats(0, 0, 0);
  227. }
  228. }
  229. // Methods
  230. public updatePoseMatrix(matrix: Matrix) {
  231. this._poseMatrix.copyFrom(matrix);
  232. }
  233. public getPoseMatrix(): Matrix {
  234. return this._poseMatrix;
  235. }
  236. public disableEdgesRendering(): void {
  237. if (this._edgesRenderer !== undefined) {
  238. this._edgesRenderer.dispose();
  239. this._edgesRenderer = undefined;
  240. }
  241. }
  242. public enableEdgesRendering(epsilon = 0.95, checkVerticesInsteadOfIndices = false) {
  243. this.disableEdgesRendering();
  244. this._edgesRenderer = new EdgesRenderer(this, epsilon, checkVerticesInsteadOfIndices);
  245. }
  246. public get isBlocked(): boolean {
  247. return false;
  248. }
  249. public getLOD(camera: Camera): AbstractMesh {
  250. return this;
  251. }
  252. public getTotalVertices(): number {
  253. return 0;
  254. }
  255. public getIndices(): number[] | Int32Array {
  256. return null;
  257. }
  258. public getVerticesData(kind: string): number[] | Float32Array {
  259. return null;
  260. }
  261. public isVerticesDataPresent(kind: string): boolean {
  262. return false;
  263. }
  264. public getBoundingInfo(): BoundingInfo {
  265. if (this._masterMesh) {
  266. return this._masterMesh.getBoundingInfo();
  267. }
  268. if (!this._boundingInfo) {
  269. this._updateBoundingInfo();
  270. }
  271. return this._boundingInfo;
  272. }
  273. public get useBones(): boolean {
  274. return this.skeleton && this.getScene().skeletonsEnabled && this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) && this.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind);
  275. }
  276. public _preActivate(): void {
  277. }
  278. public _preActivateForIntermediateRendering(renderId: number): void {
  279. }
  280. public _activate(renderId: number): void {
  281. this._renderId = renderId;
  282. }
  283. public getWorldMatrix(): Matrix {
  284. if (this._masterMesh) {
  285. return this._masterMesh.getWorldMatrix();
  286. }
  287. if (this._currentRenderId !== this.getScene().getRenderId()) {
  288. this.computeWorldMatrix();
  289. }
  290. return this._worldMatrix;
  291. }
  292. public get worldMatrixFromCache(): Matrix {
  293. return this._worldMatrix;
  294. }
  295. public get absolutePosition(): Vector3 {
  296. return this._absolutePosition;
  297. }
  298. public freezeWorldMatrix() {
  299. this._isWorldMatrixFrozen = false; // no guarantee world is not already frozen, switch off temporarily
  300. this.computeWorldMatrix(true);
  301. this._isWorldMatrixFrozen = true;
  302. }
  303. public unfreezeWorldMatrix() {
  304. this._isWorldMatrixFrozen = false;
  305. this.computeWorldMatrix(true);
  306. }
  307. public get isWorldMatrixFrozen(): boolean {
  308. return this._isWorldMatrixFrozen;
  309. }
  310. public rotate(axis: Vector3, amount: number, space?: Space): void {
  311. axis.normalize();
  312. if (!this.rotationQuaternion) {
  313. this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  314. this.rotation = Vector3.Zero();
  315. }
  316. var rotationQuaternion: Quaternion;
  317. if (!space || space === Space.LOCAL) {
  318. rotationQuaternion = Quaternion.RotationAxis(axis, amount);
  319. this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
  320. }
  321. else {
  322. if (this.parent) {
  323. var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
  324. invertParentWorldMatrix.invert();
  325. axis = Vector3.TransformNormal(axis, invertParentWorldMatrix);
  326. }
  327. rotationQuaternion = Quaternion.RotationAxis(axis, amount);
  328. this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
  329. }
  330. }
  331. public translate(axis: Vector3, distance: number, space?: Space): void {
  332. var displacementVector = axis.scale(distance);
  333. if (!space || space === Space.LOCAL) {
  334. var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
  335. this.setPositionWithLocalVector(tempV3);
  336. }
  337. else {
  338. this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
  339. }
  340. }
  341. public getAbsolutePosition(): Vector3 {
  342. this.computeWorldMatrix();
  343. return this._absolutePosition;
  344. }
  345. public setAbsolutePosition(absolutePosition: Vector3): void {
  346. if (!absolutePosition) {
  347. return;
  348. }
  349. var absolutePositionX;
  350. var absolutePositionY;
  351. var absolutePositionZ;
  352. if (absolutePosition.x === undefined) {
  353. if (arguments.length < 3) {
  354. return;
  355. }
  356. absolutePositionX = arguments[0];
  357. absolutePositionY = arguments[1];
  358. absolutePositionZ = arguments[2];
  359. }
  360. else {
  361. absolutePositionX = absolutePosition.x;
  362. absolutePositionY = absolutePosition.y;
  363. absolutePositionZ = absolutePosition.z;
  364. }
  365. if (this.parent) {
  366. var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
  367. invertParentWorldMatrix.invert();
  368. var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
  369. this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
  370. } else {
  371. this.position.x = absolutePositionX;
  372. this.position.y = absolutePositionY;
  373. this.position.z = absolutePositionZ;
  374. }
  375. }
  376. // ================================== Point of View Movement =================================
  377. /**
  378. * Perform relative position change from the point of view of behind the front of the mesh.
  379. * This is performed taking into account the meshes current rotation, so you do not have to care.
  380. * Supports definition of mesh facing forward or backward.
  381. * @param {number} amountRight
  382. * @param {number} amountUp
  383. * @param {number} amountForward
  384. */
  385. public movePOV(amountRight: number, amountUp: number, amountForward: number): void {
  386. this.position.addInPlace(this.calcMovePOV(amountRight, amountUp, amountForward));
  387. }
  388. /**
  389. * Calculate relative position change from the point of view of behind the front of the mesh.
  390. * This is performed taking into account the meshes current rotation, so you do not have to care.
  391. * Supports definition of mesh facing forward or backward.
  392. * @param {number} amountRight
  393. * @param {number} amountUp
  394. * @param {number} amountForward
  395. */
  396. public calcMovePOV(amountRight: number, amountUp: number, amountForward: number): Vector3 {
  397. var rotMatrix = new Matrix();
  398. var rotQuaternion = (this.rotationQuaternion) ? this.rotationQuaternion : Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  399. rotQuaternion.toRotationMatrix(rotMatrix);
  400. var translationDelta = Vector3.Zero();
  401. var defForwardMult = this.definedFacingForward ? -1 : 1;
  402. Vector3.TransformCoordinatesFromFloatsToRef(amountRight * defForwardMult, amountUp, amountForward * defForwardMult, rotMatrix, translationDelta);
  403. return translationDelta;
  404. }
  405. // ================================== Point of View Rotation =================================
  406. /**
  407. * Perform relative rotation change from the point of view of behind the front of the mesh.
  408. * Supports definition of mesh facing forward or backward.
  409. * @param {number} flipBack
  410. * @param {number} twirlClockwise
  411. * @param {number} tiltRight
  412. */
  413. public rotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): void {
  414. this.rotation.addInPlace(this.calcRotatePOV(flipBack, twirlClockwise, tiltRight));
  415. }
  416. /**
  417. * Calculate relative rotation change from the point of view of behind the front of the mesh.
  418. * Supports definition of mesh facing forward or backward.
  419. * @param {number} flipBack
  420. * @param {number} twirlClockwise
  421. * @param {number} tiltRight
  422. */
  423. public calcRotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): Vector3 {
  424. var defForwardMult = this.definedFacingForward ? 1 : -1;
  425. return new Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
  426. }
  427. public setPivotMatrix(matrix: Matrix): void {
  428. this._pivotMatrix = matrix;
  429. this._cache.pivotMatrixUpdated = true;
  430. }
  431. public getPivotMatrix(): Matrix {
  432. return this._pivotMatrix;
  433. }
  434. public _isSynchronized(): boolean {
  435. if (this._isDirty) {
  436. return false;
  437. }
  438. if (this.billboardMode !== this._cache.billboardMode || this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE)
  439. return false;
  440. if (this._cache.pivotMatrixUpdated) {
  441. return false;
  442. }
  443. if (this.infiniteDistance) {
  444. return false;
  445. }
  446. if (!this._cache.position.equals(this.position))
  447. return false;
  448. if (this.rotationQuaternion) {
  449. if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
  450. return false;
  451. } else {
  452. if (!this._cache.rotation.equals(this.rotation))
  453. return false;
  454. }
  455. if (!this._cache.scaling.equals(this.scaling))
  456. return false;
  457. return true;
  458. }
  459. public _initCache() {
  460. super._initCache();
  461. this._cache.localMatrixUpdated = false;
  462. this._cache.position = Vector3.Zero();
  463. this._cache.scaling = Vector3.Zero();
  464. this._cache.rotation = Vector3.Zero();
  465. this._cache.rotationQuaternion = new Quaternion(0, 0, 0, 0);
  466. this._cache.billboardMode = -1;
  467. }
  468. public markAsDirty(property: string): void {
  469. if (property === "rotation") {
  470. this.rotationQuaternion = null;
  471. }
  472. this._currentRenderId = Number.MAX_VALUE;
  473. this._isDirty = true;
  474. }
  475. public _updateBoundingInfo(): void {
  476. this._boundingInfo = this._boundingInfo || new BoundingInfo(this.absolutePosition, this.absolutePosition);
  477. this._boundingInfo.update(this.worldMatrixFromCache);
  478. this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
  479. }
  480. public _updateSubMeshesBoundingInfo(matrix: Matrix): void {
  481. if (!this.subMeshes) {
  482. return;
  483. }
  484. for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
  485. var subMesh = this.subMeshes[subIndex];
  486. if (!subMesh.IsGlobal) {
  487. subMesh.updateBoundingInfo(matrix);
  488. }
  489. }
  490. }
  491. public computeWorldMatrix(force?: boolean): Matrix {
  492. if (this._isWorldMatrixFrozen) {
  493. return this._worldMatrix;
  494. }
  495. if (!force && (this._currentRenderId === this.getScene().getRenderId() || this.isSynchronized(true))) {
  496. this._currentRenderId = this.getScene().getRenderId();
  497. return this._worldMatrix;
  498. }
  499. this._cache.position.copyFrom(this.position);
  500. this._cache.scaling.copyFrom(this.scaling);
  501. this._cache.pivotMatrixUpdated = false;
  502. this._cache.billboardMode = this.billboardMode;
  503. this._currentRenderId = this.getScene().getRenderId();
  504. this._isDirty = false;
  505. // Scaling
  506. Matrix.ScalingToRef(this.scaling.x * this.scalingDeterminant, this.scaling.y * this.scalingDeterminant, this.scaling.z * this.scalingDeterminant, Tmp.Matrix[1]);
  507. // Rotation
  508. //rotate, if quaternion is set and rotation was used
  509. if (this.rotationQuaternion) {
  510. var len = this.rotation.length();
  511. if (len) {
  512. this.rotationQuaternion.multiplyInPlace(BABYLON.Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z))
  513. this.rotation.copyFromFloats(0, 0, 0);
  514. }
  515. }
  516. if (this.rotationQuaternion) {
  517. this.rotationQuaternion.toRotationMatrix(Tmp.Matrix[0]);
  518. this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
  519. } else {
  520. Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, Tmp.Matrix[0]);
  521. this._cache.rotation.copyFrom(this.rotation);
  522. }
  523. // Translation
  524. if (this.infiniteDistance && !this.parent) {
  525. var camera = this.getScene().activeCamera;
  526. if (camera) {
  527. var cameraWorldMatrix = camera.getWorldMatrix();
  528. var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
  529. Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
  530. this.position.z + cameraGlobalPosition.z, Tmp.Matrix[2]);
  531. }
  532. } else {
  533. Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, Tmp.Matrix[2]);
  534. }
  535. // Composing transformations
  536. this._pivotMatrix.multiplyToRef(Tmp.Matrix[1], Tmp.Matrix[4]);
  537. Tmp.Matrix[4].multiplyToRef(Tmp.Matrix[0], Tmp.Matrix[5]);
  538. // Billboarding
  539. if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && this.getScene().activeCamera) {
  540. Tmp.Vector3[0].copyFrom(this.position);
  541. var localPosition = Tmp.Vector3[0];
  542. if (this.parent && this.parent.getWorldMatrix) {
  543. this._markSyncedWithParent();
  544. var parentMatrix: Matrix;
  545. if (this._meshToBoneReferal) {
  546. this.parent.getWorldMatrix().multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), Tmp.Matrix[6]);
  547. parentMatrix = Tmp.Matrix[6];
  548. } else {
  549. parentMatrix = this.parent.getWorldMatrix();
  550. }
  551. Vector3.TransformNormalToRef(localPosition, parentMatrix, Tmp.Vector3[1]);
  552. localPosition = Tmp.Vector3[1];
  553. }
  554. var zero = this.getScene().activeCamera.globalPosition.clone();
  555. if (this.parent && (<any>this.parent).position) {
  556. localPosition.addInPlace((<any>this.parent).position);
  557. Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, Tmp.Matrix[2]);
  558. }
  559. if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) !== AbstractMesh.BILLBOARDMODE_ALL) {
  560. if (this.billboardMode & AbstractMesh.BILLBOARDMODE_X)
  561. zero.x = localPosition.x + Epsilon;
  562. if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Y)
  563. zero.y = localPosition.y + Epsilon;
  564. if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Z)
  565. zero.z = localPosition.z + Epsilon;
  566. }
  567. Matrix.LookAtLHToRef(localPosition, zero, Vector3.Up(), Tmp.Matrix[3]);
  568. Tmp.Matrix[3].m[12] = Tmp.Matrix[3].m[13] = Tmp.Matrix[3].m[14] = 0;
  569. Tmp.Matrix[3].invert();
  570. Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[3], this._localWorld);
  571. this._rotateYByPI.multiplyToRef(this._localWorld, Tmp.Matrix[5]);
  572. }
  573. // Local world
  574. Tmp.Matrix[5].multiplyToRef(Tmp.Matrix[2], this._localWorld);
  575. // Parent
  576. if (this.parent && this.parent.getWorldMatrix && this.billboardMode === AbstractMesh.BILLBOARDMODE_NONE) {
  577. this._markSyncedWithParent();
  578. if (this._meshToBoneReferal) {
  579. this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), Tmp.Matrix[6]);
  580. Tmp.Matrix[6].multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), this._worldMatrix);
  581. } else {
  582. this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
  583. }
  584. } else {
  585. this._worldMatrix.copyFrom(this._localWorld);
  586. }
  587. // Bounding info
  588. this._updateBoundingInfo();
  589. // Absolute position
  590. this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
  591. // Callbacks
  592. this.onAfterWorldMatrixUpdateObservable.notifyObservers(this);
  593. if (!this._poseMatrix) {
  594. this._poseMatrix = Matrix.Invert(this._worldMatrix);
  595. }
  596. return this._worldMatrix;
  597. }
  598. /**
  599. * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
  600. * @param func: callback function to add
  601. */
  602. public registerAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void {
  603. this.onAfterWorldMatrixUpdateObservable.add(func);
  604. }
  605. public unregisterAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void {
  606. this.onAfterWorldMatrixUpdateObservable.removeCallback(func);
  607. }
  608. public setPositionWithLocalVector(vector3: Vector3): void {
  609. this.computeWorldMatrix();
  610. this.position = Vector3.TransformNormal(vector3, this._localWorld);
  611. }
  612. public getPositionExpressedInLocalSpace(): Vector3 {
  613. this.computeWorldMatrix();
  614. var invLocalWorldMatrix = this._localWorld.clone();
  615. invLocalWorldMatrix.invert();
  616. return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
  617. }
  618. public locallyTranslate(vector3: Vector3): void {
  619. this.computeWorldMatrix(true);
  620. this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
  621. }
  622. public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void {
  623. /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
  624. /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
  625. /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
  626. /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
  627. /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
  628. /// <returns>Mesh oriented towards targetMesh</returns>
  629. yawCor = yawCor || 0; // default to zero if undefined
  630. pitchCor = pitchCor || 0;
  631. rollCor = rollCor || 0;
  632. var dv = targetPoint.subtract(this.position);
  633. var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
  634. var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
  635. var pitch = Math.atan2(dv.y, len);
  636. this.rotationQuaternion = Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
  637. }
  638. public attachToBone(bone: Bone, affectedMesh: AbstractMesh): void {
  639. this._meshToBoneReferal = affectedMesh;
  640. this.parent = bone;
  641. if (bone.getWorldMatrix().determinant() < 0) {
  642. this.scalingDeterminant *= -1;
  643. }
  644. }
  645. public detachFromBone(): void {
  646. if (this.parent.getWorldMatrix().determinant() < 0) {
  647. this.scalingDeterminant *= -1;
  648. }
  649. this._meshToBoneReferal = null;
  650. this.parent = null;
  651. }
  652. public isInFrustum(frustumPlanes: Plane[]): boolean {
  653. return this._boundingInfo.isInFrustum(frustumPlanes);
  654. }
  655. public isCompletelyInFrustum(camera?: Camera): boolean {
  656. if (!camera) {
  657. camera = this.getScene().activeCamera;
  658. }
  659. var transformMatrix = camera.getViewMatrix().multiply(camera.getProjectionMatrix());
  660. if (!this._boundingInfo.isCompletelyInFrustum(Frustum.GetPlanes(transformMatrix))) {
  661. return false;
  662. }
  663. return true;
  664. }
  665. public intersectsMesh(mesh: AbstractMesh, precise?: boolean): boolean {
  666. if (!this._boundingInfo || !mesh._boundingInfo) {
  667. return false;
  668. }
  669. return this._boundingInfo.intersects(mesh._boundingInfo, precise);
  670. }
  671. public intersectsPoint(point: Vector3): boolean {
  672. if (!this._boundingInfo) {
  673. return false;
  674. }
  675. return this._boundingInfo.intersectsPoint(point);
  676. }
  677. // Physics
  678. /**
  679. * @Deprecated. Use new PhysicsImpostor instead.
  680. * */
  681. public setPhysicsState(impostor?: any, options?: PhysicsImpostorParameters): any {
  682. //legacy support
  683. if (impostor.impostor) {
  684. options = impostor;
  685. impostor = impostor.impostor;
  686. }
  687. this.physicsImpostor = new PhysicsImpostor(this, impostor, options, this.getScene());
  688. return this.physicsImpostor.physicsBody;
  689. }
  690. public getPhysicsImpostor(): PhysicsImpostor {
  691. return this.physicsImpostor;
  692. }
  693. /**
  694. * @Deprecated. Use getPhysicsImpostor().getParam("mass");
  695. */
  696. public getPhysicsMass(): number {
  697. return this.physicsImpostor.getParam("mass")
  698. }
  699. /**
  700. * @Deprecated. Use getPhysicsImpostor().getParam("friction");
  701. */
  702. public getPhysicsFriction(): number {
  703. return this.physicsImpostor.getParam("friction")
  704. }
  705. /**
  706. * @Deprecated. Use getPhysicsImpostor().getParam("restitution");
  707. */
  708. public getPhysicsRestitution(): number {
  709. return this.physicsImpostor.getParam("resitution")
  710. }
  711. public getPositionInCameraSpace(camera?: Camera): Vector3 {
  712. if (!camera) {
  713. camera = this.getScene().activeCamera;
  714. }
  715. return Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
  716. }
  717. public getDistanceToCamera(camera?: Camera): number {
  718. if (!camera) {
  719. camera = this.getScene().activeCamera;
  720. }
  721. return this.absolutePosition.subtract(camera.position).length();
  722. }
  723. public applyImpulse(force: Vector3, contactPoint: Vector3): void {
  724. if (!this.physicsImpostor) {
  725. return;
  726. }
  727. this.physicsImpostor.applyImpulse(force, contactPoint);
  728. }
  729. public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): void {
  730. if (!this.physicsImpostor || !otherMesh.physicsImpostor) {
  731. return;
  732. }
  733. this.physicsImpostor.createJoint(otherMesh.physicsImpostor, PhysicsJoint.HingeJoint, {
  734. mainPivot: pivot1,
  735. connectedPivot: pivot2,
  736. nativeParams: options
  737. })
  738. }
  739. /**
  740. * @Deprecated
  741. */
  742. public updatePhysicsBodyPosition(): void {
  743. Tools.Warn("updatePhysicsBodyPosition() is deprecated, please use updatePhysicsBody()")
  744. this.updatePhysicsBody();
  745. }
  746. /**
  747. * @Deprecated
  748. * Calling this function is not needed anymore.
  749. * The physics engine takes care of transofmration automatically.
  750. */
  751. public updatePhysicsBody(): void {
  752. //Unneeded
  753. }
  754. // Collisions
  755. public get checkCollisions(): boolean {
  756. return this._checkCollisions;
  757. }
  758. public set checkCollisions(collisionEnabled: boolean) {
  759. this._checkCollisions = collisionEnabled;
  760. if (this.getScene().workerCollisions) {
  761. this.getScene().collisionCoordinator.onMeshUpdated(this);
  762. }
  763. }
  764. public moveWithCollisions(velocity: Vector3): void {
  765. var globalPosition = this.getAbsolutePosition();
  766. globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
  767. this._oldPositionForCollisions.addInPlace(this.ellipsoidOffset);
  768. this._collider.radius = this.ellipsoid;
  769. this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, velocity, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
  770. }
  771. private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: AbstractMesh = null) => {
  772. //TODO move this to the collision coordinator!
  773. if (this.getScene().workerCollisions)
  774. newPosition.multiplyInPlace(this._collider.radius);
  775. newPosition.subtractToRef(this._oldPositionForCollisions, this._diffPositionForCollisions);
  776. if (this._diffPositionForCollisions.length() > Engine.CollisionsEpsilon) {
  777. this.position.addInPlace(this._diffPositionForCollisions);
  778. }
  779. if (collidedMesh) {
  780. this.onCollideObservable.notifyObservers(collidedMesh);
  781. }
  782. this.onCollisionPositionChangeObservable.notifyObservers(this.position);
  783. }
  784. // Submeshes octree
  785. /**
  786. * This function will create an octree to help select the right submeshes for rendering, picking and collisions
  787. * Please note that you must have a decent number of submeshes to get performance improvements when using octree
  788. */
  789. public createOrUpdateSubmeshesOctree(maxCapacity = 64, maxDepth = 2): Octree<SubMesh> {
  790. if (!this._submeshesOctree) {
  791. this._submeshesOctree = new Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
  792. }
  793. this.computeWorldMatrix(true);
  794. // Update octree
  795. var bbox = this.getBoundingInfo().boundingBox;
  796. this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
  797. return this._submeshesOctree;
  798. }
  799. // Collisions
  800. public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): void {
  801. this._generatePointsArray();
  802. // Transformation
  803. if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
  804. subMesh._lastColliderTransformMatrix = transformMatrix.clone();
  805. subMesh._lastColliderWorldVertices = [];
  806. subMesh._trianglePlanes = [];
  807. var start = subMesh.verticesStart;
  808. var end = (subMesh.verticesStart + subMesh.verticesCount);
  809. for (var i = start; i < end; i++) {
  810. subMesh._lastColliderWorldVertices.push(Vector3.TransformCoordinates(this._positions[i], transformMatrix));
  811. }
  812. }
  813. // Collide
  814. collider._collide(subMesh._trianglePlanes, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, !!subMesh.getMaterial());
  815. if (collider.collisionFound) {
  816. collider.collidedMesh = this;
  817. }
  818. }
  819. public _processCollisionsForSubMeshes(collider: Collider, transformMatrix: Matrix): void {
  820. var subMeshes: SubMesh[];
  821. var len: number;
  822. // Octrees
  823. if (this._submeshesOctree && this.useOctreeForCollisions) {
  824. var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
  825. var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
  826. len = intersections.length;
  827. subMeshes = intersections.data;
  828. } else {
  829. subMeshes = this.subMeshes;
  830. len = subMeshes.length;
  831. }
  832. for (var index = 0; index < len; index++) {
  833. var subMesh = subMeshes[index];
  834. // Bounding test
  835. if (len > 1 && !subMesh._checkCollision(collider))
  836. continue;
  837. this._collideForSubMesh(subMesh, transformMatrix, collider);
  838. }
  839. }
  840. public _checkCollision(collider: Collider): void {
  841. // Bounding box test
  842. if (!this._boundingInfo._checkCollision(collider))
  843. return;
  844. // Transformation matrix
  845. Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
  846. this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
  847. this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
  848. }
  849. // Picking
  850. public _generatePointsArray(): boolean {
  851. return false;
  852. }
  853. public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
  854. var pickingInfo = new PickingInfo();
  855. if (!this.subMeshes || !this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
  856. return pickingInfo;
  857. }
  858. if (!this._generatePointsArray()) {
  859. return pickingInfo;
  860. }
  861. var intersectInfo: IntersectionInfo = null;
  862. // Octrees
  863. var subMeshes: SubMesh[];
  864. var len: number;
  865. if (this._submeshesOctree && this.useOctreeForPicking) {
  866. var worldRay = Ray.Transform(ray, this.getWorldMatrix());
  867. var intersections = this._submeshesOctree.intersectsRay(worldRay);
  868. len = intersections.length;
  869. subMeshes = intersections.data;
  870. } else {
  871. subMeshes = this.subMeshes;
  872. len = subMeshes.length;
  873. }
  874. for (var index = 0; index < len; index++) {
  875. var subMesh = subMeshes[index];
  876. // Bounding test
  877. if (len > 1 && !subMesh.canIntersects(ray))
  878. continue;
  879. var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
  880. if (currentIntersectInfo) {
  881. if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
  882. intersectInfo = currentIntersectInfo;
  883. intersectInfo.subMeshId = index;
  884. if (fastCheck) {
  885. break;
  886. }
  887. }
  888. }
  889. }
  890. if (intersectInfo) {
  891. // Get picked point
  892. var world = this.getWorldMatrix();
  893. var worldOrigin = Vector3.TransformCoordinates(ray.origin, world);
  894. var direction = ray.direction.clone();
  895. direction = direction.scale(intersectInfo.distance);
  896. var worldDirection = Vector3.TransformNormal(direction, world);
  897. var pickedPoint = worldOrigin.add(worldDirection);
  898. // Return result
  899. pickingInfo.hit = true;
  900. pickingInfo.distance = Vector3.Distance(worldOrigin, pickedPoint);
  901. pickingInfo.pickedPoint = pickedPoint;
  902. pickingInfo.pickedMesh = this;
  903. pickingInfo.bu = intersectInfo.bu;
  904. pickingInfo.bv = intersectInfo.bv;
  905. pickingInfo.faceId = intersectInfo.faceId;
  906. pickingInfo.subMeshId = intersectInfo.subMeshId;
  907. return pickingInfo;
  908. }
  909. return pickingInfo;
  910. }
  911. public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): AbstractMesh {
  912. return null;
  913. }
  914. public releaseSubMeshes(): void {
  915. if (this.subMeshes) {
  916. while (this.subMeshes.length) {
  917. this.subMeshes[0].dispose();
  918. }
  919. } else {
  920. this.subMeshes = new Array<SubMesh>();
  921. }
  922. }
  923. public dispose(doNotRecurse?: boolean): void {
  924. var index: number;
  925. // Action manager
  926. if (this.actionManager) {
  927. this.actionManager.dispose();
  928. this.actionManager = null;
  929. }
  930. // Skeleton
  931. this.skeleton = null;
  932. // Animations
  933. this.getScene().stopAnimation(this);
  934. // Physics
  935. if (this.physicsImpostor) {
  936. this.physicsImpostor.dispose(/*!doNotRecurse*/);
  937. }
  938. // Intersections in progress
  939. for (index = 0; index < this._intersectionsInProgress.length; index++) {
  940. var other = this._intersectionsInProgress[index];
  941. var pos = other._intersectionsInProgress.indexOf(this);
  942. other._intersectionsInProgress.splice(pos, 1);
  943. }
  944. this._intersectionsInProgress = [];
  945. // Lights
  946. var lights = this.getScene().lights;
  947. lights.forEach((light: Light) => {
  948. var meshIndex = light.includedOnlyMeshes.indexOf(this);
  949. if (meshIndex !== -1) {
  950. light.includedOnlyMeshes.splice(meshIndex, 1);
  951. }
  952. meshIndex = light.excludedMeshes.indexOf(this);
  953. if (meshIndex !== -1) {
  954. light.excludedMeshes.splice(meshIndex, 1);
  955. }
  956. });
  957. // Edges
  958. if (this._edgesRenderer) {
  959. this._edgesRenderer.dispose();
  960. this._edgesRenderer = null;
  961. }
  962. // SubMeshes
  963. this.releaseSubMeshes();
  964. // Remove from scene
  965. this.getScene().removeMesh(this);
  966. if (!doNotRecurse) {
  967. // Particles
  968. for (index = 0; index < this.getScene().particleSystems.length; index++) {
  969. if (this.getScene().particleSystems[index].emitter === this) {
  970. this.getScene().particleSystems[index].dispose();
  971. index--;
  972. }
  973. }
  974. // Children
  975. var objects = this.getDescendants(true);
  976. for (index = 0; index < objects.length; index++) {
  977. objects[index].dispose();
  978. }
  979. } else {
  980. var childMeshes = this.getChildMeshes(true);
  981. for (index = 0; index < childMeshes.length; index++) {
  982. var child = childMeshes[index];
  983. child.parent = null;
  984. child.computeWorldMatrix(true);
  985. }
  986. }
  987. super.dispose();
  988. this.onAfterWorldMatrixUpdateObservable.clear();
  989. this.onCollideObservable.clear();
  990. this.onCollisionPositionChangeObservable.clear();
  991. this._isDisposed = true;
  992. // Callback
  993. this.onDisposeObservable.notifyObservers(this);
  994. this.onDisposeObservable.clear();
  995. }
  996. }
  997. }