babylon.oimoJSPlugin.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. var BABYLON;
  2. (function (BABYLON) {
  3. var OimoJSPlugin = (function () {
  4. function OimoJSPlugin() {
  5. this._registeredMeshes = [];
  6. /**
  7. * Update the body position according to the mesh position
  8. * @param mesh
  9. */
  10. this.updateBodyPosition = function (mesh) {
  11. for (var index = 0; index < this._registeredMeshes.length; index++) {
  12. var registeredMesh = this._registeredMeshes[index];
  13. if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
  14. var body = registeredMesh.body.body;
  15. mesh.computeWorldMatrix(true);
  16. var center = mesh.getBoundingInfo().boundingBox.center;
  17. body.setPosition(center.x, center.y, center.z);
  18. body.setRotation(mesh.rotation.x, mesh.rotation.y, mesh.rotation.z);
  19. return;
  20. }
  21. // Case where the parent has been updated
  22. if (registeredMesh.mesh.parent === mesh) {
  23. mesh.computeWorldMatrix(true);
  24. registeredMesh.mesh.computeWorldMatrix(true);
  25. var absolutePosition = registeredMesh.mesh.getAbsolutePosition();
  26. var absoluteRotation = mesh.rotation;
  27. body = registeredMesh.body.body;
  28. body.setPosition(absolutePosition.x, absolutePosition.y, absolutePosition.z);
  29. body.setRotation(absoluteRotation.x, absoluteRotation.y, absoluteRotation.z);
  30. return;
  31. }
  32. }
  33. };
  34. }
  35. OimoJSPlugin.prototype._checkWithEpsilon = function (value) {
  36. return value < BABYLON.PhysicsEngine.Epsilon ? BABYLON.PhysicsEngine.Epsilon : value;
  37. };
  38. OimoJSPlugin.prototype.initialize = function (iterations) {
  39. this._world = new OIMO.World();
  40. this._world.clear();
  41. };
  42. OimoJSPlugin.prototype.setGravity = function (gravity) {
  43. this._world.gravity = gravity;
  44. };
  45. OimoJSPlugin.prototype.registerMesh = function (mesh, impostor, options) {
  46. var body = null;
  47. this.unregisterMesh(mesh);
  48. mesh.computeWorldMatrix(true);
  49. var initialRotation = null;
  50. if (mesh.rotationQuaternion) {
  51. initialRotation = mesh.rotationQuaternion.clone();
  52. mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
  53. mesh.computeWorldMatrix(true);
  54. }
  55. var bbox = mesh.getBoundingInfo().boundingBox;
  56. // The delta between the mesh position and the mesh bounding box center
  57. var deltaPosition = mesh.position.subtract(bbox.center);
  58. // Transform delta position with the rotation
  59. if (initialRotation) {
  60. var m = new BABYLON.Matrix();
  61. initialRotation.toRotationMatrix(m);
  62. deltaPosition = BABYLON.Vector3.TransformCoordinates(deltaPosition, m);
  63. }
  64. switch (impostor) {
  65. case BABYLON.PhysicsEngine.SphereImpostor:
  66. var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
  67. var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
  68. var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
  69. var size = Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2;
  70. body = new OIMO.Body({
  71. type: 'sphere',
  72. size: [size],
  73. pos: [bbox.center.x, bbox.center.y, bbox.center.z],
  74. rot: [mesh.rotation.x / OIMO.TO_RAD, mesh.rotation.y / OIMO.TO_RAD, mesh.rotation.z / OIMO.TO_RAD],
  75. move: options.mass != 0,
  76. config: [options.mass, options.friction, options.restitution],
  77. world: this._world
  78. });
  79. break;
  80. case BABYLON.PhysicsEngine.PlaneImpostor:
  81. case BABYLON.PhysicsEngine.CylinderImpostor:
  82. case BABYLON.PhysicsEngine.BoxImpostor:
  83. var min = bbox.minimumWorld;
  84. var max = bbox.maximumWorld;
  85. var box = max.subtract(min);
  86. var sizeX = this._checkWithEpsilon(box.x);
  87. var sizeY = this._checkWithEpsilon(box.y);
  88. var sizeZ = this._checkWithEpsilon(box.z);
  89. body = new OIMO.Body({
  90. type: 'box',
  91. size: [sizeX, sizeY, sizeZ],
  92. pos: [bbox.center.x, bbox.center.y, bbox.center.z],
  93. rot: [mesh.rotation.x / OIMO.TO_RAD, mesh.rotation.y / OIMO.TO_RAD, mesh.rotation.z / OIMO.TO_RAD],
  94. move: options.mass != 0,
  95. config: [options.mass, options.friction, options.restitution],
  96. world: this._world
  97. });
  98. break;
  99. }
  100. //If quaternion was set as the rotation of the object
  101. if (initialRotation) {
  102. //We have to access the rigid body's properties to set the quaternion.
  103. //The setQuaternion function of Oimo only sets the newOrientation that is only set after an impulse is given or a collision.
  104. body.body.orientation = new OIMO.Quat(initialRotation.w, initialRotation.x, initialRotation.y, initialRotation.z);
  105. //update the internal rotation matrix
  106. body.body.syncShapes();
  107. }
  108. this._registeredMeshes.push({
  109. mesh: mesh,
  110. body: body,
  111. delta: deltaPosition
  112. });
  113. return body;
  114. };
  115. OimoJSPlugin.prototype.registerMeshesAsCompound = function (parts, options) {
  116. var types = [], sizes = [], positions = [], rotations = [];
  117. var initialMesh = parts[0].mesh;
  118. for (var index = 0; index < parts.length; index++) {
  119. var part = parts[index];
  120. var bodyParameters = this._createBodyAsCompound(part, options, initialMesh);
  121. types.push(bodyParameters.type);
  122. sizes.push.apply(sizes, bodyParameters.size);
  123. positions.push.apply(positions, bodyParameters.pos);
  124. rotations.push.apply(rotations, bodyParameters.rot);
  125. }
  126. var body = new OIMO.Body({
  127. type: types,
  128. size: sizes,
  129. pos: positions,
  130. rot: rotations,
  131. move: options.mass != 0,
  132. config: [options.mass, options.friction, options.restitution],
  133. world: this._world
  134. });
  135. this._registeredMeshes.push({
  136. mesh: initialMesh,
  137. body: body
  138. });
  139. return body;
  140. };
  141. OimoJSPlugin.prototype._createBodyAsCompound = function (part, options, initialMesh) {
  142. var bodyParameters = null;
  143. var mesh = part.mesh;
  144. // We need the bounding box/sphere info to compute the physics body
  145. mesh.computeWorldMatrix();
  146. switch (part.impostor) {
  147. case BABYLON.PhysicsEngine.SphereImpostor:
  148. var bbox = mesh.getBoundingInfo().boundingBox;
  149. var radiusX = bbox.maximumWorld.x - bbox.minimumWorld.x;
  150. var radiusY = bbox.maximumWorld.y - bbox.minimumWorld.y;
  151. var radiusZ = bbox.maximumWorld.z - bbox.minimumWorld.z;
  152. var size = Math.max(this._checkWithEpsilon(radiusX), this._checkWithEpsilon(radiusY), this._checkWithEpsilon(radiusZ)) / 2;
  153. bodyParameters = {
  154. type: 'sphere',
  155. /* bug with oimo : sphere needs 3 sizes in this case */
  156. size: [size, -1, -1],
  157. pos: [mesh.position.x, mesh.position.y, mesh.position.z],
  158. rot: [mesh.rotation.x / OIMO.TO_RAD, mesh.rotation.y / OIMO.TO_RAD, mesh.rotation.z / OIMO.TO_RAD]
  159. };
  160. break;
  161. case BABYLON.PhysicsEngine.PlaneImpostor:
  162. case BABYLON.PhysicsEngine.BoxImpostor:
  163. bbox = mesh.getBoundingInfo().boundingBox;
  164. var min = bbox.minimumWorld;
  165. var max = bbox.maximumWorld;
  166. var box = max.subtract(min);
  167. var sizeX = this._checkWithEpsilon(box.x);
  168. var sizeY = this._checkWithEpsilon(box.y);
  169. var sizeZ = this._checkWithEpsilon(box.z);
  170. var relativePosition = mesh.position;
  171. bodyParameters = {
  172. type: 'box',
  173. size: [sizeX, sizeY, sizeZ],
  174. pos: [relativePosition.x, relativePosition.y, relativePosition.z],
  175. rot: [mesh.rotation.x / OIMO.TO_RAD, mesh.rotation.y / OIMO.TO_RAD, mesh.rotation.z / OIMO.TO_RAD]
  176. };
  177. break;
  178. }
  179. return bodyParameters;
  180. };
  181. OimoJSPlugin.prototype.unregisterMesh = function (mesh) {
  182. for (var index = 0; index < this._registeredMeshes.length; index++) {
  183. var registeredMesh = this._registeredMeshes[index];
  184. if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
  185. if (registeredMesh.body) {
  186. this._world.removeRigidBody(registeredMesh.body.body);
  187. this._unbindBody(registeredMesh.body);
  188. }
  189. this._registeredMeshes.splice(index, 1);
  190. return;
  191. }
  192. }
  193. };
  194. OimoJSPlugin.prototype._unbindBody = function (body) {
  195. for (var index = 0; index < this._registeredMeshes.length; index++) {
  196. var registeredMesh = this._registeredMeshes[index];
  197. if (registeredMesh.body === body) {
  198. registeredMesh.body = null;
  199. }
  200. }
  201. };
  202. OimoJSPlugin.prototype.applyImpulse = function (mesh, force, contactPoint) {
  203. for (var index = 0; index < this._registeredMeshes.length; index++) {
  204. var registeredMesh = this._registeredMeshes[index];
  205. if (registeredMesh.mesh === mesh || registeredMesh.mesh === mesh.parent) {
  206. // Get object mass to have a behaviour similar to cannon.js
  207. var mass = registeredMesh.body.body.massInfo.mass;
  208. // The force is scaled with the mass of object
  209. registeredMesh.body.body.applyImpulse(contactPoint.scale(OIMO.INV_SCALE), force.scale(OIMO.INV_SCALE * mass));
  210. return;
  211. }
  212. }
  213. };
  214. OimoJSPlugin.prototype.createLink = function (mesh1, mesh2, pivot1, pivot2, options) {
  215. var body1 = null, body2 = null;
  216. for (var index = 0; index < this._registeredMeshes.length; index++) {
  217. var registeredMesh = this._registeredMeshes[index];
  218. if (registeredMesh.mesh === mesh1) {
  219. body1 = registeredMesh.body.body;
  220. }
  221. else if (registeredMesh.mesh === mesh2) {
  222. body2 = registeredMesh.body.body;
  223. }
  224. }
  225. if (!body1 || !body2) {
  226. return false;
  227. }
  228. if (!options) {
  229. options = {};
  230. }
  231. new OIMO.Link({
  232. type: options.type,
  233. body1: body1,
  234. body2: body2,
  235. min: options.min,
  236. max: options.max,
  237. axe1: options.axe1,
  238. axe2: options.axe2,
  239. pos1: [pivot1.x, pivot1.y, pivot1.z],
  240. pos2: [pivot2.x, pivot2.y, pivot2.z],
  241. collision: options.collision,
  242. spring: options.spring,
  243. world: this._world
  244. });
  245. return true;
  246. };
  247. OimoJSPlugin.prototype.dispose = function () {
  248. this._world.clear();
  249. while (this._registeredMeshes.length) {
  250. this.unregisterMesh(this._registeredMeshes[0].mesh);
  251. }
  252. };
  253. OimoJSPlugin.prototype.isSupported = function () {
  254. return OIMO !== undefined;
  255. };
  256. OimoJSPlugin.prototype._getLastShape = function (body) {
  257. var lastShape = body.shapes;
  258. while (lastShape.next) {
  259. lastShape = lastShape.next;
  260. }
  261. return lastShape;
  262. };
  263. OimoJSPlugin.prototype.runOneStep = function (time) {
  264. this._world.step();
  265. // Update the position of all registered meshes
  266. var i = this._registeredMeshes.length;
  267. var m;
  268. while (i--) {
  269. var body = this._registeredMeshes[i].body.body;
  270. var mesh = this._registeredMeshes[i].mesh;
  271. var delta = this._registeredMeshes[i].delta;
  272. if (!body.sleeping) {
  273. if (body.shapes.next) {
  274. var parentShape = this._getLastShape(body);
  275. mesh.position.x = parentShape.position.x * OIMO.WORLD_SCALE;
  276. mesh.position.y = parentShape.position.y * OIMO.WORLD_SCALE;
  277. mesh.position.z = parentShape.position.z * OIMO.WORLD_SCALE;
  278. var mtx = BABYLON.Matrix.FromArray(body.getMatrix());
  279. if (!mesh.rotationQuaternion) {
  280. mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
  281. }
  282. mesh.rotationQuaternion.fromRotationMatrix(mtx);
  283. mesh.computeWorldMatrix();
  284. }
  285. else {
  286. m = body.getMatrix();
  287. mtx = BABYLON.Matrix.FromArray(m);
  288. // Body position
  289. var bodyX = mtx.m[12], bodyY = mtx.m[13], bodyZ = mtx.m[14];
  290. if (!delta) {
  291. mesh.position.x = bodyX;
  292. mesh.position.y = bodyY;
  293. mesh.position.z = bodyZ;
  294. }
  295. else {
  296. mesh.position.x = bodyX + delta.x;
  297. mesh.position.y = bodyY + delta.y;
  298. mesh.position.z = bodyZ + delta.z;
  299. }
  300. if (!mesh.rotationQuaternion) {
  301. mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
  302. }
  303. BABYLON.Quaternion.FromRotationMatrixToRef(mtx, mesh.rotationQuaternion);
  304. mesh.computeWorldMatrix();
  305. }
  306. }
  307. }
  308. };
  309. return OimoJSPlugin;
  310. })();
  311. BABYLON.OimoJSPlugin = OimoJSPlugin;
  312. })(BABYLON || (BABYLON = {}));
  313. //# sourceMappingURL=babylon.oimoJSPlugin.js.map