babylon.abstractMesh.ts 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  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. // Properties
  25. public definedFacingForward = true; // orientation for POV movement & rotation
  26. public position = new Vector3(0, 0, 0);
  27. public rotation = new Vector3(0, 0, 0);
  28. public rotationQuaternion: Quaternion;
  29. public scaling = new Vector3(1, 1, 1);
  30. public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
  31. public visibility = 1.0;
  32. public alphaIndex = Number.MAX_VALUE;
  33. public infiniteDistance = false;
  34. public isVisible = true;
  35. public isPickable = true;
  36. public showBoundingBox = false;
  37. public showSubMeshesBoundingBox = false;
  38. public onDispose = null;
  39. public isBlocker = false;
  40. public skeleton: Skeleton;
  41. public renderingGroupId = 0;
  42. public material: Material;
  43. public receiveShadows = false;
  44. public actionManager: ActionManager;
  45. public renderOutline = false;
  46. public outlineColor = Color3.Red();
  47. public outlineWidth = 0.02;
  48. public renderOverlay = false;
  49. public overlayColor = Color3.Red();
  50. public overlayAlpha = 0.5;
  51. public hasVertexAlpha = false;
  52. public useVertexColors = true;
  53. public applyFog = true;
  54. public useOctreeForRenderingSelection = true;
  55. public useOctreeForPicking = true;
  56. public useOctreeForCollisions = true;
  57. public layerMask: number = 0x0FFFFFFF;
  58. public alwaysSelectAsActiveMesh = false;
  59. // Physics
  60. public _physicImpostor = PhysicsEngine.NoImpostor;
  61. public _physicsMass: number;
  62. public _physicsFriction: number;
  63. public _physicRestitution: number;
  64. // Collisions
  65. private _checkCollisions = false;
  66. public ellipsoid = new Vector3(0.5, 1, 0.5);
  67. public ellipsoidOffset = new Vector3(0, 0, 0);
  68. private _collider = new Collider();
  69. private _oldPositionForCollisions = new Vector3(0, 0, 0);
  70. private _diffPositionForCollisions = new Vector3(0, 0, 0);
  71. private _newPositionForCollisions = new Vector3(0, 0, 0);
  72. public onCollide: (collidedMesh: AbstractMesh) => void;
  73. // Attach to bone
  74. private _meshToBoneReferal: AbstractMesh;
  75. // Cache
  76. private _localScaling = Matrix.Zero();
  77. private _localRotation = Matrix.Zero();
  78. private _localTranslation = Matrix.Zero();
  79. private _localBillboard = Matrix.Zero();
  80. private _localPivotScaling = Matrix.Zero();
  81. private _localPivotScalingRotation = Matrix.Zero();
  82. private _localMeshReferalTransform: Matrix;
  83. private _localWorld = Matrix.Zero();
  84. public _worldMatrix = Matrix.Zero();
  85. private _rotateYByPI = Matrix.RotationY(Math.PI);
  86. private _absolutePosition = Vector3.Zero();
  87. private _collisionsTransformMatrix = Matrix.Zero();
  88. private _collisionsScalingMatrix = Matrix.Zero();
  89. public _positions: Vector3[];
  90. private _isDirty = false;
  91. public _masterMesh: AbstractMesh;
  92. public _boundingInfo: BoundingInfo;
  93. private _pivotMatrix = Matrix.Identity();
  94. public _isDisposed = false;
  95. public _renderId = 0;
  96. public subMeshes: SubMesh[];
  97. public _submeshesOctree: Octree<SubMesh>;
  98. public _intersectionsInProgress = new Array<AbstractMesh>();
  99. private _onAfterWorldMatrixUpdate = new Array<(mesh: AbstractMesh) => void>();
  100. private _isWorldMatrixFrozen = false;
  101. // Loading properties
  102. public _waitingActions: any;
  103. constructor(name: string, scene: Scene) {
  104. super(name, scene);
  105. scene.addMesh(this);
  106. }
  107. // Methods
  108. public get isBlocked(): boolean {
  109. return false;
  110. }
  111. public getLOD(camera: Camera): AbstractMesh {
  112. return this;
  113. }
  114. public getTotalVertices(): number {
  115. return 0;
  116. }
  117. public getIndices(): number[] {
  118. return null;
  119. }
  120. public getVerticesData(kind: string): number[] {
  121. return null;
  122. }
  123. public isVerticesDataPresent(kind: string): boolean {
  124. return false;
  125. }
  126. public getBoundingInfo(): BoundingInfo {
  127. if (this._masterMesh) {
  128. return this._masterMesh.getBoundingInfo();
  129. }
  130. if (!this._boundingInfo) {
  131. this._updateBoundingInfo();
  132. }
  133. return this._boundingInfo;
  134. }
  135. public get useBones(): boolean {
  136. return this.skeleton && this.getScene().skeletonsEnabled && this.isVerticesDataPresent(VertexBuffer.MatricesIndicesKind) && this.isVerticesDataPresent(VertexBuffer.MatricesWeightsKind);
  137. }
  138. public _preActivate(): void {
  139. }
  140. public _activate(renderId: number): void {
  141. this._renderId = renderId;
  142. }
  143. public getWorldMatrix(): Matrix {
  144. if (this._masterMesh) {
  145. return this._masterMesh.getWorldMatrix();
  146. }
  147. if (this._currentRenderId !== this.getScene().getRenderId()) {
  148. this.computeWorldMatrix();
  149. }
  150. return this._worldMatrix;
  151. }
  152. public get worldMatrixFromCache(): Matrix {
  153. return this._worldMatrix;
  154. }
  155. public get absolutePosition(): Vector3 {
  156. return this._absolutePosition;
  157. }
  158. public freezeWorldMatrix() {
  159. this._isWorldMatrixFrozen = false; // no guarantee world is not already frozen, switch off temporarily
  160. this.computeWorldMatrix(true);
  161. this._isWorldMatrixFrozen = true;
  162. }
  163. public unfreezeWorldMatrix() {
  164. this._isWorldMatrixFrozen = false;
  165. this.computeWorldMatrix(true);
  166. }
  167. public get isWorldMatrixFrozen(): boolean {
  168. return this._isWorldMatrixFrozen;
  169. }
  170. public rotate(axis: Vector3, amount: number, space: Space): void {
  171. axis.normalize();
  172. if (!this.rotationQuaternion) {
  173. this.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  174. this.rotation = Vector3.Zero();
  175. }
  176. if (!space || space === Space.LOCAL) {
  177. var rotationQuaternion = Quaternion.RotationAxis(axis, amount);
  178. this.rotationQuaternion = this.rotationQuaternion.multiply(rotationQuaternion);
  179. }
  180. else {
  181. if (this.parent) {
  182. var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
  183. invertParentWorldMatrix.invert();
  184. axis = Vector3.TransformNormal(axis, invertParentWorldMatrix);
  185. }
  186. rotationQuaternion = Quaternion.RotationAxis(axis, amount);
  187. this.rotationQuaternion = rotationQuaternion.multiply(this.rotationQuaternion);
  188. }
  189. }
  190. public translate(axis: Vector3, distance: number, space: Space): void {
  191. var displacementVector = axis.scale(distance);
  192. if (!space || space === Space.LOCAL) {
  193. var tempV3 = this.getPositionExpressedInLocalSpace().add(displacementVector);
  194. this.setPositionWithLocalVector(tempV3);
  195. }
  196. else {
  197. this.setAbsolutePosition(this.getAbsolutePosition().add(displacementVector));
  198. }
  199. }
  200. public getAbsolutePosition(): Vector3 {
  201. this.computeWorldMatrix();
  202. return this._absolutePosition;
  203. }
  204. public setAbsolutePosition(absolutePosition: Vector3): void {
  205. if (!absolutePosition) {
  206. return;
  207. }
  208. var absolutePositionX;
  209. var absolutePositionY;
  210. var absolutePositionZ;
  211. if (absolutePosition.x === undefined) {
  212. if (arguments.length < 3) {
  213. return;
  214. }
  215. absolutePositionX = arguments[0];
  216. absolutePositionY = arguments[1];
  217. absolutePositionZ = arguments[2];
  218. }
  219. else {
  220. absolutePositionX = absolutePosition.x;
  221. absolutePositionY = absolutePosition.y;
  222. absolutePositionZ = absolutePosition.z;
  223. }
  224. if (this.parent) {
  225. var invertParentWorldMatrix = this.parent.getWorldMatrix().clone();
  226. invertParentWorldMatrix.invert();
  227. var worldPosition = new Vector3(absolutePositionX, absolutePositionY, absolutePositionZ);
  228. this.position = Vector3.TransformCoordinates(worldPosition, invertParentWorldMatrix);
  229. } else {
  230. this.position.x = absolutePositionX;
  231. this.position.y = absolutePositionY;
  232. this.position.z = absolutePositionZ;
  233. }
  234. }
  235. // ================================== Point of View Movement =================================
  236. /**
  237. * Perform relative position change from the point of view of behind the front of the mesh.
  238. * This is performed taking into account the meshes current rotation, so you do not have to care.
  239. * Supports definition of mesh facing forward or backward.
  240. * @param {number} amountRight
  241. * @param {number} amountUp
  242. * @param {number} amountForward
  243. */
  244. public movePOV(amountRight: number, amountUp: number, amountForward: number): void {
  245. this.position.addInPlace(this.calcMovePOV(amountRight, amountUp, amountForward));
  246. }
  247. /**
  248. * Calculate relative position change from the point of view of behind the front of the mesh.
  249. * This is performed taking into account the meshes current rotation, so you do not have to care.
  250. * Supports definition of mesh facing forward or backward.
  251. * @param {number} amountRight
  252. * @param {number} amountUp
  253. * @param {number} amountForward
  254. */
  255. public calcMovePOV(amountRight: number, amountUp: number, amountForward: number): Vector3 {
  256. var rotMatrix = new Matrix();
  257. var rotQuaternion = (this.rotationQuaternion) ? this.rotationQuaternion : Quaternion.RotationYawPitchRoll(this.rotation.y, this.rotation.x, this.rotation.z);
  258. rotQuaternion.toRotationMatrix(rotMatrix);
  259. var translationDelta = Vector3.Zero();
  260. var defForwardMult = this.definedFacingForward ? -1 : 1;
  261. Vector3.TransformCoordinatesFromFloatsToRef(amountRight * defForwardMult, amountUp, amountForward * defForwardMult, rotMatrix, translationDelta);
  262. return translationDelta;
  263. }
  264. // ================================== Point of View Rotation =================================
  265. /**
  266. * Perform relative rotation change from the point of view of behind the front of the mesh.
  267. * Supports definition of mesh facing forward or backward.
  268. * @param {number} flipBack
  269. * @param {number} twirlClockwise
  270. * @param {number} tiltRight
  271. */
  272. public rotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): void {
  273. this.rotation.addInPlace(this.calcRotatePOV(flipBack, twirlClockwise, tiltRight));
  274. }
  275. /**
  276. * Calculate relative rotation change from the point of view of behind the front of the mesh.
  277. * Supports definition of mesh facing forward or backward.
  278. * @param {number} flipBack
  279. * @param {number} twirlClockwise
  280. * @param {number} tiltRight
  281. */
  282. public calcRotatePOV(flipBack: number, twirlClockwise: number, tiltRight: number): Vector3 {
  283. var defForwardMult = this.definedFacingForward ? 1 : -1;
  284. return new Vector3(flipBack * defForwardMult, twirlClockwise, tiltRight * defForwardMult);
  285. }
  286. public setPivotMatrix(matrix: Matrix): void {
  287. this._pivotMatrix = matrix;
  288. this._cache.pivotMatrixUpdated = true;
  289. }
  290. public getPivotMatrix(): Matrix {
  291. return this._pivotMatrix;
  292. }
  293. public _isSynchronized(): boolean {
  294. if (this._isDirty) {
  295. return false;
  296. }
  297. if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE)
  298. return false;
  299. if (this._cache.pivotMatrixUpdated) {
  300. return false;
  301. }
  302. if (this.infiniteDistance) {
  303. return false;
  304. }
  305. if (!this._cache.position.equals(this.position))
  306. return false;
  307. if (this.rotationQuaternion) {
  308. if (!this._cache.rotationQuaternion.equals(this.rotationQuaternion))
  309. return false;
  310. } else {
  311. if (!this._cache.rotation.equals(this.rotation))
  312. return false;
  313. }
  314. if (!this._cache.scaling.equals(this.scaling))
  315. return false;
  316. return true;
  317. }
  318. public _initCache() {
  319. super._initCache();
  320. this._cache.localMatrixUpdated = false;
  321. this._cache.position = Vector3.Zero();
  322. this._cache.scaling = Vector3.Zero();
  323. this._cache.rotation = Vector3.Zero();
  324. this._cache.rotationQuaternion = new Quaternion(0, 0, 0, 0);
  325. }
  326. public markAsDirty(property: string): void {
  327. if (property === "rotation") {
  328. this.rotationQuaternion = null;
  329. }
  330. this._currentRenderId = Number.MAX_VALUE;
  331. this._isDirty = true;
  332. }
  333. public _updateBoundingInfo(): void {
  334. this._boundingInfo = this._boundingInfo || new BoundingInfo(this.absolutePosition, this.absolutePosition);
  335. this._boundingInfo._update(this.worldMatrixFromCache);
  336. this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
  337. }
  338. public _updateSubMeshesBoundingInfo(matrix: Matrix): void {
  339. if (!this.subMeshes) {
  340. return;
  341. }
  342. for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
  343. var subMesh = this.subMeshes[subIndex];
  344. subMesh.updateBoundingInfo(matrix);
  345. }
  346. }
  347. public computeWorldMatrix(force?: boolean): Matrix {
  348. if (this._isWorldMatrixFrozen) {
  349. return this._worldMatrix;
  350. }
  351. if (!force && (this._currentRenderId === this.getScene().getRenderId() || this.isSynchronized(true))) {
  352. return this._worldMatrix;
  353. }
  354. this._cache.position.copyFrom(this.position);
  355. this._cache.scaling.copyFrom(this.scaling);
  356. this._cache.pivotMatrixUpdated = false;
  357. this._currentRenderId = this.getScene().getRenderId();
  358. this._isDirty = false;
  359. // Scaling
  360. Matrix.ScalingToRef(this.scaling.x, this.scaling.y, this.scaling.z, this._localScaling);
  361. // Rotation
  362. if (this.rotationQuaternion) {
  363. this.rotationQuaternion.toRotationMatrix(this._localRotation);
  364. this._cache.rotationQuaternion.copyFrom(this.rotationQuaternion);
  365. } else {
  366. Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._localRotation);
  367. this._cache.rotation.copyFrom(this.rotation);
  368. }
  369. // Translation
  370. if (this.infiniteDistance && !this.parent) {
  371. var camera = this.getScene().activeCamera;
  372. var cameraWorldMatrix = camera.getWorldMatrix();
  373. var cameraGlobalPosition = new Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
  374. Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
  375. this.position.z + cameraGlobalPosition.z, this._localTranslation);
  376. } else {
  377. Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
  378. }
  379. // Composing transformations
  380. this._pivotMatrix.multiplyToRef(this._localScaling, this._localPivotScaling);
  381. this._localPivotScaling.multiplyToRef(this._localRotation, this._localPivotScalingRotation);
  382. // Billboarding
  383. if (this.billboardMode !== AbstractMesh.BILLBOARDMODE_NONE && this.getScene().activeCamera) {
  384. var localPosition = this.position.clone();
  385. var zero = this.getScene().activeCamera.globalPosition.clone();
  386. if (this.parent && (<any>this.parent).position) {
  387. localPosition.addInPlace((<any>this.parent).position);
  388. Matrix.TranslationToRef(localPosition.x, localPosition.y, localPosition.z, this._localTranslation);
  389. }
  390. if ((this.billboardMode & AbstractMesh.BILLBOARDMODE_ALL) != AbstractMesh.BILLBOARDMODE_ALL) {
  391. if (this.billboardMode & AbstractMesh.BILLBOARDMODE_X)
  392. zero.x = localPosition.x + Engine.Epsilon;
  393. if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Y)
  394. zero.y = localPosition.y + 0.001;
  395. if (this.billboardMode & AbstractMesh.BILLBOARDMODE_Z)
  396. zero.z = localPosition.z + 0.001;
  397. }
  398. Matrix.LookAtLHToRef(localPosition, zero, Vector3.Up(), this._localBillboard);
  399. this._localBillboard.m[12] = this._localBillboard.m[13] = this._localBillboard.m[14] = 0;
  400. this._localBillboard.invert();
  401. this._localPivotScalingRotation.multiplyToRef(this._localBillboard, this._localWorld);
  402. this._rotateYByPI.multiplyToRef(this._localWorld, this._localPivotScalingRotation);
  403. }
  404. // Local world
  405. this._localPivotScalingRotation.multiplyToRef(this._localTranslation, this._localWorld);
  406. // Parent
  407. if (this.parent && this.parent.getWorldMatrix && this.billboardMode === AbstractMesh.BILLBOARDMODE_NONE) {
  408. this._markSyncedWithParent();
  409. if (this._meshToBoneReferal) {
  410. if (!this._localMeshReferalTransform) {
  411. this._localMeshReferalTransform = Matrix.Zero();
  412. }
  413. this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._localMeshReferalTransform);
  414. this._localMeshReferalTransform.multiplyToRef(this._meshToBoneReferal.getWorldMatrix(), this._worldMatrix);
  415. } else {
  416. this._localWorld.multiplyToRef(this.parent.getWorldMatrix(), this._worldMatrix);
  417. }
  418. } else {
  419. this._worldMatrix.copyFrom(this._localWorld);
  420. }
  421. // Bounding info
  422. this._updateBoundingInfo();
  423. // Absolute position
  424. this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
  425. // Callbacks
  426. for (var callbackIndex = 0; callbackIndex < this._onAfterWorldMatrixUpdate.length; callbackIndex++) {
  427. this._onAfterWorldMatrixUpdate[callbackIndex](this);
  428. }
  429. return this._worldMatrix;
  430. }
  431. /**
  432. * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
  433. * @param func: callback function to add
  434. */
  435. public registerAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void {
  436. this._onAfterWorldMatrixUpdate.push(func);
  437. }
  438. public unregisterAfterWorldMatrixUpdate(func: (mesh: AbstractMesh) => void): void {
  439. var index = this._onAfterWorldMatrixUpdate.indexOf(func);
  440. if (index > -1) {
  441. this._onAfterWorldMatrixUpdate.splice(index, 1);
  442. }
  443. }
  444. public setPositionWithLocalVector(vector3: Vector3): void {
  445. this.computeWorldMatrix();
  446. this.position = Vector3.TransformNormal(vector3, this._localWorld);
  447. }
  448. public getPositionExpressedInLocalSpace(): Vector3 {
  449. this.computeWorldMatrix();
  450. var invLocalWorldMatrix = this._localWorld.clone();
  451. invLocalWorldMatrix.invert();
  452. return Vector3.TransformNormal(this.position, invLocalWorldMatrix);
  453. }
  454. public locallyTranslate(vector3: Vector3): void {
  455. this.computeWorldMatrix(true);
  456. this.position = Vector3.TransformCoordinates(vector3, this._localWorld);
  457. }
  458. public lookAt(targetPoint: Vector3, yawCor: number, pitchCor: number, rollCor: number): void {
  459. /// <summary>Orients a mesh towards a target point. Mesh must be drawn facing user.</summary>
  460. /// <param name="targetPoint" type="Vector3">The position (must be in same space as current mesh) to look at</param>
  461. /// <param name="yawCor" type="Number">optional yaw (y-axis) correction in radians</param>
  462. /// <param name="pitchCor" type="Number">optional pitch (x-axis) correction in radians</param>
  463. /// <param name="rollCor" type="Number">optional roll (z-axis) correction in radians</param>
  464. /// <returns>Mesh oriented towards targetMesh</returns>
  465. yawCor = yawCor || 0; // default to zero if undefined
  466. pitchCor = pitchCor || 0;
  467. rollCor = rollCor || 0;
  468. var dv = targetPoint.subtract(this.position);
  469. var yaw = -Math.atan2(dv.z, dv.x) - Math.PI / 2;
  470. var len = Math.sqrt(dv.x * dv.x + dv.z * dv.z);
  471. var pitch = Math.atan2(dv.y, len);
  472. this.rotationQuaternion = Quaternion.RotationYawPitchRoll(yaw + yawCor, pitch + pitchCor, rollCor);
  473. }
  474. public attachToBone(bone: Bone, affectedMesh: AbstractMesh): void {
  475. this._meshToBoneReferal = affectedMesh;
  476. this.parent = bone;
  477. }
  478. public detachFromBone(): void {
  479. this._meshToBoneReferal = null;
  480. this.parent = null;
  481. }
  482. public isInFrustum(frustumPlanes: Plane[]): boolean {
  483. return this._boundingInfo.isInFrustum(frustumPlanes);
  484. }
  485. public isCompletelyInFrustum(camera?: Camera): boolean {
  486. if (!camera) {
  487. camera = this.getScene().activeCamera;
  488. }
  489. var transformMatrix = camera.getViewMatrix().multiply(camera.getProjectionMatrix());
  490. if (!this._boundingInfo.isCompletelyInFrustum(Frustum.GetPlanes(transformMatrix))) {
  491. return false;
  492. }
  493. return true;
  494. }
  495. public intersectsMesh(mesh: AbstractMesh, precise?: boolean): boolean {
  496. if (!this._boundingInfo || !mesh._boundingInfo) {
  497. return false;
  498. }
  499. return this._boundingInfo.intersects(mesh._boundingInfo, precise);
  500. }
  501. public intersectsPoint(point: Vector3): boolean {
  502. if (!this._boundingInfo) {
  503. return false;
  504. }
  505. return this._boundingInfo.intersectsPoint(point);
  506. }
  507. // Physics
  508. public setPhysicsState(impostor?: any, options?: PhysicsBodyCreationOptions): any {
  509. var physicsEngine = this.getScene().getPhysicsEngine();
  510. if (!physicsEngine) {
  511. return;
  512. }
  513. impostor = impostor || PhysicsEngine.NoImpostor;
  514. if (impostor.impostor) {
  515. // Old API
  516. options = impostor;
  517. impostor = impostor.impostor;
  518. }
  519. if (impostor === PhysicsEngine.NoImpostor) {
  520. physicsEngine._unregisterMesh(this);
  521. return;
  522. }
  523. if (!options) {
  524. options = { mass: 0, friction: 0.2, restitution: 0.2 };
  525. } else {
  526. if (!options.mass && options.mass !== 0) options.mass = 0;
  527. if (!options.friction && options.friction !== 0) options.friction = 0.2;
  528. if (!options.restitution && options.restitution !== 0) options.restitution = 0.2;
  529. }
  530. this._physicImpostor = impostor;
  531. this._physicsMass = options.mass;
  532. this._physicsFriction = options.friction;
  533. this._physicRestitution = options.restitution;
  534. return physicsEngine._registerMesh(this, impostor, options);
  535. }
  536. public getPhysicsImpostor(): number {
  537. if (!this._physicImpostor) {
  538. return PhysicsEngine.NoImpostor;
  539. }
  540. return this._physicImpostor;
  541. }
  542. public getPhysicsMass(): number {
  543. if (!this._physicsMass) {
  544. return 0;
  545. }
  546. return this._physicsMass;
  547. }
  548. public getPhysicsFriction(): number {
  549. if (!this._physicsFriction) {
  550. return 0;
  551. }
  552. return this._physicsFriction;
  553. }
  554. public getPhysicsRestitution(): number {
  555. if (!this._physicRestitution) {
  556. return 0;
  557. }
  558. return this._physicRestitution;
  559. }
  560. public getPositionInCameraSpace(camera?: Camera): Vector3 {
  561. if (!camera) {
  562. camera = this.getScene().activeCamera;
  563. }
  564. return Vector3.TransformCoordinates(this.absolutePosition, camera.getViewMatrix());
  565. }
  566. public getDistanceToCamera(camera?: Camera): number {
  567. if (!camera) {
  568. camera = this.getScene().activeCamera;
  569. }
  570. return this.absolutePosition.subtract(camera.position).length();
  571. }
  572. public applyImpulse(force: Vector3, contactPoint: Vector3): void {
  573. if (!this._physicImpostor) {
  574. return;
  575. }
  576. this.getScene().getPhysicsEngine()._applyImpulse(this, force, contactPoint);
  577. }
  578. public setPhysicsLinkWith(otherMesh: Mesh, pivot1: Vector3, pivot2: Vector3, options?: any): void {
  579. if (!this._physicImpostor) {
  580. return;
  581. }
  582. this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2, options);
  583. }
  584. public updatePhysicsBodyPosition(): void {
  585. if (!this._physicImpostor) {
  586. return;
  587. }
  588. this.getScene().getPhysicsEngine()._updateBodyPosition(this);
  589. }
  590. // Collisions
  591. public get checkCollisions() : boolean {
  592. return this._checkCollisions;
  593. }
  594. public set checkCollisions(collisionEnabled: boolean) {
  595. this._checkCollisions = collisionEnabled;
  596. if (this.getScene().workerCollisions) {
  597. this.getScene().collisionCoordinator.onMeshUpdated(this);
  598. }
  599. }
  600. public moveWithCollisions(velocity: Vector3): void {
  601. var globalPosition = this.getAbsolutePosition();
  602. globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
  603. this._oldPositionForCollisions.addInPlace(this.ellipsoidOffset);
  604. this._collider.radius = this.ellipsoid;
  605. this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, velocity, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
  606. }
  607. private _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: AbstractMesh = null) => {
  608. //TODO move this to the collision coordinator!
  609. if (this.getScene().workerCollisions)
  610. newPosition.multiplyInPlace(this._collider.radius);
  611. newPosition.subtractToRef(this._oldPositionForCollisions, this._diffPositionForCollisions);
  612. if (this._diffPositionForCollisions.length() > Engine.CollisionsEpsilon) {
  613. this.position.addInPlace(this._diffPositionForCollisions);
  614. }
  615. if (this.onCollide && collidedMesh) {
  616. this.onCollide(collidedMesh);
  617. }
  618. }
  619. // Submeshes octree
  620. /**
  621. * This function will create an octree to help select the right submeshes for rendering, picking and collisions
  622. * Please note that you must have a decent number of submeshes to get performance improvements when using octree
  623. */
  624. public createOrUpdateSubmeshesOctree(maxCapacity = 64, maxDepth = 2): Octree<SubMesh> {
  625. if (!this._submeshesOctree) {
  626. this._submeshesOctree = new Octree<SubMesh>(Octree.CreationFuncForSubMeshes, maxCapacity, maxDepth);
  627. }
  628. this.computeWorldMatrix(true);
  629. // Update octree
  630. var bbox = this.getBoundingInfo().boundingBox;
  631. this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
  632. return this._submeshesOctree;
  633. }
  634. // Collisions
  635. public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): void {
  636. this._generatePointsArray();
  637. // Transformation
  638. if (!subMesh._lastColliderWorldVertices || !subMesh._lastColliderTransformMatrix.equals(transformMatrix)) {
  639. subMesh._lastColliderTransformMatrix = transformMatrix.clone();
  640. subMesh._lastColliderWorldVertices = [];
  641. subMesh._trianglePlanes = [];
  642. var start = subMesh.verticesStart;
  643. var end = (subMesh.verticesStart + subMesh.verticesCount);
  644. for (var i = start; i < end; i++) {
  645. subMesh._lastColliderWorldVertices.push(Vector3.TransformCoordinates(this._positions[i], transformMatrix));
  646. }
  647. }
  648. // Collide
  649. collider._collide(subMesh._trianglePlanes, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, !!subMesh.getMaterial());
  650. if (collider.collisionFound) {
  651. collider.collidedMesh = this;
  652. }
  653. }
  654. public _processCollisionsForSubMeshes(collider: Collider, transformMatrix: Matrix): void {
  655. var subMeshes: SubMesh[];
  656. var len: number;
  657. // Octrees
  658. if (this._submeshesOctree && this.useOctreeForCollisions) {
  659. var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
  660. var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
  661. len = intersections.length;
  662. subMeshes = intersections.data;
  663. } else {
  664. subMeshes = this.subMeshes;
  665. len = subMeshes.length;
  666. }
  667. for (var index = 0; index < len; index++) {
  668. var subMesh = subMeshes[index];
  669. // Bounding test
  670. if (len > 1 && !subMesh._checkCollision(collider))
  671. continue;
  672. this._collideForSubMesh(subMesh, transformMatrix, collider);
  673. }
  674. }
  675. public _checkCollision(collider: Collider): void {
  676. // Bounding box test
  677. if (!this._boundingInfo._checkCollision(collider))
  678. return;
  679. // Transformation matrix
  680. Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
  681. this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
  682. this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
  683. }
  684. // Picking
  685. public _generatePointsArray(): boolean {
  686. return false;
  687. }
  688. public intersects(ray: Ray, fastCheck?: boolean): PickingInfo {
  689. var pickingInfo = new PickingInfo();
  690. if (!this.subMeshes || !this._boundingInfo || !ray.intersectsSphere(this._boundingInfo.boundingSphere) || !ray.intersectsBox(this._boundingInfo.boundingBox)) {
  691. return pickingInfo;
  692. }
  693. if (!this._generatePointsArray()) {
  694. return pickingInfo;
  695. }
  696. var intersectInfo: IntersectionInfo = null;
  697. // Octrees
  698. var subMeshes: SubMesh[];
  699. var len: number;
  700. if (this._submeshesOctree && this.useOctreeForPicking) {
  701. var worldRay = Ray.Transform(ray, this.getWorldMatrix());
  702. var intersections = this._submeshesOctree.intersectsRay(worldRay);
  703. len = intersections.length;
  704. subMeshes = intersections.data;
  705. } else {
  706. subMeshes = this.subMeshes;
  707. len = subMeshes.length;
  708. }
  709. for (var index = 0; index < len; index++) {
  710. var subMesh = subMeshes[index];
  711. // Bounding test
  712. if (len > 1 && !subMesh.canIntersects(ray))
  713. continue;
  714. var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);
  715. if (currentIntersectInfo) {
  716. if (fastCheck || !intersectInfo || currentIntersectInfo.distance < intersectInfo.distance) {
  717. intersectInfo = currentIntersectInfo;
  718. intersectInfo.subMeshId = index;
  719. if (fastCheck) {
  720. break;
  721. }
  722. }
  723. }
  724. }
  725. if (intersectInfo) {
  726. // Get picked point
  727. var world = this.getWorldMatrix();
  728. var worldOrigin = Vector3.TransformCoordinates(ray.origin, world);
  729. var direction = ray.direction.clone();
  730. direction = direction.scale(intersectInfo.distance);
  731. var worldDirection = Vector3.TransformNormal(direction, world);
  732. var pickedPoint = worldOrigin.add(worldDirection);
  733. // Return result
  734. pickingInfo.hit = true;
  735. pickingInfo.distance = Vector3.Distance(worldOrigin, pickedPoint);
  736. pickingInfo.pickedPoint = pickedPoint;
  737. pickingInfo.pickedMesh = this;
  738. pickingInfo.bu = intersectInfo.bu;
  739. pickingInfo.bv = intersectInfo.bv;
  740. pickingInfo.faceId = intersectInfo.faceId;
  741. pickingInfo.subMeshId = intersectInfo.subMeshId;
  742. return pickingInfo;
  743. }
  744. return pickingInfo;
  745. }
  746. public clone(name: string, newParent: Node, doNotCloneChildren?: boolean): AbstractMesh {
  747. return null;
  748. }
  749. public releaseSubMeshes(): void {
  750. if (this.subMeshes) {
  751. while (this.subMeshes.length) {
  752. this.subMeshes[0].dispose();
  753. }
  754. } else {
  755. this.subMeshes = new Array<SubMesh>();
  756. }
  757. }
  758. public dispose(doNotRecurse?: boolean): void {
  759. var index: number;
  760. // Physics
  761. if (this.getPhysicsImpostor() !== PhysicsEngine.NoImpostor) {
  762. this.setPhysicsState(PhysicsEngine.NoImpostor);
  763. }
  764. // Intersections in progress
  765. for (index = 0; index < this._intersectionsInProgress.length; index++) {
  766. var other = this._intersectionsInProgress[index];
  767. var pos = other._intersectionsInProgress.indexOf(this);
  768. other._intersectionsInProgress.splice(pos, 1);
  769. }
  770. this._intersectionsInProgress = [];
  771. // SubMeshes
  772. this.releaseSubMeshes();
  773. // Remove from scene
  774. this.getScene().removeMesh(this);
  775. if (!doNotRecurse) {
  776. // Particles
  777. for (index = 0; index < this.getScene().particleSystems.length; index++) {
  778. if (this.getScene().particleSystems[index].emitter === this) {
  779. this.getScene().particleSystems[index].dispose();
  780. index--;
  781. }
  782. }
  783. // Children
  784. var objects = this.getScene().meshes.slice(0);
  785. for (index = 0; index < objects.length; index++) {
  786. if (objects[index].parent === this) {
  787. objects[index].dispose();
  788. }
  789. }
  790. } else {
  791. for (index = 0; index < this.getScene().meshes.length; index++) {
  792. var obj = this.getScene().meshes[index];
  793. if (obj.parent === this) {
  794. obj.parent = null;
  795. obj.computeWorldMatrix(true);
  796. }
  797. }
  798. }
  799. this._onAfterWorldMatrixUpdate = [];
  800. this._isDisposed = true;
  801. // Callback
  802. if (this.onDispose) {
  803. this.onDispose();
  804. }
  805. }
  806. }
  807. }