physicsImpostor.ts 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269
  1. import { Nullable, IndicesArray } from "../types";
  2. import { Logger } from "../Misc/logger";
  3. import { ArrayTools } from "../Misc/arrayTools";
  4. import { Vector3, Matrix, Quaternion, Space } from "../Maths/math";
  5. import { TransformNode } from "../Meshes/transformNode";
  6. import { AbstractMesh } from "../Meshes/abstractMesh";
  7. import { Mesh } from "../Meshes/mesh";
  8. import { Scene } from "../scene";
  9. import { Bone } from "../Bones/bone";
  10. import { BoundingInfo } from "../Culling/boundingInfo";
  11. import { IPhysicsEngine } from "./IPhysicsEngine";
  12. import { PhysicsJoint, PhysicsJointData } from "./physicsJoint";
  13. /**
  14. * The interface for the physics imposter parameters
  15. * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  16. */
  17. export interface PhysicsImpostorParameters {
  18. /**
  19. * The mass of the physics imposter
  20. */
  21. mass: number;
  22. /**
  23. * The friction of the physics imposter
  24. */
  25. friction?: number;
  26. /**
  27. * The coefficient of restitution of the physics imposter
  28. */
  29. restitution?: number;
  30. /**
  31. * The native options of the physics imposter
  32. */
  33. nativeOptions?: any;
  34. /**
  35. * Specifies if the parent should be ignored
  36. */
  37. ignoreParent?: boolean;
  38. /**
  39. * Specifies if bi-directional transformations should be disabled
  40. */
  41. disableBidirectionalTransformation?: boolean;
  42. /**
  43. * The pressure inside the physics imposter, soft object only
  44. */
  45. pressure?: number;
  46. /**
  47. * The stiffness the physics imposter, soft object only
  48. */
  49. stiffness?: number;
  50. /**
  51. * The number of iterations used in maintaining consistent vertex velocities, soft object only
  52. */
  53. velocityIterations?: number;
  54. /**
  55. * The number of iterations used in maintaining consistent vertex positions, soft object only
  56. */
  57. positionIterations?: number;
  58. /**
  59. * The number used to fix points on a cloth (0, 1, 2, 4, 8) or rope (0, 1, 2) only
  60. * 0 None, 1, back left or top, 2, back right or bottom, 4, front left, 8, front right
  61. * Add to fix multiple points
  62. */
  63. fixedPoints?: number;
  64. /**
  65. * The collision margin around a soft object
  66. */
  67. margin?: number;
  68. /**
  69. * The collision margin around a soft object
  70. */
  71. damping?: number;
  72. /**
  73. * The path for a rope based on an extrusion
  74. */
  75. path?: any;
  76. /**
  77. * The shape of an extrusion used for a rope based on an extrusion
  78. */
  79. shape?: any;
  80. }
  81. /**
  82. * Interface for a physics-enabled object
  83. * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  84. */
  85. export interface IPhysicsEnabledObject {
  86. /**
  87. * The position of the physics-enabled object
  88. */
  89. position: Vector3;
  90. /**
  91. * The rotation of the physics-enabled object
  92. */
  93. rotationQuaternion: Nullable<Quaternion>;
  94. /**
  95. * The scale of the physics-enabled object
  96. */
  97. scaling: Vector3;
  98. /**
  99. * The rotation of the physics-enabled object
  100. */
  101. rotation?: Vector3;
  102. /**
  103. * The parent of the physics-enabled object
  104. */
  105. parent?: any;
  106. /**
  107. * The bounding info of the physics-enabled object
  108. * @returns The bounding info of the physics-enabled object
  109. */
  110. getBoundingInfo(): BoundingInfo;
  111. /**
  112. * Computes the world matrix
  113. * @param force Specifies if the world matrix should be computed by force
  114. * @returns A world matrix
  115. */
  116. computeWorldMatrix(force: boolean): Matrix;
  117. /**
  118. * Gets the world matrix
  119. * @returns A world matrix
  120. */
  121. getWorldMatrix?(): Matrix;
  122. /**
  123. * Gets the child meshes
  124. * @param directDescendantsOnly Specifies if only direct-descendants should be obtained
  125. * @returns An array of abstract meshes
  126. */
  127. getChildMeshes?(directDescendantsOnly?: boolean): Array<AbstractMesh>;
  128. /**
  129. * Gets the vertex data
  130. * @param kind The type of vertex data
  131. * @returns A nullable array of numbers, or a float32 array
  132. */
  133. getVerticesData(kind: string): Nullable<Array<number> | Float32Array>;
  134. /**
  135. * Gets the indices from the mesh
  136. * @returns A nullable array of index arrays
  137. */
  138. getIndices?(): Nullable<IndicesArray>;
  139. /**
  140. * Gets the scene from the mesh
  141. * @returns the indices array or null
  142. */
  143. getScene?(): Scene;
  144. /**
  145. * Gets the absolute position from the mesh
  146. * @returns the absolute position
  147. */
  148. getAbsolutePosition(): Vector3;
  149. /**
  150. * Gets the absolute pivot point from the mesh
  151. * @returns the absolute pivot point
  152. */
  153. getAbsolutePivotPoint(): Vector3;
  154. /**
  155. * Rotates the mesh
  156. * @param axis The axis of rotation
  157. * @param amount The amount of rotation
  158. * @param space The space of the rotation
  159. * @returns The rotation transform node
  160. */
  161. rotate(axis: Vector3, amount: number, space?: Space): TransformNode;
  162. /**
  163. * Translates the mesh
  164. * @param axis The axis of translation
  165. * @param distance The distance of translation
  166. * @param space The space of the translation
  167. * @returns The transform node
  168. */
  169. translate(axis: Vector3, distance: number, space?: Space): TransformNode;
  170. /**
  171. * Sets the absolute position of the mesh
  172. * @param absolutePosition The absolute position of the mesh
  173. * @returns The transform node
  174. */
  175. setAbsolutePosition(absolutePosition: Vector3): TransformNode;
  176. /**
  177. * Gets the class name of the mesh
  178. * @returns The class name
  179. */
  180. getClassName(): string;
  181. }
  182. Mesh._PhysicsImpostorParser = function(scene: Scene, physicObject: IPhysicsEnabledObject, jsonObject: any): PhysicsImpostor {
  183. return new PhysicsImpostor(physicObject, jsonObject.physicsImpostor, {
  184. mass: jsonObject.physicsMass,
  185. friction: jsonObject.physicsFriction,
  186. restitution: jsonObject.physicsRestitution
  187. }, scene);
  188. };
  189. /**
  190. * Represents a physics imposter
  191. * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  192. */
  193. export class PhysicsImpostor {
  194. /**
  195. * The default object size of the imposter
  196. */
  197. public static DEFAULT_OBJECT_SIZE: Vector3 = new Vector3(1, 1, 1);
  198. /**
  199. * The identity quaternion of the imposter
  200. */
  201. public static IDENTITY_QUATERNION = Quaternion.Identity();
  202. /** @hidden */
  203. public _pluginData: any = {};
  204. private _physicsEngine: Nullable<IPhysicsEngine>;
  205. //The native cannon/oimo/energy physics body object.
  206. private _physicsBody: any;
  207. private _bodyUpdateRequired: boolean = false;
  208. private _onBeforePhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
  209. private _onAfterPhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
  210. /** @hidden */
  211. public _onPhysicsCollideCallbacks: Array<{ callback: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void, otherImpostors: Array<PhysicsImpostor> }> = [];
  212. private _deltaPosition: Vector3 = Vector3.Zero();
  213. private _deltaRotation: Quaternion;
  214. private _deltaRotationConjugated: Quaternion;
  215. /** hidden */
  216. public _isFromLine: boolean;
  217. //If set, this is this impostor's parent
  218. private _parent: Nullable<PhysicsImpostor>;
  219. private _isDisposed = false;
  220. private static _tmpVecs: Vector3[] = ArrayTools.BuildArray(3, Vector3.Zero);
  221. private static _tmpQuat: Quaternion = Quaternion.Identity();
  222. /**
  223. * Specifies if the physics imposter is disposed
  224. */
  225. get isDisposed(): boolean {
  226. return this._isDisposed;
  227. }
  228. /**
  229. * Gets the mass of the physics imposter
  230. */
  231. get mass(): number {
  232. return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getBodyMass(this) : 0;
  233. }
  234. set mass(value: number) {
  235. this.setMass(value);
  236. }
  237. /**
  238. * Gets the coefficient of friction
  239. */
  240. get friction(): number {
  241. return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getBodyFriction(this) : 0;
  242. }
  243. /**
  244. * Sets the coefficient of friction
  245. */
  246. set friction(value: number) {
  247. if (!this._physicsEngine) {
  248. return;
  249. }
  250. this._physicsEngine.getPhysicsPlugin().setBodyFriction(this, value);
  251. }
  252. /**
  253. * Gets the coefficient of restitution
  254. */
  255. get restitution(): number {
  256. return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getBodyRestitution(this) : 0;
  257. }
  258. /**
  259. * Sets the coefficient of restitution
  260. */
  261. set restitution(value: number) {
  262. if (!this._physicsEngine) {
  263. return;
  264. }
  265. this._physicsEngine.getPhysicsPlugin().setBodyRestitution(this, value);
  266. }
  267. /**
  268. * Gets the pressure of a soft body; only supported by the AmmoJSPlugin
  269. */
  270. get pressure(): number {
  271. if (!this._physicsEngine) {
  272. return 0;
  273. }
  274. const plugin = this._physicsEngine.getPhysicsPlugin();
  275. if (!plugin .setBodyPressure) {
  276. return 0;
  277. }
  278. return plugin.getBodyPressure!(this);
  279. }
  280. /**
  281. * Sets the pressure of a soft body; only supported by the AmmoJSPlugin
  282. */
  283. set pressure(value: number) {
  284. if (!this._physicsEngine) {
  285. return;
  286. }
  287. const plugin = this._physicsEngine.getPhysicsPlugin();
  288. if (!plugin.setBodyPressure) {
  289. return;
  290. }
  291. plugin.setBodyPressure!(this, value);
  292. }
  293. /**
  294. * Gets the stiffness of a soft body; only supported by the AmmoJSPlugin
  295. */
  296. get stiffness(): number {
  297. if (!this._physicsEngine) {
  298. return 0;
  299. }
  300. const plugin = this._physicsEngine.getPhysicsPlugin();
  301. if (!plugin.getBodyStiffness) {
  302. return 0;
  303. }
  304. return plugin.getBodyStiffness!(this);
  305. }
  306. /**
  307. * Sets the stiffness of a soft body; only supported by the AmmoJSPlugin
  308. */
  309. set stiffness(value: number) {
  310. if (!this._physicsEngine) {
  311. return;
  312. }
  313. const plugin = this._physicsEngine.getPhysicsPlugin();
  314. if (!plugin.setBodyStiffness) {
  315. return;
  316. }
  317. plugin.setBodyStiffness!(this, value);
  318. }
  319. /**
  320. * Gets the velocityIterations of a soft body; only supported by the AmmoJSPlugin
  321. */
  322. get velocityIterations(): number {
  323. if (!this._physicsEngine) {
  324. return 0;
  325. }
  326. const plugin = this._physicsEngine.getPhysicsPlugin();
  327. if (!plugin.getBodyVelocityIterations) {
  328. return 0;
  329. }
  330. return plugin.getBodyVelocityIterations!(this);
  331. }
  332. /**
  333. * Sets the velocityIterations of a soft body; only supported by the AmmoJSPlugin
  334. */
  335. set velocityIterations(value: number) {
  336. if (!this._physicsEngine) {
  337. return;
  338. }
  339. const plugin = this._physicsEngine.getPhysicsPlugin();
  340. if (!plugin.setBodyVelocityIterations) {
  341. return;
  342. }
  343. plugin.setBodyVelocityIterations!(this, value);
  344. }
  345. /**
  346. * Gets the positionIterations of a soft body; only supported by the AmmoJSPlugin
  347. */
  348. get positionIterations(): number {
  349. if (!this._physicsEngine) {
  350. return 0;
  351. }
  352. const plugin = this._physicsEngine.getPhysicsPlugin();
  353. if (!plugin.getBodyPositionIterations) {
  354. return 0;
  355. }
  356. return plugin.getBodyPositionIterations!(this);
  357. }
  358. /**
  359. * Sets the positionIterations of a soft body; only supported by the AmmoJSPlugin
  360. */
  361. set positionIterations(value: number) {
  362. if (!this._physicsEngine) {
  363. return;
  364. }
  365. const plugin = this._physicsEngine.getPhysicsPlugin();
  366. if (!plugin.setBodyPositionIterations) {
  367. return;
  368. }
  369. plugin.setBodyPositionIterations!(this, value);
  370. }
  371. /**
  372. * The unique id of the physics imposter
  373. * set by the physics engine when adding this impostor to the array
  374. */
  375. public uniqueId: number;
  376. /**
  377. * @hidden
  378. */
  379. public soft: boolean = false;
  380. /**
  381. * @hidden
  382. */
  383. public segments: number = 0;
  384. private _joints: Array<{
  385. joint: PhysicsJoint,
  386. otherImpostor: PhysicsImpostor
  387. }>;
  388. /**
  389. * Initializes the physics imposter
  390. * @param object The physics-enabled object used as the physics imposter
  391. * @param type The type of the physics imposter
  392. * @param _options The options for the physics imposter
  393. * @param _scene The Babylon scene
  394. */
  395. constructor(
  396. /**
  397. * The physics-enabled object used as the physics imposter
  398. */
  399. public object: IPhysicsEnabledObject,
  400. /**
  401. * The type of the physics imposter
  402. */
  403. public type: number, private _options: PhysicsImpostorParameters = { mass: 0 }, private _scene?: Scene) {
  404. //sanity check!
  405. if (!this.object) {
  406. Logger.Error("No object was provided. A physics object is obligatory");
  407. return;
  408. }
  409. // Legacy support for old syntax.
  410. if (!this._scene && object.getScene) {
  411. this._scene = object.getScene();
  412. }
  413. if (!this._scene) {
  414. return;
  415. }
  416. if (this.type > 100) {
  417. this.soft = true;
  418. }
  419. this._physicsEngine = this._scene.getPhysicsEngine();
  420. if (!this._physicsEngine) {
  421. Logger.Error("Physics not enabled. Please use scene.enablePhysics(...) before creating impostors.");
  422. } else {
  423. //set the object's quaternion, if not set
  424. if (!this.object.rotationQuaternion) {
  425. if (this.object.rotation) {
  426. this.object.rotationQuaternion = Quaternion.RotationYawPitchRoll(this.object.rotation.y, this.object.rotation.x, this.object.rotation.z);
  427. } else {
  428. this.object.rotationQuaternion = new Quaternion();
  429. }
  430. }
  431. //default options params
  432. this._options.mass = (_options.mass === void 0) ? 0 : _options.mass;
  433. this._options.friction = (_options.friction === void 0) ? 0.2 : _options.friction;
  434. this._options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution;
  435. if (this.soft) {
  436. //softbody mass must be above 0;
  437. this._options.mass = this._options.mass > 0 ? this._options.mass : 1;
  438. this._options.pressure = (_options.pressure === void 0) ? 200 : _options.pressure;
  439. this._options.stiffness = (_options.stiffness === void 0) ? 1 : _options.stiffness;
  440. this._options.velocityIterations = (_options.velocityIterations === void 0) ? 20 : _options.velocityIterations;
  441. this._options.positionIterations = (_options.positionIterations === void 0) ? 20 : _options.positionIterations;
  442. this._options.fixedPoints = (_options.fixedPoints === void 0) ? 0 : _options.fixedPoints;
  443. this._options.margin = (_options.margin === void 0) ? 0 : _options.margin;
  444. this._options.damping = (_options.damping === void 0) ? 0 : _options.damping;
  445. this._options.path = (_options.path === void 0) ? null : _options.path;
  446. this._options.shape = (_options.shape === void 0) ? null : _options.shape;
  447. }
  448. this._joints = [];
  449. //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
  450. if (!this.object.parent || this._options.ignoreParent) {
  451. this._init();
  452. } else if (this.object.parent.physicsImpostor) {
  453. Logger.Warn("You must affect impostors to children before affecting impostor to parent.");
  454. }
  455. }
  456. }
  457. /**
  458. * This function will completly initialize this impostor.
  459. * It will create a new body - but only if this mesh has no parent.
  460. * If it has, this impostor will not be used other than to define the impostor
  461. * of the child mesh.
  462. * @hidden
  463. */
  464. public _init() {
  465. if (!this._physicsEngine) {
  466. return;
  467. }
  468. this._physicsEngine.removeImpostor(this);
  469. this.physicsBody = null;
  470. this._parent = this._parent || this._getPhysicsParent();
  471. if (!this._isDisposed && (!this.parent || this._options.ignoreParent)) {
  472. this._physicsEngine.addImpostor(this);
  473. }
  474. }
  475. private _getPhysicsParent(): Nullable<PhysicsImpostor> {
  476. if (this.object.parent instanceof AbstractMesh) {
  477. var parentMesh: AbstractMesh = <AbstractMesh>this.object.parent;
  478. return parentMesh.physicsImpostor;
  479. }
  480. return null;
  481. }
  482. /**
  483. * Should a new body be generated.
  484. * @returns boolean specifying if body initialization is required
  485. */
  486. public isBodyInitRequired(): boolean {
  487. return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
  488. }
  489. /**
  490. * Sets the updated scaling
  491. * @param updated Specifies if the scaling is updated
  492. */
  493. public setScalingUpdated() {
  494. this.forceUpdate();
  495. }
  496. /**
  497. * Force a regeneration of this or the parent's impostor's body.
  498. * Use under cautious - This will remove all joints already implemented.
  499. */
  500. public forceUpdate() {
  501. this._init();
  502. if (this.parent && !this._options.ignoreParent) {
  503. this.parent.forceUpdate();
  504. }
  505. }
  506. /*public get mesh(): AbstractMesh {
  507. return this._mesh;
  508. }*/
  509. /**
  510. * Gets the body that holds this impostor. Either its own, or its parent.
  511. */
  512. public get physicsBody(): any {
  513. return (this._parent && !this._options.ignoreParent) ? this._parent.physicsBody : this._physicsBody;
  514. }
  515. /**
  516. * Get the parent of the physics imposter
  517. * @returns Physics imposter or null
  518. */
  519. public get parent(): Nullable<PhysicsImpostor> {
  520. return !this._options.ignoreParent && this._parent ? this._parent : null;
  521. }
  522. /**
  523. * Sets the parent of the physics imposter
  524. */
  525. public set parent(value: Nullable<PhysicsImpostor>) {
  526. this._parent = value;
  527. }
  528. /**
  529. * Set the physics body. Used mainly by the physics engine/plugin
  530. */
  531. public set physicsBody(physicsBody: any) {
  532. if (this._physicsBody && this._physicsEngine) {
  533. this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this);
  534. }
  535. this._physicsBody = physicsBody;
  536. this.resetUpdateFlags();
  537. }
  538. /**
  539. * Resets the update flags
  540. */
  541. public resetUpdateFlags() {
  542. this._bodyUpdateRequired = false;
  543. }
  544. /**
  545. * Gets the object extend size
  546. * @returns the object extend size
  547. */
  548. public getObjectExtendSize(): Vector3 {
  549. if (this.object.getBoundingInfo) {
  550. let q = this.object.rotationQuaternion;
  551. //reset rotation
  552. this.object.rotationQuaternion = PhysicsImpostor.IDENTITY_QUATERNION;
  553. //calculate the world matrix with no rotation
  554. this.object.computeWorldMatrix && this.object.computeWorldMatrix(true);
  555. let boundingInfo = this.object.getBoundingInfo();
  556. let size = boundingInfo.boundingBox.extendSizeWorld.scale(2);
  557. //bring back the rotation
  558. this.object.rotationQuaternion = q;
  559. //calculate the world matrix with the new rotation
  560. this.object.computeWorldMatrix && this.object.computeWorldMatrix(true);
  561. return size;
  562. } else {
  563. return PhysicsImpostor.DEFAULT_OBJECT_SIZE;
  564. }
  565. }
  566. /**
  567. * Gets the object center
  568. * @returns The object center
  569. */
  570. public getObjectCenter(): Vector3 {
  571. if (this.object.getBoundingInfo) {
  572. let boundingInfo = this.object.getBoundingInfo();
  573. return boundingInfo.boundingBox.centerWorld;
  574. } else {
  575. return this.object.position;
  576. }
  577. }
  578. /**
  579. * Get a specific parametes from the options parameter
  580. * @param paramName The object parameter name
  581. * @returns The object parameter
  582. */
  583. public getParam(paramName: string): any {
  584. return (<any>this._options)[paramName];
  585. }
  586. /**
  587. * Sets a specific parameter in the options given to the physics plugin
  588. * @param paramName The parameter name
  589. * @param value The value of the parameter
  590. */
  591. public setParam(paramName: string, value: number) {
  592. (<any>this._options)[paramName] = value;
  593. this._bodyUpdateRequired = true;
  594. }
  595. /**
  596. * Specifically change the body's mass option. Won't recreate the physics body object
  597. * @param mass The mass of the physics imposter
  598. */
  599. public setMass(mass: number) {
  600. if (this.getParam("mass") !== mass) {
  601. this.setParam("mass", mass);
  602. }
  603. if (this._physicsEngine) {
  604. this._physicsEngine.getPhysicsPlugin().setBodyMass(this, mass);
  605. }
  606. }
  607. /**
  608. * Gets the linear velocity
  609. * @returns linear velocity or null
  610. */
  611. public getLinearVelocity(): Nullable<Vector3> {
  612. return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getLinearVelocity(this) : Vector3.Zero();
  613. }
  614. /**
  615. * Sets the linear velocity
  616. * @param velocity linear velocity or null
  617. */
  618. public setLinearVelocity(velocity: Nullable<Vector3>) {
  619. if (this._physicsEngine) {
  620. this._physicsEngine.getPhysicsPlugin().setLinearVelocity(this, velocity);
  621. }
  622. }
  623. /**
  624. * Gets the angular velocity
  625. * @returns angular velocity or null
  626. */
  627. public getAngularVelocity(): Nullable<Vector3> {
  628. return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getAngularVelocity(this) : Vector3.Zero();
  629. }
  630. /**
  631. * Sets the angular velocity
  632. * @param velocity The velocity or null
  633. */
  634. public setAngularVelocity(velocity: Nullable<Vector3>) {
  635. if (this._physicsEngine) {
  636. this._physicsEngine.getPhysicsPlugin().setAngularVelocity(this, velocity);
  637. }
  638. }
  639. /**
  640. * Execute a function with the physics plugin native code
  641. * Provide a function the will have two variables - the world object and the physics body object
  642. * @param func The function to execute with the physics plugin native code
  643. */
  644. public executeNativeFunction(func: (world: any, physicsBody: any) => void) {
  645. if (this._physicsEngine) {
  646. func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
  647. }
  648. }
  649. /**
  650. * Register a function that will be executed before the physics world is stepping forward
  651. * @param func The function to execute before the physics world is stepped forward
  652. */
  653. public registerBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  654. this._onBeforePhysicsStepCallbacks.push(func);
  655. }
  656. /**
  657. * Unregister a function that will be executed before the physics world is stepping forward
  658. * @param func The function to execute before the physics world is stepped forward
  659. */
  660. public unregisterBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  661. var index = this._onBeforePhysicsStepCallbacks.indexOf(func);
  662. if (index > -1) {
  663. this._onBeforePhysicsStepCallbacks.splice(index, 1);
  664. } else {
  665. Logger.Warn("Function to remove was not found");
  666. }
  667. }
  668. /**
  669. * Register a function that will be executed after the physics step
  670. * @param func The function to execute after physics step
  671. */
  672. public registerAfterPhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  673. this._onAfterPhysicsStepCallbacks.push(func);
  674. }
  675. /**
  676. * Unregisters a function that will be executed after the physics step
  677. * @param func The function to execute after physics step
  678. */
  679. public unregisterAfterPhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  680. var index = this._onAfterPhysicsStepCallbacks.indexOf(func);
  681. if (index > -1) {
  682. this._onAfterPhysicsStepCallbacks.splice(index, 1);
  683. } else {
  684. Logger.Warn("Function to remove was not found");
  685. }
  686. }
  687. /**
  688. * register a function that will be executed when this impostor collides against a different body
  689. * @param collideAgainst Physics imposter, or array of physics imposters to collide against
  690. * @param func Callback that is executed on collision
  691. */
  692. public registerOnPhysicsCollide(collideAgainst: PhysicsImpostor | Array<PhysicsImpostor>, func: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void): void {
  693. var collidedAgainstList: Array<PhysicsImpostor> = collideAgainst instanceof Array ? <Array<PhysicsImpostor>>collideAgainst : [<PhysicsImpostor>collideAgainst];
  694. this._onPhysicsCollideCallbacks.push({ callback: func, otherImpostors: collidedAgainstList });
  695. }
  696. /**
  697. * Unregisters the physics imposter on contact
  698. * @param collideAgainst The physics object to collide against
  699. * @param func Callback to execute on collision
  700. */
  701. public unregisterOnPhysicsCollide(collideAgainst: PhysicsImpostor | Array<PhysicsImpostor>, func: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor | Array<PhysicsImpostor>) => void): void {
  702. var collidedAgainstList: Array<PhysicsImpostor> = collideAgainst instanceof Array ? <Array<PhysicsImpostor>>collideAgainst : [<PhysicsImpostor>collideAgainst];
  703. var index = -1;
  704. let found = this._onPhysicsCollideCallbacks.some((cbDef, idx) => {
  705. if (cbDef.callback === func && cbDef.otherImpostors.length === collidedAgainstList.length) {
  706. // chcek the arrays match
  707. let sameList = cbDef.otherImpostors.every((impostor) => {
  708. return collidedAgainstList.indexOf(impostor) > -1;
  709. });
  710. if (sameList) {
  711. index = idx;
  712. }
  713. return sameList;
  714. }
  715. return false;
  716. });
  717. if (found) {
  718. this._onPhysicsCollideCallbacks.splice(index, 1);
  719. } else {
  720. Logger.Warn("Function to remove was not found");
  721. }
  722. }
  723. //temp variables for parent rotation calculations
  724. //private _mats: Array<Matrix> = [new Matrix(), new Matrix()];
  725. private _tmpQuat: Quaternion = new Quaternion();
  726. private _tmpQuat2: Quaternion = new Quaternion();
  727. /**
  728. * Get the parent rotation
  729. * @returns The parent rotation
  730. */
  731. public getParentsRotation(): Quaternion {
  732. let parent = this.object.parent;
  733. this._tmpQuat.copyFromFloats(0, 0, 0, 1);
  734. while (parent) {
  735. if (parent.rotationQuaternion) {
  736. this._tmpQuat2.copyFrom(parent.rotationQuaternion);
  737. } else {
  738. Quaternion.RotationYawPitchRollToRef(parent.rotation.y, parent.rotation.x, parent.rotation.z, this._tmpQuat2);
  739. }
  740. this._tmpQuat.multiplyToRef(this._tmpQuat2, this._tmpQuat);
  741. parent = parent.parent;
  742. }
  743. return this._tmpQuat;
  744. }
  745. /**
  746. * this function is executed by the physics engine.
  747. */
  748. public beforeStep = () => {
  749. if (!this._physicsEngine) {
  750. return;
  751. }
  752. this.object.translate(this._deltaPosition, -1);
  753. this._deltaRotationConjugated && this.object.rotationQuaternion && this.object.rotationQuaternion.multiplyToRef(this._deltaRotationConjugated, this.object.rotationQuaternion);
  754. this.object.computeWorldMatrix(false);
  755. if (this.object.parent && this.object.rotationQuaternion) {
  756. this.getParentsRotation();
  757. this._tmpQuat.multiplyToRef(this.object.rotationQuaternion, this._tmpQuat);
  758. } else {
  759. this._tmpQuat.copyFrom(this.object.rotationQuaternion || new Quaternion());
  760. }
  761. if (!this._options.disableBidirectionalTransformation) {
  762. this.object.rotationQuaternion && this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(this, /*bInfo.boundingBox.centerWorld*/ this.object.getAbsolutePosition(), this._tmpQuat);
  763. }
  764. this._onBeforePhysicsStepCallbacks.forEach((func) => {
  765. func(this);
  766. });
  767. }
  768. /**
  769. * this function is executed by the physics engine
  770. */
  771. public afterStep = () => {
  772. if (!this._physicsEngine) {
  773. return;
  774. }
  775. this._onAfterPhysicsStepCallbacks.forEach((func) => {
  776. func(this);
  777. });
  778. this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(this);
  779. // object has now its world rotation. needs to be converted to local.
  780. if (this.object.parent && this.object.rotationQuaternion) {
  781. this.getParentsRotation();
  782. this._tmpQuat.conjugateInPlace();
  783. this._tmpQuat.multiplyToRef(this.object.rotationQuaternion, this.object.rotationQuaternion);
  784. }
  785. // take the position set and make it the absolute position of this object.
  786. this.object.setAbsolutePosition(this.object.position);
  787. this._deltaRotation && this.object.rotationQuaternion && this.object.rotationQuaternion.multiplyToRef(this._deltaRotation, this.object.rotationQuaternion);
  788. this.object.translate(this._deltaPosition, 1);
  789. }
  790. /**
  791. * Legacy collision detection event support
  792. */
  793. public onCollideEvent: Nullable<(collider: PhysicsImpostor, collidedWith: PhysicsImpostor) => void> = null;
  794. /**
  795. * event and body object due to cannon's event-based architecture.
  796. */
  797. public onCollide = (e: { body: any }) => {
  798. if (!this._onPhysicsCollideCallbacks.length && !this.onCollideEvent) {
  799. return;
  800. }
  801. if (!this._physicsEngine) {
  802. return;
  803. }
  804. var otherImpostor = this._physicsEngine.getImpostorWithPhysicsBody(e.body);
  805. if (otherImpostor) {
  806. // Legacy collision detection event support
  807. if (this.onCollideEvent) {
  808. this.onCollideEvent(this, otherImpostor);
  809. }
  810. this._onPhysicsCollideCallbacks.filter((obj) => {
  811. return obj.otherImpostors.indexOf((<PhysicsImpostor>otherImpostor)) !== -1;
  812. }).forEach((obj) => {
  813. obj.callback(this, <PhysicsImpostor>otherImpostor);
  814. });
  815. }
  816. }
  817. /**
  818. * Apply a force
  819. * @param force The force to apply
  820. * @param contactPoint The contact point for the force
  821. * @returns The physics imposter
  822. */
  823. public applyForce(force: Vector3, contactPoint: Vector3): PhysicsImpostor {
  824. if (this._physicsEngine) {
  825. this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
  826. }
  827. return this;
  828. }
  829. /**
  830. * Apply an impulse
  831. * @param force The impulse force
  832. * @param contactPoint The contact point for the impulse force
  833. * @returns The physics imposter
  834. */
  835. public applyImpulse(force: Vector3, contactPoint: Vector3): PhysicsImpostor {
  836. if (this._physicsEngine) {
  837. this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
  838. }
  839. return this;
  840. }
  841. /**
  842. * A help function to create a joint
  843. * @param otherImpostor A physics imposter used to create a joint
  844. * @param jointType The type of joint
  845. * @param jointData The data for the joint
  846. * @returns The physics imposter
  847. */
  848. public createJoint(otherImpostor: PhysicsImpostor, jointType: number, jointData: PhysicsJointData): PhysicsImpostor {
  849. var joint = new PhysicsJoint(jointType, jointData);
  850. this.addJoint(otherImpostor, joint);
  851. return this;
  852. }
  853. /**
  854. * Add a joint to this impostor with a different impostor
  855. * @param otherImpostor A physics imposter used to add a joint
  856. * @param joint The joint to add
  857. * @returns The physics imposter
  858. */
  859. public addJoint(otherImpostor: PhysicsImpostor, joint: PhysicsJoint): PhysicsImpostor {
  860. this._joints.push({
  861. otherImpostor: otherImpostor,
  862. joint: joint
  863. });
  864. if (this._physicsEngine) {
  865. this._physicsEngine.addJoint(this, otherImpostor, joint);
  866. }
  867. return this;
  868. }
  869. /**
  870. * Add an anchor to a cloth impostor
  871. * @param otherImpostor rigid impostor to anchor to
  872. * @param width ratio across width from 0 to 1
  873. * @param height ratio up height from 0 to 1
  874. * @param influence the elasticity between cloth impostor and anchor from 0, very stretchy to 1, little strech
  875. * @param noCollisionBetweenLinkedBodies when true collisions between cloth impostor and anchor are ignored; default false
  876. * @returns impostor the soft imposter
  877. */
  878. public addAnchor(otherImpostor: PhysicsImpostor, width: number, height: number, influence: number, noCollisionBetweenLinkedBodies: boolean): PhysicsImpostor {
  879. if (!this._physicsEngine) {
  880. return this;
  881. }
  882. const plugin = this._physicsEngine.getPhysicsPlugin();
  883. if (!plugin.appendAnchor) {
  884. return this;
  885. }
  886. if (this._physicsEngine) {
  887. plugin.appendAnchor!(this, otherImpostor, width, height, influence, noCollisionBetweenLinkedBodies);
  888. }
  889. return this;
  890. }
  891. /**
  892. * Add a hook to a rope impostor
  893. * @param otherImpostor rigid impostor to anchor to
  894. * @param length ratio across rope from 0 to 1
  895. * @param influence the elasticity between rope impostor and anchor from 0, very stretchy to 1, little strech
  896. * @param noCollisionBetweenLinkedBodies when true collisions between soft impostor and anchor are ignored; default false
  897. * @returns impostor the rope imposter
  898. */
  899. public addHook(otherImpostor: PhysicsImpostor, length: number, influence: number, noCollisionBetweenLinkedBodies: boolean): PhysicsImpostor {
  900. if (!this._physicsEngine) {
  901. return this;
  902. }
  903. const plugin = this._physicsEngine.getPhysicsPlugin();
  904. if (!plugin.appendAnchor) {
  905. return this;
  906. }
  907. if (this._physicsEngine) {
  908. plugin.appendHook!(this, otherImpostor, length, influence, noCollisionBetweenLinkedBodies);
  909. }
  910. return this;
  911. }
  912. /**
  913. * Will keep this body still, in a sleep mode.
  914. * @returns the physics imposter
  915. */
  916. public sleep(): PhysicsImpostor {
  917. if (this._physicsEngine) {
  918. this._physicsEngine.getPhysicsPlugin().sleepBody(this);
  919. }
  920. return this;
  921. }
  922. /**
  923. * Wake the body up.
  924. * @returns The physics imposter
  925. */
  926. public wakeUp(): PhysicsImpostor {
  927. if (this._physicsEngine) {
  928. this._physicsEngine.getPhysicsPlugin().wakeUpBody(this);
  929. }
  930. return this;
  931. }
  932. /**
  933. * Clones the physics imposter
  934. * @param newObject The physics imposter clones to this physics-enabled object
  935. * @returns A nullable physics imposter
  936. */
  937. public clone(newObject: IPhysicsEnabledObject): Nullable<PhysicsImpostor> {
  938. if (!newObject) { return null; }
  939. return new PhysicsImpostor(newObject, this.type, this._options, this._scene);
  940. }
  941. /**
  942. * Disposes the physics imposter
  943. */
  944. public dispose(/*disposeChildren: boolean = true*/) {
  945. //no dispose if no physics engine is available.
  946. if (!this._physicsEngine) {
  947. return;
  948. }
  949. this._joints.forEach((j) => {
  950. if (this._physicsEngine) {
  951. this._physicsEngine.removeJoint(this, j.otherImpostor, j.joint);
  952. }
  953. });
  954. //dispose the physics body
  955. this._physicsEngine.removeImpostor(this);
  956. if (this.parent) {
  957. this.parent.forceUpdate();
  958. } else {
  959. /*this._object.getChildMeshes().forEach(function(mesh) {
  960. if (mesh.physicsImpostor) {
  961. if (disposeChildren) {
  962. mesh.physicsImpostor.dispose();
  963. mesh.physicsImpostor = null;
  964. }
  965. }
  966. })*/
  967. }
  968. this._isDisposed = true;
  969. }
  970. /**
  971. * Sets the delta position
  972. * @param position The delta position amount
  973. */
  974. public setDeltaPosition(position: Vector3) {
  975. this._deltaPosition.copyFrom(position);
  976. }
  977. /**
  978. * Sets the delta rotation
  979. * @param rotation The delta rotation amount
  980. */
  981. public setDeltaRotation(rotation: Quaternion) {
  982. if (!this._deltaRotation) {
  983. this._deltaRotation = new Quaternion();
  984. }
  985. this._deltaRotation.copyFrom(rotation);
  986. this._deltaRotationConjugated = this._deltaRotation.conjugate();
  987. }
  988. /**
  989. * Gets the box size of the physics imposter and stores the result in the input parameter
  990. * @param result Stores the box size
  991. * @returns The physics imposter
  992. */
  993. public getBoxSizeToRef(result: Vector3): PhysicsImpostor {
  994. if (this._physicsEngine) {
  995. this._physicsEngine.getPhysicsPlugin().getBoxSizeToRef(this, result);
  996. }
  997. return this;
  998. }
  999. /**
  1000. * Gets the radius of the physics imposter
  1001. * @returns Radius of the physics imposter
  1002. */
  1003. public getRadius(): number {
  1004. return this._physicsEngine ? this._physicsEngine.getPhysicsPlugin().getRadius(this) : 0;
  1005. }
  1006. /**
  1007. * Sync a bone with this impostor
  1008. * @param bone The bone to sync to the impostor.
  1009. * @param boneMesh The mesh that the bone is influencing.
  1010. * @param jointPivot The pivot of the joint / bone in local space.
  1011. * @param distToJoint Optional distance from the impostor to the joint.
  1012. * @param adjustRotation Optional quaternion for adjusting the local rotation of the bone.
  1013. */
  1014. public syncBoneWithImpostor(bone: Bone, boneMesh: AbstractMesh, jointPivot: Vector3, distToJoint?: number, adjustRotation?: Quaternion) {
  1015. var tempVec = PhysicsImpostor._tmpVecs[0];
  1016. var mesh = <AbstractMesh>this.object;
  1017. if (mesh.rotationQuaternion) {
  1018. if (adjustRotation) {
  1019. var tempQuat = PhysicsImpostor._tmpQuat;
  1020. mesh.rotationQuaternion.multiplyToRef(adjustRotation, tempQuat);
  1021. bone.setRotationQuaternion(tempQuat, Space.WORLD, boneMesh);
  1022. } else {
  1023. bone.setRotationQuaternion(mesh.rotationQuaternion, Space.WORLD, boneMesh);
  1024. }
  1025. }
  1026. tempVec.x = 0;
  1027. tempVec.y = 0;
  1028. tempVec.z = 0;
  1029. if (jointPivot) {
  1030. tempVec.x = jointPivot.x;
  1031. tempVec.y = jointPivot.y;
  1032. tempVec.z = jointPivot.z;
  1033. bone.getDirectionToRef(tempVec, boneMesh, tempVec);
  1034. if (distToJoint === undefined || distToJoint === null) {
  1035. distToJoint = jointPivot.length();
  1036. }
  1037. tempVec.x *= distToJoint;
  1038. tempVec.y *= distToJoint;
  1039. tempVec.z *= distToJoint;
  1040. }
  1041. if (bone.getParent()) {
  1042. tempVec.addInPlace(mesh.getAbsolutePosition());
  1043. bone.setAbsolutePosition(tempVec, boneMesh);
  1044. } else {
  1045. boneMesh.setAbsolutePosition(mesh.getAbsolutePosition());
  1046. boneMesh.position.x -= tempVec.x;
  1047. boneMesh.position.y -= tempVec.y;
  1048. boneMesh.position.z -= tempVec.z;
  1049. }
  1050. }
  1051. /**
  1052. * Sync impostor to a bone
  1053. * @param bone The bone that the impostor will be synced to.
  1054. * @param boneMesh The mesh that the bone is influencing.
  1055. * @param jointPivot The pivot of the joint / bone in local space.
  1056. * @param distToJoint Optional distance from the impostor to the joint.
  1057. * @param adjustRotation Optional quaternion for adjusting the local rotation of the bone.
  1058. * @param boneAxis Optional vector3 axis the bone is aligned with
  1059. */
  1060. public syncImpostorWithBone(bone: Bone, boneMesh: AbstractMesh, jointPivot: Vector3, distToJoint?: number, adjustRotation?: Quaternion, boneAxis?: Vector3) {
  1061. var mesh = <AbstractMesh>this.object;
  1062. if (mesh.rotationQuaternion) {
  1063. if (adjustRotation) {
  1064. var tempQuat = PhysicsImpostor._tmpQuat;
  1065. bone.getRotationQuaternionToRef(Space.WORLD, boneMesh, tempQuat);
  1066. tempQuat.multiplyToRef(adjustRotation, mesh.rotationQuaternion);
  1067. } else {
  1068. bone.getRotationQuaternionToRef(Space.WORLD, boneMesh, mesh.rotationQuaternion);
  1069. }
  1070. }
  1071. var pos = PhysicsImpostor._tmpVecs[0];
  1072. var boneDir = PhysicsImpostor._tmpVecs[1];
  1073. if (!boneAxis) {
  1074. boneAxis = PhysicsImpostor._tmpVecs[2];
  1075. boneAxis.x = 0;
  1076. boneAxis.y = 1;
  1077. boneAxis.z = 0;
  1078. }
  1079. bone.getDirectionToRef(boneAxis, boneMesh, boneDir);
  1080. bone.getAbsolutePositionToRef(boneMesh, pos);
  1081. if ((distToJoint === undefined || distToJoint === null) && jointPivot) {
  1082. distToJoint = jointPivot.length();
  1083. }
  1084. if (distToJoint !== undefined && distToJoint !== null) {
  1085. pos.x += boneDir.x * distToJoint;
  1086. pos.y += boneDir.y * distToJoint;
  1087. pos.z += boneDir.z * distToJoint;
  1088. }
  1089. mesh.setAbsolutePosition(pos);
  1090. }
  1091. //Impostor types
  1092. /**
  1093. * No-Imposter type
  1094. */
  1095. public static NoImpostor = 0;
  1096. /**
  1097. * Sphere-Imposter type
  1098. */
  1099. public static SphereImpostor = 1;
  1100. /**
  1101. * Box-Imposter type
  1102. */
  1103. public static BoxImpostor = 2;
  1104. /**
  1105. * Plane-Imposter type
  1106. */
  1107. public static PlaneImpostor = 3;
  1108. /**
  1109. * Mesh-imposter type
  1110. */
  1111. public static MeshImpostor = 4;
  1112. /**
  1113. * Cylinder-Imposter type
  1114. */
  1115. public static CylinderImpostor = 7;
  1116. /**
  1117. * Particle-Imposter type
  1118. */
  1119. public static ParticleImpostor = 8;
  1120. /**
  1121. * Heightmap-Imposter type
  1122. */
  1123. public static HeightmapImpostor = 9;
  1124. /**
  1125. * ConvexHull-Impostor type (Ammo.js plugin only)
  1126. */
  1127. public static ConvexHullImpostor = 10;
  1128. /**
  1129. * Rope-Imposter type
  1130. */
  1131. public static RopeImpostor = 101;
  1132. /**
  1133. * Cloth-Imposter type
  1134. */
  1135. public static ClothImpostor = 102;
  1136. /**
  1137. * Softbody-Imposter type
  1138. */
  1139. public static SoftbodyImpostor = 103;
  1140. }