babylon.physicsImpostor.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. module BABYLON {
  2. export interface PhysicsImpostorParameters {
  3. mass: number;
  4. friction?: number;
  5. restitution?: number;
  6. nativeOptions?: any;
  7. }
  8. export class PhysicsImpostor {
  9. private _physicsEngine: PhysicsEngine;
  10. //The native cannon/oimo/energy physics body object.
  11. private _physicsBody: any;
  12. private _bodyUpdateRequired: boolean = false;
  13. private _onBeforePhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
  14. private _onAfterPhysicsStepCallbacks = new Array<(impostor: PhysicsImpostor) => void>();
  15. private _onPhysicsCollideCallbacks: Array<{ callback: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void, otherImpostors: Array<PhysicsImpostor> }> = []
  16. private _deltaPosition: Vector3 = Vector3.Zero();
  17. private _deltaRotation: Quaternion;
  18. private _deltaRotationConjugated: Quaternion;
  19. //If set, this is this impostor's parent
  20. private _parent: PhysicsImpostor;
  21. private _joints: Array<{
  22. joint: PhysicsJoint,
  23. otherImpostor: PhysicsImpostor
  24. }>;
  25. constructor(private _mesh: AbstractMesh, public type: number, private _options: PhysicsImpostorParameters = { mass: 0 }) {
  26. this._physicsEngine = this._mesh.getScene().getPhysicsEngine();
  27. if (!this._physicsEngine) {
  28. Tools.Error("Physics not enabled. Please use scene.enablePhysics(...) before creating impostors.")
  29. } else {
  30. //default options params
  31. this._options.mass = (_options.mass === void 0) ? 0 : _options.mass
  32. this._options.friction = (_options.friction === void 0) ? 0.2 : _options.friction
  33. this._options.restitution = (_options.restitution === void 0) ? 0.2 : _options.restitution
  34. this._joints = [];
  35. //If the mesh has a parent, don't initialize the physicsBody. Instead wait for the parent to do that.
  36. if (!this._mesh.parent) {
  37. this._init();
  38. }
  39. }
  40. }
  41. /**
  42. * This function will completly initialize this impostor.
  43. * It will create a new body - but only if this mesh has no parent.
  44. * If it has, this impostor will not be used other than to define the impostor
  45. * of the child mesh.
  46. */
  47. public _init() {
  48. this._physicsEngine.removeImpostor(this);
  49. this.physicsBody = null;
  50. this._parent = this._parent || this._getPhysicsParent();
  51. if (!this.parent) {
  52. this._physicsEngine.addImpostor(this);
  53. }
  54. }
  55. private _getPhysicsParent(): PhysicsImpostor {
  56. if (this.mesh.parent instanceof AbstractMesh) {
  57. var parentMesh: AbstractMesh = <AbstractMesh>this.mesh.parent;
  58. return parentMesh.getPhysicsImpostor();
  59. }
  60. return;
  61. }
  62. /**
  63. * Should a new body be generated.
  64. */
  65. public isBodyInitRequired(): boolean {
  66. return this._bodyUpdateRequired || (!this._physicsBody && !this._parent);
  67. }
  68. public setScalingUpdated(updated: boolean) {
  69. this.forceUpdate();
  70. }
  71. /**
  72. * Force a regeneration of this or the parent's impostor's body.
  73. * Use under cautious - This will remove all joints already implemented.
  74. */
  75. public forceUpdate() {
  76. this._init();
  77. if (this.parent) {
  78. this.parent.forceUpdate();
  79. }
  80. }
  81. public get mesh(): AbstractMesh {
  82. return this._mesh;
  83. }
  84. /**
  85. * Gets the body that holds this impostor. Either its own, or its parent.
  86. */
  87. public get physicsBody(): any {
  88. return this._parent ? this._parent.physicsBody : this._physicsBody;
  89. }
  90. public get parent() {
  91. return this._parent;
  92. }
  93. /**
  94. * Set the physics body. Used mainly by the physics engine/plugin
  95. */
  96. public set physicsBody(physicsBody: any) {
  97. if (this._physicsBody) {
  98. this._physicsEngine.getPhysicsPlugin().removePhysicsBody(this);
  99. }
  100. this._physicsBody = physicsBody;
  101. this.resetUpdateFlags();
  102. }
  103. public resetUpdateFlags() {
  104. this._bodyUpdateRequired = false;
  105. }
  106. /**
  107. * Get a specific parametes from the options parameter.
  108. */
  109. public getParam(paramName: string) {
  110. return this._options[paramName];
  111. }
  112. /**
  113. * Sets a specific parameter in the options given to the physics plugin
  114. */
  115. public setParam(paramName: string, value: number) {
  116. this._options[paramName] = value;
  117. this._bodyUpdateRequired = true;
  118. }
  119. /**
  120. * Specifically change the body's mass option. Won't recreate the physics body object
  121. */
  122. public setMass(mass: number) {
  123. if (this.getParam("mass") !== mass) {
  124. this.setParam("mass", mass);
  125. }
  126. this._physicsEngine.getPhysicsPlugin().setBodyMass(this, mass);
  127. }
  128. public getLinearVelocity() : Vector3 {
  129. return this._physicsEngine.getPhysicsPlugin().getLinearVelocity(this);
  130. }
  131. /**
  132. * Set the body's linear velocity.
  133. */
  134. public setLinearVelocity(velocity: Vector3) {
  135. this._physicsEngine.getPhysicsPlugin().setLinearVelocity(this, velocity);
  136. }
  137. public getAngularVelocity() : Vector3 {
  138. return this._physicsEngine.getPhysicsPlugin().getAngularVelocity(this);
  139. }
  140. /**
  141. * Set the body's linear velocity.
  142. */
  143. public setAngularVelocity(velocity: Vector3) {
  144. this._physicsEngine.getPhysicsPlugin().setAngularVelocity(this, velocity);
  145. }
  146. /**
  147. * Execute a function with the physics plugin native code.
  148. * Provide a function the will have two variables - the world object and the physics body object.
  149. */
  150. public executeNativeFunction(func: (world: any, physicsBody: any) => void) {
  151. func(this._physicsEngine.getPhysicsPlugin().world, this.physicsBody);
  152. }
  153. /**
  154. * Register a function that will be executed before the physics world is stepping forward.
  155. */
  156. public registerBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  157. this._onBeforePhysicsStepCallbacks.push(func);
  158. }
  159. public unregisterBeforePhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  160. var index = this._onBeforePhysicsStepCallbacks.indexOf(func);
  161. if (index > -1) {
  162. this._onBeforePhysicsStepCallbacks.splice(index, 1);
  163. } else {
  164. Tools.Warn("Function to remove was not found");
  165. }
  166. }
  167. /**
  168. * Register a function that will be executed after the physics step
  169. */
  170. public registerAfterPhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  171. this._onAfterPhysicsStepCallbacks.push(func);
  172. }
  173. public unregisterAfterPhysicsStep(func: (impostor: PhysicsImpostor) => void): void {
  174. var index = this._onAfterPhysicsStepCallbacks.indexOf(func);
  175. if (index > -1) {
  176. this._onAfterPhysicsStepCallbacks.splice(index, 1);
  177. } else {
  178. Tools.Warn("Function to remove was not found");
  179. }
  180. }
  181. /**
  182. * register a function that will be executed when this impostor collides against a different body.
  183. */
  184. public registerOnPhysicsCollide(collideAgainst: PhysicsImpostor | Array<PhysicsImpostor>, func: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor) => void): void {
  185. var collidedAgainstList: Array<PhysicsImpostor> = collideAgainst instanceof Array ? <Array<PhysicsImpostor>>collideAgainst : [<PhysicsImpostor>collideAgainst]
  186. this._onPhysicsCollideCallbacks.push({ callback: func, otherImpostors: collidedAgainstList });
  187. }
  188. public unregisterOnPhysicsCollide(collideAgainst: PhysicsImpostor | Array<PhysicsImpostor>, func: (collider: PhysicsImpostor, collidedAgainst: PhysicsImpostor | Array<PhysicsImpostor>) => void): void {
  189. var collidedAgainstList: Array<PhysicsImpostor> = collideAgainst instanceof Array ? <Array<PhysicsImpostor>>collideAgainst : [<PhysicsImpostor>collideAgainst]
  190. var index = this._onPhysicsCollideCallbacks.indexOf({ callback: func, otherImpostors: collidedAgainstList });
  191. if (index > -1) {
  192. this._onPhysicsCollideCallbacks.splice(index, 1);
  193. } else {
  194. Tools.Warn("Function to remove was not found");
  195. }
  196. }
  197. private _tmpPositionWithDelta: Vector3 = Vector3.Zero();
  198. private _tmpRotationWithDelta: Quaternion = new Quaternion();
  199. /**
  200. * this function is executed by the physics engine.
  201. */
  202. public beforeStep = () => {
  203. this.mesh.position.subtractToRef(this._deltaPosition, this._tmpPositionWithDelta);
  204. //conjugate deltaRotation
  205. if (this._deltaRotationConjugated) {
  206. this.mesh.rotationQuaternion.multiplyToRef(this._deltaRotationConjugated, this._tmpRotationWithDelta);
  207. } else {
  208. this._tmpRotationWithDelta.copyFrom(this.mesh.rotationQuaternion);
  209. }
  210. this._physicsEngine.getPhysicsPlugin().setPhysicsBodyTransformation(this, this._tmpPositionWithDelta, this._tmpRotationWithDelta);
  211. this._onBeforePhysicsStepCallbacks.forEach((func) => {
  212. func(this);
  213. });
  214. }
  215. /**
  216. * this function is executed by the physics engine.
  217. */
  218. public afterStep = () => {
  219. this._onAfterPhysicsStepCallbacks.forEach((func) => {
  220. func(this);
  221. });
  222. this._physicsEngine.getPhysicsPlugin().setTransformationFromPhysicsBody(this);
  223. this.mesh.position.addInPlace(this._deltaPosition)
  224. if (this._deltaRotation) {
  225. this.mesh.rotationQuaternion.multiplyInPlace(this._deltaRotation);
  226. }
  227. }
  228. //event and body object due to cannon's event-based architecture.
  229. public onCollide = (e: { body: any }) => {
  230. var otherImpostor = this._physicsEngine.getImpostorWithPhysicsBody(e.body);
  231. if (otherImpostor) {
  232. this._onPhysicsCollideCallbacks.filter((obj) => {
  233. return obj.otherImpostors.indexOf(otherImpostor) !== -1
  234. }).forEach((obj) => {
  235. obj.callback(this, otherImpostor);
  236. })
  237. }
  238. }
  239. /**
  240. * Apply a force
  241. */
  242. public applyForce(force: Vector3, contactPoint: Vector3) {
  243. this._physicsEngine.getPhysicsPlugin().applyForce(this, force, contactPoint);
  244. }
  245. /**
  246. * Apply an impulse
  247. */
  248. public applyImpulse(force: Vector3, contactPoint: Vector3) {
  249. this._physicsEngine.getPhysicsPlugin().applyImpulse(this, force, contactPoint);
  250. }
  251. /**
  252. * A help function to create a joint.
  253. */
  254. public createJoint(otherImpostor: PhysicsImpostor, jointType: number, jointData: PhysicsJointData) {
  255. var joint = new PhysicsJoint(jointType, jointData);
  256. this.addJoint(otherImpostor, joint);
  257. }
  258. /**
  259. * Add a joint to this impostor with a different impostor.
  260. */
  261. public addJoint(otherImpostor: PhysicsImpostor, joint: PhysicsJoint) {
  262. this._joints.push({
  263. otherImpostor: otherImpostor,
  264. joint: joint
  265. })
  266. this._physicsEngine.addJoint(this, otherImpostor, joint);
  267. }
  268. /**
  269. * Will keep this body still, in a sleep mode.
  270. */
  271. public sleep() {
  272. this._physicsEngine.getPhysicsPlugin().sleepBody(this);
  273. }
  274. /**
  275. * Wake the body up.
  276. */
  277. public wakeUp() {
  278. this._physicsEngine.getPhysicsPlugin().wakeUpBody(this);
  279. }
  280. public dispose(disposeChildren: boolean = true) {
  281. this.physicsBody = null;
  282. if (this.parent) {
  283. this.parent.forceUpdate();
  284. } else {
  285. this.mesh.getChildMeshes().forEach(function(mesh) {
  286. if (mesh.physicsImpostor) {
  287. if (disposeChildren) {
  288. mesh.physicsImpostor.dispose();
  289. mesh.physicsImpostor = null;
  290. }
  291. }
  292. })
  293. }
  294. }
  295. public setDeltaPosition(position: Vector3) {
  296. this._deltaPosition.copyFrom(position);
  297. }
  298. public setDeltaRotation(rotation: Quaternion) {
  299. if (!this._deltaRotation) {
  300. this._deltaRotation = new Quaternion();
  301. }
  302. this._deltaRotation.copyFrom(rotation);
  303. this._deltaRotationConjugated = this._deltaRotation.conjugate();
  304. }
  305. //Impostor types
  306. public static NoImpostor = 0;
  307. public static SphereImpostor = 1;
  308. public static BoxImpostor = 2;
  309. public static PlaneImpostor = 3;
  310. public static MeshImpostor = 4;
  311. public static CylinderImpostor = 7;
  312. public static ParticleImpostor = 8;
  313. public static HeightmapImpostor = 9;
  314. }
  315. }