ammoJSPlugin.ts 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127
  1. import { Quaternion, Vector3, Matrix } from "../../Maths/math";
  2. import { IPhysicsEnginePlugin, PhysicsImpostorJoint } from "../../Physics/IPhysicsEngine";
  3. import { Logger } from "../../Misc/logger";
  4. import { PhysicsImpostor, IPhysicsEnabledObject } from "../../Physics/physicsImpostor";
  5. import { PhysicsJoint, IMotorEnabledJoint, DistanceJointData } from "../../Physics/physicsJoint";
  6. import { VertexBuffer } from "../../Meshes/buffer";
  7. import { VertexData } from "../../Meshes/mesh.vertexData";
  8. import { Nullable } from "../../types";
  9. import { AbstractMesh } from "../../Meshes/abstractMesh";
  10. import { Mesh } from "../../Meshes/mesh";
  11. declare var Ammo: any;
  12. /**
  13. * AmmoJS Physics plugin
  14. * @see https://doc.babylonjs.com/how_to/using_the_physics_engine
  15. * @see https://github.com/kripken/ammo.js/
  16. */
  17. export class AmmoJSPlugin implements IPhysicsEnginePlugin {
  18. /**
  19. * Reference to the Ammo library
  20. */
  21. public bjsAMMO: any = {};
  22. /**
  23. * Created ammoJS world which physics bodies are added to
  24. */
  25. public world: any;
  26. /**
  27. * Name of the plugin
  28. */
  29. public name: string = "AmmoJSPlugin";
  30. private _timeStep: number = 1 / 60;
  31. private _fixedTimeStep: number = 1 / 60;
  32. private _maxSteps = 5;
  33. private _tmpQuaternion = new Quaternion();
  34. private _tmpAmmoTransform: any;
  35. private _tmpAmmoQuaternion: any;
  36. private _tmpAmmoConcreteContactResultCallback: any;
  37. private _collisionConfiguration: any;
  38. private _dispatcher: any;
  39. private _overlappingPairCache: any;
  40. private _solver: any;
  41. private _softBodySolver: any;
  42. private _tmpAmmoVectorA: any;
  43. private _tmpAmmoVectorB: any;
  44. private _tmpAmmoVectorC: any;
  45. private _tmpContactCallbackResult = false;
  46. private static readonly DISABLE_COLLISION_FLAG = 4;
  47. private static readonly KINEMATIC_FLAG = 2;
  48. private static readonly DISABLE_DEACTIVATION_FLAG = 4;
  49. /**
  50. * Initializes the ammoJS plugin
  51. * @param _includeSoftBodies when true you can mix tigid and soft bodies (default false)
  52. * @param _useDeltaForWorldStep if the time between frames should be used when calculating physics steps (Default: true)
  53. * @param ammoInjection can be used to inject your own ammo reference
  54. */
  55. public constructor(private _includeSoftBodies: boolean = false, private _useDeltaForWorldStep: boolean = true, ammoInjection: any = Ammo) {
  56. if (typeof ammoInjection === "function") {
  57. ammoInjection(this.bjsAMMO);
  58. }else {
  59. this.bjsAMMO = ammoInjection;
  60. }
  61. if (!this.isSupported()) {
  62. Logger.Error("AmmoJS is not available. Please make sure you included the js file.");
  63. return;
  64. }
  65. // Initialize the physics world
  66. if (this._includeSoftBodies) {
  67. this._collisionConfiguration = new this.bjsAMMO.btSoftBodyRigidBodyCollisionConfiguration();
  68. this._dispatcher = new this.bjsAMMO.btCollisionDispatcher(this._collisionConfiguration);
  69. this._overlappingPairCache = new this.bjsAMMO.btDbvtBroadphase();
  70. this._solver = new this.bjsAMMO.btSequentialImpulseConstraintSolver();
  71. this._softBodySolver = new this.bjsAMMO.btDefaultSoftBodySolver();
  72. this.world = new this.bjsAMMO.btSoftRigidDynamicsWorld(this._dispatcher, this._overlappingPairCache, this._solver, this._collisionConfiguration, this._softBodySolver);
  73. }
  74. else {
  75. this._collisionConfiguration = new this.bjsAMMO.btDefaultCollisionConfiguration();
  76. this._dispatcher = new this.bjsAMMO.btCollisionDispatcher(this._collisionConfiguration);
  77. this._overlappingPairCache = new this.bjsAMMO.btDbvtBroadphase();
  78. this._solver = new this.bjsAMMO.btSequentialImpulseConstraintSolver();
  79. this.world = new this.bjsAMMO.btDiscreteDynamicsWorld(this._dispatcher, this._overlappingPairCache, this._solver, this._collisionConfiguration);
  80. }
  81. this._tmpAmmoConcreteContactResultCallback = new this.bjsAMMO.ConcreteContactResultCallback();
  82. this._tmpAmmoConcreteContactResultCallback.addSingleResult = () => { this._tmpContactCallbackResult = true; };
  83. // Create temp ammo variables
  84. this._tmpAmmoTransform = new this.bjsAMMO.btTransform();
  85. this._tmpAmmoTransform.setIdentity();
  86. this._tmpAmmoQuaternion = new this.bjsAMMO.btQuaternion(0, 0, 0, 1);
  87. this._tmpAmmoVectorA = new this.bjsAMMO.btVector3(0, 0, 0);
  88. this._tmpAmmoVectorB = new this.bjsAMMO.btVector3(0, 0, 0);
  89. this._tmpAmmoVectorC = new this.bjsAMMO.btVector3(0, 0, 0);
  90. }
  91. /**
  92. * Sets the gravity of the physics world (m/(s^2))
  93. * @param gravity Gravity to set
  94. */
  95. public setGravity(gravity: Vector3): void {
  96. this._tmpAmmoVectorA.setValue(gravity.x, gravity.y, gravity.z);
  97. this.world.setGravity(this._tmpAmmoVectorA);
  98. if (this._includeSoftBodies) {
  99. this.world.getWorldInfo().set_m_gravity(this._tmpAmmoVectorA);
  100. }
  101. }
  102. /**
  103. * Amount of time to step forward on each frame (only used if useDeltaForWorldStep is false in the constructor)
  104. * @param timeStep timestep to use in seconds
  105. */
  106. public setTimeStep(timeStep: number) {
  107. this._timeStep = timeStep;
  108. }
  109. /**
  110. * Increment to step forward in the physics engine (If timeStep is set to 1/60 and fixedTimeStep is set to 1/120 the physics engine should run 2 steps per frame) (Default: 1/60)
  111. * @param fixedTimeStep fixedTimeStep to use in seconds
  112. */
  113. public setFixedTimeStep(fixedTimeStep: number) {
  114. this._fixedTimeStep = fixedTimeStep;
  115. }
  116. /**
  117. * Sets the maximum number of steps by the physics engine per frame (Default: 5)
  118. * @param maxSteps the maximum number of steps by the physics engine per frame
  119. */
  120. public setMaxSteps(maxSteps: number) {
  121. this._maxSteps = maxSteps;
  122. }
  123. /**
  124. * Gets the current timestep (only used if useDeltaForWorldStep is false in the constructor)
  125. * @returns the current timestep in seconds
  126. */
  127. public getTimeStep(): number {
  128. return this._timeStep;
  129. }
  130. // Ammo's contactTest and contactPairTest take a callback that runs synchronously, wrap them so that they are easier to consume
  131. private _isImpostorInContact(impostor: PhysicsImpostor) {
  132. this._tmpContactCallbackResult = false;
  133. this.world.contactTest(impostor.physicsBody, this._tmpAmmoConcreteContactResultCallback);
  134. return this._tmpContactCallbackResult;
  135. }
  136. // Ammo's collision events have some weird quirks
  137. // contactPairTest fires too many events as it fires events even when objects are close together but contactTest does not
  138. // so only fire event if both contactTest and contactPairTest have a hit
  139. private _isImpostorPairInContact(impostorA: PhysicsImpostor, impostorB: PhysicsImpostor) {
  140. this._tmpContactCallbackResult = false;
  141. this.world.contactPairTest(impostorA.physicsBody, impostorB.physicsBody, this._tmpAmmoConcreteContactResultCallback);
  142. return this._tmpContactCallbackResult;
  143. }
  144. // Ammo's behavior when maxSteps > 0 does not behave as described in docs
  145. // @see http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Stepping_The_World
  146. //
  147. // When maxSteps is 0 do the entire simulation in one step
  148. // When maxSteps is > 0, run up to maxStep times, if on the last step the (remaining step - fixedTimeStep) is < fixedTimeStep, the remainder will be used for the step. (eg. if remainder is 1.001 and fixedTimeStep is 1 the last step will be 1.001, if instead it did 2 steps (1, 0.001) issues occuered when having a tiny step in ammo)
  149. // Note: To get deterministic physics, timeStep would always need to be divisible by fixedTimeStep
  150. private _stepSimulation(timeStep: number = 1 / 60, maxSteps: number = 10, fixedTimeStep: number = 1 / 60) {
  151. if (maxSteps == 0) {
  152. this.world.stepSimulation(timeStep, 0);
  153. } else {
  154. while (maxSteps > 0 && timeStep > 0) {
  155. if (timeStep - fixedTimeStep < fixedTimeStep) {
  156. this.world.stepSimulation(timeStep, 0);
  157. timeStep = 0;
  158. } else {
  159. timeStep -= fixedTimeStep;
  160. this.world.stepSimulation(fixedTimeStep, 0);
  161. }
  162. maxSteps--;
  163. }
  164. }
  165. }
  166. /**
  167. * Moves the physics simulation forward delta seconds and updates the given physics imposters
  168. * Prior to the step the imposters physics location is set to the position of the babylon meshes
  169. * After the step the babylon meshes are set to the position of the physics imposters
  170. * @param delta amount of time to step forward
  171. * @param impostors array of imposters to update before/after the step
  172. */
  173. public executeStep(delta: number, impostors: Array<PhysicsImpostor>): void {
  174. for (var impostor of impostors) {
  175. // Update physics world objects to match babylon world
  176. if (!impostor.soft) {
  177. impostor.beforeStep();
  178. }
  179. }
  180. this._stepSimulation(this._useDeltaForWorldStep ? delta : this._timeStep, this._maxSteps, this._fixedTimeStep);
  181. for (var mainImpostor of impostors) {
  182. // After physics update make babylon world objects match physics world objects
  183. if (mainImpostor.soft) {
  184. this.afterSoftStep(mainImpostor);
  185. }
  186. else {
  187. mainImpostor.afterStep();
  188. }
  189. // Handle collision event
  190. if (mainImpostor._onPhysicsCollideCallbacks.length > 0) {
  191. if (this._isImpostorInContact(mainImpostor)) {
  192. for (var collideCallback of mainImpostor._onPhysicsCollideCallbacks) {
  193. for (var otherImpostor of collideCallback.otherImpostors) {
  194. if (mainImpostor.physicsBody.isActive() || otherImpostor.physicsBody.isActive()) {
  195. if (this._isImpostorPairInContact(mainImpostor, otherImpostor)) {
  196. mainImpostor.onCollide({ body: otherImpostor.physicsBody });
  197. otherImpostor.onCollide({ body: mainImpostor.physicsBody });
  198. }
  199. }
  200. }
  201. }
  202. }
  203. }
  204. }
  205. }
  206. /**
  207. * Update babylon mesh vertices vertices to match physics world object
  208. * @param impostor imposter to apply impulse
  209. */
  210. public afterSoftStep(impostor: PhysicsImpostor): void {
  211. var object = impostor.object;
  212. var vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
  213. if (!vertexPositions) {
  214. vertexPositions = [];
  215. }
  216. var vertexNormals = object.getVerticesData(VertexBuffer.NormalKind);
  217. if (!vertexNormals) {
  218. vertexNormals = [];
  219. }
  220. var nbVertices = vertexPositions.length / 3;
  221. var bodyVertices = impostor.physicsBody.get_m_nodes();
  222. var node: any;
  223. var nodePositions: any;
  224. var nodeNormals: any;
  225. var x, y, z: number;
  226. var nx, ny, nz: number;
  227. for (var n = 0; n < nbVertices; n++) {
  228. node = bodyVertices.at(n);
  229. nodePositions = node.get_m_x();
  230. x = nodePositions.x();
  231. y = nodePositions.y();
  232. z = -nodePositions.z();
  233. var nodeNormals = node.get_m_n();
  234. nx = nodeNormals.x();
  235. ny = nodeNormals.y();
  236. nz = -nodeNormals.z();
  237. vertexPositions[3 * n] = x;
  238. vertexPositions[3 * n + 1] = y;
  239. vertexPositions[3 * n + 2] = z;
  240. vertexNormals[3 * n] = nx;
  241. vertexNormals[3 * n + 1] = ny;
  242. vertexNormals[3 * n + 2] = nz;
  243. }
  244. var vertex_data = new VertexData();
  245. vertex_data.positions = vertexPositions;
  246. vertex_data.normals = vertexNormals;
  247. vertex_data.uvs = object.getVerticesData(VertexBuffer.UVKind);
  248. vertex_data.colors = object.getVerticesData(VertexBuffer.ColorKind);
  249. if (object && object.getIndices) {
  250. vertex_data.indices = object.getIndices();
  251. }
  252. vertex_data.applyToMesh(<Mesh>object);
  253. }
  254. private _tmpVector = new Vector3();
  255. private _tmpMatrix = new Matrix();
  256. /**
  257. * Applies an impulse on the imposter
  258. * @param impostor imposter to apply impulse
  259. * @param force amount of force to be applied to the imposter
  260. * @param contactPoint the location to apply the impulse on the imposter
  261. */
  262. public applyImpulse(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
  263. if (!impulse.soft) {
  264. impostor.physicsBody.activate();
  265. var worldPoint = this._tmpAmmoVectorA;
  266. var impulse = this._tmpAmmoVectorB;
  267. // Convert contactPoint into world space
  268. if (impostor.object && impostor.object.getWorldMatrix) {
  269. impostor.object.getWorldMatrix().invertToRef(this._tmpMatrix);
  270. Vector3.TransformCoordinatesToRef(contactPoint, this._tmpMatrix, this._tmpVector);
  271. contactPoint = this._tmpVector;
  272. }
  273. worldPoint.setValue(contactPoint.x, contactPoint.y, contactPoint.z);
  274. impulse.setValue(force.x, force.y, force.z);
  275. impostor.physicsBody.applyImpulse(impulse, worldPoint);
  276. }
  277. else {
  278. Logger.Warn("Cannot be applied to a soft body");
  279. }
  280. }
  281. /**
  282. * Applies a force on the imposter
  283. * @param impostor imposter to apply force
  284. * @param force amount of force to be applied to the imposter
  285. * @param contactPoint the location to apply the force on the imposter
  286. */
  287. public applyForce(impostor: PhysicsImpostor, force: Vector3, contactPoint: Vector3) {
  288. if (!impostor.soft) {
  289. impostor.physicsBody.activate();
  290. var worldPoint = this._tmpAmmoVectorA;
  291. var impulse = this._tmpAmmoVectorB;
  292. // Convert contactPoint into world space
  293. if (impostor.object && impostor.object.getWorldMatrix) {
  294. impostor.object.getWorldMatrix().invertToRef(this._tmpMatrix);
  295. Vector3.TransformCoordinatesToRef(contactPoint, this._tmpMatrix, this._tmpVector);
  296. contactPoint = this._tmpVector;
  297. }
  298. worldPoint.setValue(contactPoint.x, contactPoint.y, contactPoint.z);
  299. impulse.setValue(force.x, force.y, force.z);
  300. impostor.physicsBody.applyForce(impulse, worldPoint);
  301. }
  302. else {
  303. Logger.Warn("Cannot be applied to a soft body");
  304. }
  305. }
  306. /**
  307. * Creates a physics body using the plugin
  308. * @param impostor the imposter to create the physics body on
  309. */
  310. public generatePhysicsBody(impostor: PhysicsImpostor) {
  311. impostor._pluginData = { toDispose: [] };
  312. //parent-child relationship
  313. if (impostor.parent) {
  314. if (impostor.physicsBody) {
  315. this.removePhysicsBody(impostor);
  316. impostor.forceUpdate();
  317. }
  318. return;
  319. }
  320. if (impostor.isBodyInitRequired()) {
  321. var colShape = this._createShape(impostor);
  322. var mass = impostor.getParam("mass");
  323. impostor._pluginData.mass = mass;
  324. if (impostor.soft) {
  325. Logger.Warn("Stiffness ");
  326. Ammo.castObject(colShape, Ammo.btCollisionObject).getCollisionShape().setMargin(0.05);
  327. this.world.addSoftBody(colShape, 1, -1);
  328. impostor.physicsBody = colShape;
  329. impostor._pluginData.toDispose.concat([colShape]);
  330. this.setBodyPressure(impostor, impostor.getParam("pressure"));
  331. this.setBodyStiffness(impostor, impostor.getParam("stiffness"));
  332. this.setBodyVelocityIterations(impostor, impostor.getParam("velocityIterations"));
  333. this.setBodyPositionIterations(impostor, impostor.getParam("positionIterations"));
  334. }
  335. else {
  336. Logger.Warn("mass " + impostor.mass);
  337. var localInertia = new Ammo.btVector3(0, 0, 0);
  338. var startTransform = new Ammo.btTransform();
  339. startTransform.setIdentity();
  340. if (mass !== 0) {
  341. colShape.calculateLocalInertia(mass, localInertia);
  342. }
  343. this._tmpAmmoVectorA.setValue(impostor.object.position.x, impostor.object.position.y, impostor.object.position.z);
  344. this._tmpAmmoQuaternion.setValue(impostor.object.rotationQuaternion!.x, impostor.object.rotationQuaternion!.y, impostor.object.rotationQuaternion!.z, impostor.object.rotationQuaternion!.w);
  345. startTransform.setOrigin(this._tmpAmmoVectorA);
  346. startTransform.setRotation(this._tmpAmmoQuaternion);
  347. var myMotionState = new Ammo.btDefaultMotionState(startTransform);
  348. var rbInfo = new Ammo.btRigidBodyConstructionInfo(mass, myMotionState, colShape, localInertia);
  349. var body = new Ammo.btRigidBody(rbInfo);
  350. // Make objects kinematic if it's mass is 0
  351. if (mass === 0) {
  352. body.setCollisionFlags(body.getCollisionFlags() | AmmoJSPlugin.KINEMATIC_FLAG);
  353. body.setActivationState(AmmoJSPlugin.DISABLE_DEACTIVATION_FLAG);
  354. }
  355. // Disable collision if NoImpostor, but keep collision if shape is btCompoundShape
  356. if (impostor.type == PhysicsImpostor.NoImpostor && !colShape.getChildShape) {
  357. body.setCollisionFlags(body.getCollisionFlags() | AmmoJSPlugin.DISABLE_COLLISION_FLAG);
  358. }
  359. this.world.addRigidBody(body);
  360. impostor.physicsBody = body;
  361. impostor._pluginData.toDispose.concat([body, rbInfo, myMotionState, startTransform, localInertia, colShape]);
  362. }
  363. this.setBodyRestitution(impostor, impostor.getParam("restitution"));
  364. this.setBodyFriction(impostor, impostor.getParam("friction"));
  365. }
  366. }
  367. /**
  368. * Removes the physics body from the imposter and disposes of the body's memory
  369. * @param impostor imposter to remove the physics body from
  370. */
  371. public removePhysicsBody(impostor: PhysicsImpostor) {
  372. if (this.world) {
  373. this.world.removeRigidBody(impostor.physicsBody);
  374. impostor._pluginData.toDispose.forEach((d: any) => {
  375. this.bjsAMMO.destroy(d);
  376. });
  377. }
  378. }
  379. /**
  380. * Generates a joint
  381. * @param impostorJoint the imposter joint to create the joint with
  382. */
  383. public generateJoint(impostorJoint: PhysicsImpostorJoint) {
  384. var mainBody = impostorJoint.mainImpostor.physicsBody;
  385. var connectedBody = impostorJoint.connectedImpostor.physicsBody;
  386. if (!mainBody || !connectedBody) {
  387. return;
  388. }
  389. var jointData = impostorJoint.joint.jointData;
  390. if (!jointData.mainPivot) {
  391. jointData.mainPivot = new Vector3(0, 0, 0);
  392. }
  393. if (!jointData.connectedPivot) {
  394. jointData.connectedPivot = new Vector3(0, 0, 0);
  395. }
  396. var joint: any;
  397. switch (impostorJoint.joint.type) {
  398. case PhysicsJoint.DistanceJoint:
  399. var distance = (<DistanceJointData>jointData).maxDistance;
  400. if (distance) {
  401. jointData.mainPivot = new Vector3(0, -distance / 2, 0);
  402. jointData.connectedPivot = new Vector3(0, distance / 2, 0);
  403. }
  404. joint = new Ammo.btPoint2PointConstraint(mainBody, connectedBody, new Ammo.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new Ammo.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z));
  405. break;
  406. case PhysicsJoint.HingeJoint:
  407. if (!jointData.mainAxis) {
  408. jointData.mainAxis = new Vector3(0, 0, 0);
  409. }
  410. if (!jointData.connectedAxis) {
  411. jointData.connectedAxis = new Vector3(0, 0, 0);
  412. }
  413. var mainAxis = new Ammo.btVector3(jointData.mainAxis.x, jointData.mainAxis.y, jointData.mainAxis.z);
  414. var connectedAxis = new Ammo.btVector3(jointData.connectedAxis.x, jointData.connectedAxis.y, jointData.connectedAxis.z);
  415. joint = new Ammo.btHingeConstraint(mainBody, connectedBody, new Ammo.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new Ammo.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z), mainAxis, connectedAxis);
  416. break;
  417. case PhysicsJoint.BallAndSocketJoint:
  418. joint = new Ammo.btPoint2PointConstraint(mainBody, connectedBody, new Ammo.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new Ammo.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z));
  419. break;
  420. default:
  421. Logger.Warn("JointType not currently supported by the Ammo plugin, falling back to PhysicsJoint.BallAndSocketJoint");
  422. joint = new Ammo.btPoint2PointConstraint(mainBody, connectedBody, new Ammo.btVector3(jointData.mainPivot.x, jointData.mainPivot.y, jointData.mainPivot.z), new Ammo.btVector3(jointData.connectedPivot.x, jointData.connectedPivot.y, jointData.connectedPivot.z));
  423. break;
  424. }
  425. this.world.addConstraint(joint, !impostorJoint.joint.jointData.collision);
  426. impostorJoint.joint.physicsJoint = joint;
  427. }
  428. /**
  429. * Removes a joint
  430. * @param impostorJoint the imposter joint to remove the joint from
  431. */
  432. public removeJoint(impostorJoint: PhysicsImpostorJoint) {
  433. if (this.world) {
  434. this.world.removeConstraint(impostorJoint.joint.physicsJoint);
  435. }
  436. }
  437. // adds all verticies (including child verticies) to the triangle mesh
  438. private _addMeshVerts(btTriangleMesh: any, topLevelObject: IPhysicsEnabledObject, object: IPhysicsEnabledObject) {
  439. var triangleCount = 0;
  440. if (object && object.getIndices && object.getWorldMatrix && object.getChildMeshes) {
  441. var indices = object.getIndices();
  442. if (!indices) {
  443. indices = [];
  444. }
  445. var vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
  446. if (!vertexPositions) {
  447. vertexPositions = [];
  448. }
  449. object.computeWorldMatrix(false);
  450. var faceCount = indices.length / 3;
  451. for (var i = 0; i < faceCount; i++) {
  452. var triPoints = [];
  453. for (var point = 0; point < 3; point++) {
  454. var v = new Vector3(vertexPositions[(indices[(i * 3) + point] * 3) + 0], vertexPositions[(indices[(i * 3) + point] * 3) + 1], vertexPositions[(indices[(i * 3) + point] * 3) + 2]);
  455. v = Vector3.TransformCoordinates(v, object.getWorldMatrix());
  456. v.subtractInPlace(topLevelObject.position);
  457. var vec: any;
  458. if (point == 0) {
  459. vec = this._tmpAmmoVectorA;
  460. } else if (point == 1) {
  461. vec = this._tmpAmmoVectorB;
  462. } else {
  463. vec = this._tmpAmmoVectorC;
  464. }
  465. vec.setValue(v.x, v.y, v.z);
  466. triPoints.push(vec);
  467. }
  468. btTriangleMesh.addTriangle(triPoints[0], triPoints[1], triPoints[2]);
  469. triangleCount++;
  470. }
  471. object.getChildMeshes().forEach((m) => {
  472. triangleCount += this._addMeshVerts(btTriangleMesh, topLevelObject, m);
  473. });
  474. }
  475. return triangleCount;
  476. }
  477. /**
  478. * Create an impostor's soft body
  479. * Initialise the soft body vertices to match its object's (mesh) vertices
  480. * Softbody vertices (nodes) are in world space and to match this
  481. * The object's position and rotation is set to zero and so its vertices are also then set in world space
  482. * @param impostor to create the softbody for
  483. */
  484. private _createSoftbody(impostor: PhysicsImpostor) {
  485. var object = impostor.object;
  486. if (object && object.getIndices && object.getWorldMatrix && object.getChildMeshes) {
  487. var indices = object.getIndices();
  488. if (!indices) {
  489. indices = [];
  490. }
  491. var vertexPositions = object.getVerticesData(VertexBuffer.PositionKind);
  492. if (!vertexPositions) {
  493. vertexPositions = [];
  494. }
  495. var vertexNormals = object.getVerticesData(VertexBuffer.NormalKind);
  496. if (!vertexNormals) {
  497. vertexNormals = [];
  498. }
  499. object.computeWorldMatrix(false);
  500. var triPoints = [];
  501. var triNorms = [];
  502. var newPoints = [];
  503. var newNorms = [];
  504. for (var i = 0; i < vertexPositions.length; i += 3) {
  505. var v = new Vector3(vertexPositions[i], vertexPositions[i + 1], vertexPositions[i + 2]);
  506. var n = new Vector3(vertexNormals[i], vertexNormals[i + 1], vertexNormals[i + 2]);
  507. v = Vector3.TransformCoordinates(v, object.getWorldMatrix());
  508. n = Vector3.TransformNormal(n, object.getWorldMatrix());
  509. triPoints.push(v.x, v.y, -v.z);
  510. triNorms.push(n.x, n.y, -n.z);
  511. newPoints.push(v.x, v.y, v.z);
  512. newNorms.push(n.x, n.y, n.z);
  513. }
  514. var vertex_data = new VertexData();
  515. vertex_data.positions = newPoints;
  516. vertex_data.normals = newNorms;
  517. vertex_data.uvs = object.getVerticesData(VertexBuffer.UVKind);
  518. vertex_data.colors = object.getVerticesData(VertexBuffer.ColorKind);
  519. if (object && object.getIndices) {
  520. vertex_data.indices = object.getIndices();
  521. }
  522. vertex_data.applyToMesh(<Mesh>object);
  523. object.position = Vector3.Zero();
  524. object.rotationQuaternion = null;
  525. object.rotation = Vector3.Zero();
  526. object.computeWorldMatrix(true);
  527. if (vertexPositions.length === 0) {
  528. return new Ammo.btCompoundShape();
  529. }
  530. else {
  531. var softBody = new Ammo.btSoftBodyHelpers().CreateFromTriMesh(
  532. this.world.getWorldInfo(),
  533. triPoints,
  534. object.getIndices(),
  535. indices.length / 3,
  536. true
  537. );
  538. var nbVertices = vertexPositions.length / 3;
  539. var bodyVertices = softBody.get_m_nodes();
  540. var node: any;
  541. var nodeNormals: any;
  542. for (var i = 0; i < nbVertices; i++) {
  543. node = bodyVertices.at(i);
  544. var nodeNormals = node.get_m_n();
  545. nodeNormals.setX(triNorms[3 * i]);
  546. nodeNormals.setY(triNorms[3 * i + 1]);
  547. nodeNormals.setZ(-triNorms[3 * i + 2]);
  548. }
  549. softBody.get_m_cfg().set_collisions(0x11);
  550. return softBody;
  551. }
  552. }
  553. }
  554. private _createShape(impostor: PhysicsImpostor, ignoreChildren = false) {
  555. var object = impostor.object;
  556. var returnValue: any;
  557. var extendSize = impostor.getObjectExtendSize();
  558. if (!ignoreChildren) {
  559. var meshChildren = impostor.object.getChildMeshes ? impostor.object.getChildMeshes(true) : [];
  560. returnValue = new Ammo.btCompoundShape();
  561. // Add shape of all children to the compound shape
  562. var childrenAdded = 0;
  563. meshChildren.forEach((childMesh) => {
  564. var childImpostor = childMesh.getPhysicsImpostor();
  565. if (childImpostor) {
  566. var shape = this._createShape(childImpostor);
  567. // Position needs to be scaled based on parent's scaling
  568. var parentMat = childMesh.parent!.getWorldMatrix().clone();
  569. var s = new Vector3();
  570. parentMat.decompose(s);
  571. this._tmpAmmoTransform.getOrigin().setValue(childMesh.position.x * s.x, childMesh.position.y * s.y, childMesh.position.z * s.z);
  572. this._tmpAmmoQuaternion.setValue(childMesh.rotationQuaternion!.x, childMesh.rotationQuaternion!.y, childMesh.rotationQuaternion!.z, childMesh.rotationQuaternion!.w);
  573. this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
  574. returnValue.addChildShape(this._tmpAmmoTransform, shape);
  575. childImpostor.dispose();
  576. childrenAdded++;
  577. }
  578. });
  579. if (childrenAdded > 0) {
  580. // Add parents shape as a child if present
  581. if (impostor.type != PhysicsImpostor.NoImpostor) {
  582. var shape = this._createShape(impostor, true);
  583. if (shape) {
  584. this._tmpAmmoTransform.getOrigin().setValue(0, 0, 0);
  585. this._tmpAmmoQuaternion.setValue(0, 0, 0, 1);
  586. this._tmpAmmoTransform.setRotation(this._tmpAmmoQuaternion);
  587. returnValue.addChildShape(this._tmpAmmoTransform, shape);
  588. }
  589. }
  590. return returnValue;
  591. } else {
  592. // If no children with impostors create the actual shape below instead
  593. Ammo.destroy(returnValue);
  594. returnValue = null;
  595. }
  596. }
  597. switch (impostor.type) {
  598. case PhysicsImpostor.SphereImpostor:
  599. returnValue = new Ammo.btSphereShape(extendSize.x / 2);
  600. break;
  601. case PhysicsImpostor.CylinderImpostor:
  602. this._tmpAmmoVectorA.setValue(extendSize.x / 2, extendSize.y / 2, extendSize.z / 2);
  603. returnValue = new Ammo.btCylinderShape(this._tmpAmmoVectorA);
  604. break;
  605. case PhysicsImpostor.PlaneImpostor:
  606. case PhysicsImpostor.BoxImpostor:
  607. this._tmpAmmoVectorA.setValue(extendSize.x / 2, extendSize.y / 2, extendSize.z / 2);
  608. returnValue = new Ammo.btBoxShape(this._tmpAmmoVectorA);
  609. break;
  610. case PhysicsImpostor.MeshImpostor:
  611. var tetraMesh = new Ammo.btTriangleMesh();
  612. impostor._pluginData.toDispose.concat([tetraMesh]);
  613. var triangeCount = this._addMeshVerts(tetraMesh, object, object);
  614. if (triangeCount == 0) {
  615. returnValue = new Ammo.btCompoundShape();
  616. } else {
  617. returnValue = new Ammo.btBvhTriangleMeshShape(tetraMesh);
  618. }
  619. break;
  620. case PhysicsImpostor.NoImpostor:
  621. // Fill with sphere but collision is disabled on the rigid body in generatePhysicsBody, using an empty shape caused unexpected movement with joints
  622. returnValue = new Ammo.btSphereShape(extendSize.x / 2);
  623. break;
  624. case PhysicsImpostor.SoftbodyImpostor:
  625. // Only usable with a mesh that has sufficient and shared vertices
  626. returnValue = this._createSoftbody(impostor);
  627. break;
  628. default:
  629. Logger.Warn("The impostor type is not currently supported by the ammo plugin.");
  630. break;
  631. }
  632. return returnValue;
  633. }
  634. /**
  635. * Sets the physics body position/rotation from the babylon mesh's position/rotation
  636. * @param impostor imposter containing the physics body and babylon object
  637. */
  638. public setTransformationFromPhysicsBody(impostor: PhysicsImpostor) {
  639. impostor.physicsBody.getMotionState().getWorldTransform(this._tmpAmmoTransform);
  640. impostor.object.position.set(this._tmpAmmoTransform.getOrigin().x(), this._tmpAmmoTransform.getOrigin().y(), this._tmpAmmoTransform.getOrigin().z());
  641. if (!impostor.object.rotationQuaternion) {
  642. if (impostor.object.rotation) {
  643. this._tmpQuaternion.set(this._tmpAmmoTransform.getRotation().x(), this._tmpAmmoTransform.getRotation().y(), this._tmpAmmoTransform.getRotation().z(), this._tmpAmmoTransform.getRotation().w());
  644. this._tmpQuaternion.toEulerAnglesToRef(impostor.object.rotation);
  645. }
  646. } else {
  647. impostor.object.rotationQuaternion.set(this._tmpAmmoTransform.getRotation().x(), this._tmpAmmoTransform.getRotation().y(), this._tmpAmmoTransform.getRotation().z(), this._tmpAmmoTransform.getRotation().w());
  648. }
  649. }
  650. /**
  651. * Sets the babylon object's position/rotation from the physics body's position/rotation
  652. * @param impostor imposter containing the physics body and babylon object
  653. * @param newPosition new position
  654. * @param newRotation new rotation
  655. */
  656. public setPhysicsBodyTransformation(impostor: PhysicsImpostor, newPosition: Vector3, newRotation: Quaternion) {
  657. var trans = impostor.physicsBody.getWorldTransform();
  658. // If rotation/position has changed update and activate riged body
  659. if (
  660. trans.getOrigin().x() != newPosition.x ||
  661. trans.getOrigin().y() != newPosition.y ||
  662. trans.getOrigin().z() != newPosition.z ||
  663. trans.getRotation().x() != newRotation.x ||
  664. trans.getRotation().y() != newRotation.y ||
  665. trans.getRotation().z() != newRotation.z ||
  666. trans.getRotation().w() != newRotation.w
  667. ) {
  668. this._tmpAmmoVectorA.setValue(newPosition.x, newPosition.y, newPosition.z);
  669. trans.setOrigin(this._tmpAmmoVectorA);
  670. this._tmpAmmoQuaternion.setValue(newRotation.x, newRotation.y, newRotation.z, newRotation.w);
  671. trans.setRotation(this._tmpAmmoQuaternion);
  672. impostor.physicsBody.setWorldTransform(trans);
  673. if (impostor.mass == 0) {
  674. // Kinematic objects must be updated using motion state
  675. var motionState = impostor.physicsBody.getMotionState();
  676. if (motionState) {
  677. motionState.setWorldTransform(trans);
  678. }
  679. } else {
  680. impostor.physicsBody.activate();
  681. }
  682. }
  683. }
  684. /**
  685. * If this plugin is supported
  686. * @returns true if its supported
  687. */
  688. public isSupported(): boolean {
  689. return this.bjsAMMO !== undefined;
  690. }
  691. /**
  692. * Sets the linear velocity of the physics body
  693. * @param impostor imposter to set the velocity on
  694. * @param velocity velocity to set
  695. */
  696. public setLinearVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
  697. this._tmpAmmoVectorA.setValue(velocity.x, velocity.y, velocity.z);
  698. if (impostor.soft) {
  699. impostor.physicsBody.linearVelocity(this._tmpAmmoVectorA);
  700. }
  701. else {
  702. impostor.physicsBody.setLinearVelocity(this._tmpAmmoVectorA);
  703. }
  704. }
  705. /**
  706. * Sets the angular velocity of the physics body
  707. * @param impostor imposter to set the velocity on
  708. * @param velocity velocity to set
  709. */
  710. public setAngularVelocity(impostor: PhysicsImpostor, velocity: Vector3) {
  711. this._tmpAmmoVectorA.setValue(velocity.x, velocity.y, velocity.z);
  712. if (impostor.soft) {
  713. impostor.physicsBody.angularVelocity(this._tmpAmmoVectorA);
  714. }
  715. else {
  716. impostor.physicsBody.setAngularVelocity(this._tmpAmmoVectorA);
  717. }
  718. }
  719. /**
  720. * gets the linear velocity
  721. * @param impostor imposter to get linear velocity from
  722. * @returns linear velocity
  723. */
  724. public getLinearVelocity(impostor: PhysicsImpostor): Nullable<Vector3> {
  725. if (impostor.soft) {
  726. var v = impostor.physicsBody.linearVelocity();
  727. }
  728. else {
  729. var v = impostor.physicsBody.getLinearVelocity();
  730. }
  731. if (!v) {
  732. return null;
  733. }
  734. return new Vector3(v.x(), v.y(), v.z());
  735. }
  736. /**
  737. * gets the angular velocity
  738. * @param impostor imposter to get angular velocity from
  739. * @returns angular velocity
  740. */
  741. public getAngularVelocity(impostor: PhysicsImpostor): Nullable<Vector3> {
  742. if (impostor.soft) {
  743. var v = impostor.physicsBody.angularVelocity();
  744. }
  745. else {
  746. var v = impostor.physicsBody.getAngularVelocity();
  747. }
  748. if (!v) {
  749. return null;
  750. }
  751. return new Vector3(v.x(), v.y(), v.z());
  752. }
  753. /**
  754. * Sets the mass of physics body
  755. * @param impostor imposter to set the mass on
  756. * @param mass mass to set
  757. */
  758. public setBodyMass(impostor: PhysicsImpostor, mass: number) {
  759. if (impostor.soft) {
  760. impostor.physicsBody.setTotalMass(mass, false);
  761. }
  762. else {
  763. impostor.physicsBody.setMassProps(mass);
  764. }
  765. impostor._pluginData.mass = mass;
  766. }
  767. /**
  768. * Gets the mass of the physics body
  769. * @param impostor imposter to get the mass from
  770. * @returns mass
  771. */
  772. public getBodyMass(impostor: PhysicsImpostor): number {
  773. return impostor._pluginData.mass;
  774. }
  775. /**
  776. * Gets friction of the impostor
  777. * @param impostor impostor to get friction from
  778. * @returns friction value
  779. */
  780. public getBodyFriction(impostor: PhysicsImpostor): number {
  781. return impostor._pluginData.friction;
  782. }
  783. /**
  784. * Sets friction of the impostor
  785. * @param impostor impostor to set friction on
  786. * @param friction friction value
  787. */
  788. public setBodyFriction(impostor: PhysicsImpostor, friction: number) {
  789. if (impostor.soft) {
  790. impostor.physicsBody.get_m_cfg().set_kDF(friction);
  791. }
  792. else {
  793. impostor.physicsBody.setFriction(friction);
  794. }
  795. impostor._pluginData.friction = friction;
  796. }
  797. /**
  798. * Gets restitution of the impostor
  799. * @param impostor impostor to get restitution from
  800. * @returns restitution value
  801. */
  802. public getBodyRestitution(impostor: PhysicsImpostor): number {
  803. return impostor._pluginData.restitution;
  804. }
  805. /**
  806. * Sets resitution of the impostor
  807. * @param impostor impostor to set resitution on
  808. * @param restitution resitution value
  809. */
  810. public setBodyRestitution(impostor: PhysicsImpostor, restitution: number) {
  811. impostor.physicsBody.setRestitution(restitution);
  812. impostor._pluginData.restitution = restitution;
  813. }
  814. /**
  815. * Gets pressure inside the impostor
  816. * @param impostor impostor to get pressure from
  817. * @returns pressure value
  818. */
  819. public getBodyPressure(impostor: PhysicsImpostor): number {
  820. if (!impostor.soft) {
  821. Logger.Warn("Pressure is not a property of a rigid body");
  822. return 0;
  823. }
  824. return impostor._pluginData.pressure;
  825. }
  826. /**
  827. * Sets pressure inside the impostor
  828. * @param impostor impostor to set pressure on
  829. * @param pressure pressure value
  830. */
  831. public setBodyPressure(impostor: PhysicsImpostor, pressure: number) {
  832. if (impostor.soft) {
  833. impostor.physicsBody.get_m_cfg().set_kPR(pressure);
  834. impostor._pluginData.pressure = pressure;
  835. }
  836. else {
  837. Logger.Warn("Pressure cannot be applied to a rigid body");
  838. }
  839. }
  840. /**
  841. * Gets stiffness of the impostor
  842. * @param impostor impostor to get stiffness from
  843. * @returns pressure value
  844. */
  845. public getBodyStiffness(impostor: PhysicsImpostor): number {
  846. if (!impostor.soft) {
  847. Logger.Warn("Stiffness is not a property of a rigid body");
  848. return 0;
  849. }
  850. return impostor._pluginData.stiffness;
  851. }
  852. /**
  853. * Sets stiffness of the impostor
  854. * @param impostor impostor to set stiffness on
  855. * @param stiffness stiffness value from 0 to 1
  856. */
  857. public setBodyStiffness(impostor: PhysicsImpostor, stiffness: number) {
  858. if (impostor.soft) {
  859. stiffness = stiffness < 0 ? 0 : stiffness;
  860. stiffness = stiffness > 1 ? 1 : stiffness;
  861. impostor.physicsBody.get_m_materials().at(0).set_m_kLST(stiffness);
  862. impostor._pluginData.stiffness = stiffness;
  863. }
  864. else {
  865. Logger.Warn("Stiffness cannot be applied to a rigid body");
  866. }
  867. }
  868. /**
  869. * Gets velocityIterations of the impostor
  870. * @param impostor impostor to get velocity iterations from
  871. * @returns velocityIterations value
  872. */
  873. public getBodyVelocityIterations(impostor: PhysicsImpostor): number {
  874. if (!impostor.soft) {
  875. Logger.Warn("Velocity iterations is not a property of a rigid body");
  876. return 0;
  877. }
  878. return impostor._pluginData.velocityIterations;
  879. }
  880. /**
  881. * Sets velocityIterations of the impostor
  882. * @param impostor impostor to set velocity iterations on
  883. * @param velocityIterations velocityIterations value
  884. */
  885. public setBodyVelocityIterations(impostor: PhysicsImpostor, velocityIterations: number) {
  886. if (impostor.soft) {
  887. velocityIterations = velocityIterations < 0 ? 0 : velocityIterations;
  888. impostor.physicsBody.get_m_cfg().set_viterations(velocityIterations);
  889. impostor._pluginData.velocityIterations = velocityIterations;
  890. }
  891. else {
  892. Logger.Warn("Velocity iterations cannot be applied to a rigid body");
  893. }
  894. }
  895. /**
  896. * Gets positionIterations of the impostor
  897. * @param impostor impostor to get position iterations from
  898. * @returns positionIterations value
  899. */
  900. public getBodyPositionIterations(impostor: PhysicsImpostor): number {
  901. if (!impostor.soft) {
  902. Logger.Warn("Position iterations is not a property of a rigid body");
  903. return 0;
  904. }
  905. return impostor._pluginData.positionIterations;
  906. }
  907. /**
  908. * Sets positionIterations of the impostor
  909. * @param impostor impostor to set position on
  910. * @param positionIterations positionIterations value
  911. */
  912. public setBodyPositionIterations(impostor: PhysicsImpostor, positionIterations: number) {
  913. if (impostor.soft) {
  914. positionIterations = positionIterations < 0 ? 0 : positionIterations;
  915. impostor.physicsBody.get_m_cfg().set_piterations(positionIterations);
  916. impostor._pluginData.positionIterations = positionIterations;
  917. }
  918. else {
  919. Logger.Warn("Position iterations cannot be applied to a rigid body");
  920. }
  921. }
  922. /**
  923. * Sleeps the physics body and stops it from being active
  924. * @param impostor impostor to sleep
  925. */
  926. public sleepBody(impostor: PhysicsImpostor) {
  927. Logger.Warn("sleepBody is not currently supported by the Ammo physics plugin");
  928. }
  929. /**
  930. * Activates the physics body
  931. * @param impostor impostor to activate
  932. */
  933. public wakeUpBody(impostor: PhysicsImpostor) {
  934. impostor.physicsBody.activate();
  935. }
  936. /**
  937. * Updates the distance parameters of the joint
  938. * @param joint joint to update
  939. * @param maxDistance maximum distance of the joint
  940. * @param minDistance minimum distance of the joint
  941. */
  942. public updateDistanceJoint(joint: PhysicsJoint, maxDistance: number, minDistance?: number) {
  943. Logger.Warn("updateDistanceJoint is not currently supported by the Ammo physics plugin");
  944. }
  945. /**
  946. * Sets a motor on the joint
  947. * @param joint joint to set motor on
  948. * @param speed speed of the motor
  949. * @param maxForce maximum force of the motor
  950. * @param motorIndex index of the motor
  951. */
  952. public setMotor(joint: IMotorEnabledJoint, speed?: number, maxForce?: number, motorIndex?: number) {
  953. joint.physicsJoint.enableAngularMotor(true, speed, maxForce);
  954. }
  955. /**
  956. * Sets the motors limit
  957. * @param joint joint to set limit on
  958. * @param upperLimit upper limit
  959. * @param lowerLimit lower limit
  960. */
  961. public setLimit(joint: IMotorEnabledJoint, upperLimit: number, lowerLimit?: number) {
  962. Logger.Warn("setLimit is not currently supported by the Ammo physics plugin");
  963. }
  964. /**
  965. * Syncs the position and rotation of a mesh with the impostor
  966. * @param mesh mesh to sync
  967. * @param impostor impostor to update the mesh with
  968. */
  969. public syncMeshWithImpostor(mesh: AbstractMesh, impostor: PhysicsImpostor) {
  970. var body = impostor.physicsBody;
  971. body.getMotionState().getWorldTransform(this._tmpAmmoTransform);
  972. mesh.position.x = this._tmpAmmoTransform.getOrigin().x();
  973. mesh.position.y = this._tmpAmmoTransform.getOrigin().y();
  974. mesh.position.z = this._tmpAmmoTransform.getOrigin().z();
  975. if (mesh.rotationQuaternion) {
  976. mesh.rotationQuaternion.x = this._tmpAmmoTransform.getRotation().x();
  977. mesh.rotationQuaternion.y = this._tmpAmmoTransform.getRotation().y();
  978. mesh.rotationQuaternion.z = this._tmpAmmoTransform.getRotation().z();
  979. mesh.rotationQuaternion.w = this._tmpAmmoTransform.getRotation().w();
  980. }
  981. }
  982. /**
  983. * Gets the radius of the impostor
  984. * @param impostor impostor to get radius from
  985. * @returns the radius
  986. */
  987. public getRadius(impostor: PhysicsImpostor): number {
  988. var exntend = impostor.getObjectExtendSize();
  989. return exntend.x / 2;
  990. }
  991. /**
  992. * Gets the box size of the impostor
  993. * @param impostor impostor to get box size from
  994. * @param result the resulting box size
  995. */
  996. public getBoxSizeToRef(impostor: PhysicsImpostor, result: Vector3): void {
  997. var exntend = impostor.getObjectExtendSize();
  998. result.x = exntend.x;
  999. result.y = exntend.y;
  1000. result.z = exntend.z;
  1001. }
  1002. /**
  1003. * Disposes of the impostor
  1004. */
  1005. public dispose() {
  1006. // Dispose of world
  1007. Ammo.destroy(this.world);
  1008. Ammo.destroy(this._solver);
  1009. Ammo.destroy(this._overlappingPairCache);
  1010. Ammo.destroy(this._dispatcher);
  1011. Ammo.destroy(this._collisionConfiguration);
  1012. // Dispose of tmp variables
  1013. Ammo.destroy(this._tmpAmmoVectorA);
  1014. Ammo.destroy(this._tmpAmmoVectorB);
  1015. Ammo.destroy(this._tmpAmmoVectorC);
  1016. Ammo.destroy(this._tmpAmmoTransform);
  1017. Ammo.destroy(this._tmpAmmoQuaternion);
  1018. Ammo.destroy(this._tmpAmmoConcreteContactResultCallback);
  1019. this.world = null;
  1020. }
  1021. }