babylon.collisionWorker.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. var BABYLON;
  2. (function (BABYLON) {
  3. //If this file is included in the main thread, this will be initialized.
  4. BABYLON.WorkerIncluded = true;
  5. var CollisionCache = (function () {
  6. function CollisionCache() {
  7. this._meshes = {};
  8. this._geometries = {};
  9. }
  10. CollisionCache.prototype.getMeshes = function () {
  11. return this._meshes;
  12. };
  13. CollisionCache.prototype.getGeometries = function () {
  14. return this._geometries;
  15. };
  16. CollisionCache.prototype.getMesh = function (id) {
  17. return this._meshes[id];
  18. };
  19. CollisionCache.prototype.addMesh = function (mesh) {
  20. this._meshes[mesh.uniqueId] = mesh;
  21. };
  22. CollisionCache.prototype.removeMesh = function (uniqueId) {
  23. delete this._meshes[uniqueId];
  24. };
  25. CollisionCache.prototype.getGeometry = function (id) {
  26. return this._geometries[id];
  27. };
  28. CollisionCache.prototype.addGeometry = function (geometry) {
  29. this._geometries[geometry.id] = geometry;
  30. };
  31. CollisionCache.prototype.removeGeometry = function (id) {
  32. delete this._geometries[id];
  33. };
  34. return CollisionCache;
  35. }());
  36. BABYLON.CollisionCache = CollisionCache;
  37. var CollideWorker = (function () {
  38. function CollideWorker(collider, _collisionCache, finalPosition) {
  39. this.collider = collider;
  40. this._collisionCache = _collisionCache;
  41. this.finalPosition = finalPosition;
  42. this.collisionsScalingMatrix = BABYLON.Matrix.Zero();
  43. this.collisionTranformationMatrix = BABYLON.Matrix.Zero();
  44. }
  45. CollideWorker.prototype.collideWithWorld = function (position, velocity, maximumRetry, excludedMeshUniqueId) {
  46. //TODO CollisionsEpsilon should be defined here and not in the engine.
  47. var closeDistance = 0.01; //is initializing here correct? A quick look - looks like it is fine.
  48. if (this.collider.retry >= maximumRetry) {
  49. this.finalPosition.copyFrom(position);
  50. return;
  51. }
  52. this.collider._initialize(position, velocity, closeDistance);
  53. // Check all meshes
  54. var meshes = this._collisionCache.getMeshes();
  55. var keys = Object.keys(meshes);
  56. var len = keys.length;
  57. var uniqueId;
  58. for (var i = 0; i < len; ++i) {
  59. uniqueId = keys[i];
  60. if (parseInt(uniqueId) != excludedMeshUniqueId) {
  61. var mesh = meshes[uniqueId];
  62. if (mesh.checkCollisions)
  63. this.checkCollision(mesh);
  64. }
  65. }
  66. if (!this.collider.collisionFound) {
  67. position.addToRef(velocity, this.finalPosition);
  68. return;
  69. }
  70. if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
  71. this.collider._getResponse(position, velocity);
  72. }
  73. if (velocity.length() <= closeDistance) {
  74. this.finalPosition.copyFrom(position);
  75. return;
  76. }
  77. this.collider.retry++;
  78. this.collideWithWorld(position, velocity, maximumRetry, excludedMeshUniqueId);
  79. };
  80. CollideWorker.prototype.checkCollision = function (mesh) {
  81. if (!this.collider._canDoCollision(BABYLON.Vector3.FromArray(mesh.sphereCenter), mesh.sphereRadius, BABYLON.Vector3.FromArray(mesh.boxMinimum), BABYLON.Vector3.FromArray(mesh.boxMaximum))) {
  82. return;
  83. }
  84. ;
  85. // Transformation matrix
  86. BABYLON.Matrix.ScalingToRef(1.0 / this.collider.radius.x, 1.0 / this.collider.radius.y, 1.0 / this.collider.radius.z, this.collisionsScalingMatrix);
  87. var worldFromCache = BABYLON.Matrix.FromArray(mesh.worldMatrixFromCache);
  88. worldFromCache.multiplyToRef(this.collisionsScalingMatrix, this.collisionTranformationMatrix);
  89. this.processCollisionsForSubMeshes(this.collisionTranformationMatrix, mesh);
  90. //return colTransMat;
  91. };
  92. CollideWorker.prototype.processCollisionsForSubMeshes = function (transformMatrix, mesh) {
  93. //if (this._submeshesOctree && this.useOctreeForCollisions) {
  94. // var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
  95. // var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius);
  96. // len = intersections.length;
  97. // subMeshes = intersections.data;
  98. //} else {
  99. var subMeshes = mesh.subMeshes;
  100. var len = subMeshes.length;
  101. //}
  102. if (!mesh.geometryId) {
  103. console.log("no mesh geometry id");
  104. return;
  105. }
  106. var meshGeometry = this._collisionCache.getGeometry(mesh.geometryId);
  107. if (!meshGeometry) {
  108. console.log("couldn't find geometry", mesh.geometryId);
  109. return;
  110. }
  111. for (var index = 0; index < len; index++) {
  112. var subMesh = subMeshes[index];
  113. // Bounding test
  114. if (len > 1 && !this.checkSubmeshCollision(subMesh))
  115. continue;
  116. this.collideForSubMesh(subMesh, transformMatrix, meshGeometry);
  117. if (this.collider.collisionFound) {
  118. this.collider.collidedMesh = mesh.uniqueId;
  119. }
  120. }
  121. };
  122. CollideWorker.prototype.collideForSubMesh = function (subMesh, transformMatrix, meshGeometry) {
  123. if (!meshGeometry['positionsArray']) {
  124. meshGeometry['positionsArray'] = [];
  125. for (var i = 0, len = meshGeometry.positions.length; i < len; i = i + 3) {
  126. var p = BABYLON.Vector3.FromArray([meshGeometry.positions[i], meshGeometry.positions[i + 1], meshGeometry.positions[i + 2]]);
  127. meshGeometry['positionsArray'].push(p);
  128. }
  129. }
  130. if (!subMesh['_lastColliderWorldVertices'] || !subMesh['_lastColliderTransformMatrix'].equals(transformMatrix)) {
  131. subMesh['_lastColliderTransformMatrix'] = transformMatrix.clone();
  132. subMesh['_lastColliderWorldVertices'] = [];
  133. subMesh['_trianglePlanes'] = [];
  134. var start = subMesh.verticesStart;
  135. var end = (subMesh.verticesStart + subMesh.verticesCount);
  136. for (var i = start; i < end; i++) {
  137. subMesh['_lastColliderWorldVertices'].push(BABYLON.Vector3.TransformCoordinates(meshGeometry['positionsArray'][i], transformMatrix));
  138. }
  139. }
  140. // Collide
  141. this.collider._collide(subMesh['_trianglePlanes'], subMesh['_lastColliderWorldVertices'], meshGeometry.indices, subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart, subMesh.hasMaterial);
  142. };
  143. CollideWorker.prototype.checkSubmeshCollision = function (subMesh) {
  144. return this.collider._canDoCollision(BABYLON.Vector3.FromArray(subMesh.sphereCenter), subMesh.sphereRadius, BABYLON.Vector3.FromArray(subMesh.boxMinimum), BABYLON.Vector3.FromArray(subMesh.boxMaximum));
  145. };
  146. return CollideWorker;
  147. }());
  148. BABYLON.CollideWorker = CollideWorker;
  149. var CollisionDetectorTransferable = (function () {
  150. function CollisionDetectorTransferable() {
  151. }
  152. CollisionDetectorTransferable.prototype.onInit = function (payload) {
  153. this._collisionCache = new CollisionCache();
  154. var reply = {
  155. error: BABYLON.WorkerReplyType.SUCCESS,
  156. taskType: BABYLON.WorkerTaskType.INIT
  157. };
  158. postMessage(reply, undefined);
  159. };
  160. CollisionDetectorTransferable.prototype.onUpdate = function (payload) {
  161. var _this = this;
  162. var replay = {
  163. error: BABYLON.WorkerReplyType.SUCCESS,
  164. taskType: BABYLON.WorkerTaskType.UPDATE
  165. };
  166. try {
  167. for (var id in payload.updatedGeometries) {
  168. if (payload.updatedGeometries.hasOwnProperty(id)) {
  169. this._collisionCache.addGeometry(payload.updatedGeometries[id]);
  170. }
  171. }
  172. for (var uniqueId in payload.updatedMeshes) {
  173. if (payload.updatedMeshes.hasOwnProperty(uniqueId)) {
  174. this._collisionCache.addMesh(payload.updatedMeshes[uniqueId]);
  175. }
  176. }
  177. payload.removedGeometries.forEach(function (id) {
  178. _this._collisionCache.removeGeometry(id);
  179. });
  180. payload.removedMeshes.forEach(function (uniqueId) {
  181. _this._collisionCache.removeMesh(uniqueId);
  182. });
  183. }
  184. catch (x) {
  185. replay.error = BABYLON.WorkerReplyType.UNKNOWN_ERROR;
  186. }
  187. postMessage(replay, undefined);
  188. };
  189. CollisionDetectorTransferable.prototype.onCollision = function (payload) {
  190. var finalPosition = BABYLON.Vector3.Zero();
  191. //create a new collider
  192. var collider = new BABYLON.Collider();
  193. collider.radius = BABYLON.Vector3.FromArray(payload.collider.radius);
  194. var colliderWorker = new CollideWorker(collider, this._collisionCache, finalPosition);
  195. colliderWorker.collideWithWorld(BABYLON.Vector3.FromArray(payload.collider.position), BABYLON.Vector3.FromArray(payload.collider.velocity), payload.maximumRetry, payload.excludedMeshUniqueId);
  196. var replyPayload = {
  197. collidedMeshUniqueId: collider.collidedMesh,
  198. collisionId: payload.collisionId,
  199. newPosition: finalPosition.asArray()
  200. };
  201. var reply = {
  202. error: BABYLON.WorkerReplyType.SUCCESS,
  203. taskType: BABYLON.WorkerTaskType.COLLIDE,
  204. payload: replyPayload
  205. };
  206. postMessage(reply, undefined);
  207. };
  208. return CollisionDetectorTransferable;
  209. }());
  210. BABYLON.CollisionDetectorTransferable = CollisionDetectorTransferable;
  211. //check if we are in a web worker, as this code should NOT run on the main UI thread
  212. try {
  213. if (self && self instanceof WorkerGlobalScope) {
  214. //Window hack to allow including babylonjs native code. the <any> is for typescript.
  215. window = {};
  216. //scripts were not included, standalone worker
  217. if (!BABYLON.Collider) {
  218. importScripts("./babylon.collisionCoordinator.js");
  219. importScripts("./babylon.collider.js");
  220. importScripts("../Math/babylon.math.js");
  221. }
  222. var collisionDetector = new CollisionDetectorTransferable();
  223. var onNewMessage = function (event) {
  224. var message = event.data;
  225. switch (message.taskType) {
  226. case BABYLON.WorkerTaskType.INIT:
  227. collisionDetector.onInit(message.payload);
  228. break;
  229. case BABYLON.WorkerTaskType.COLLIDE:
  230. collisionDetector.onCollision(message.payload);
  231. break;
  232. case BABYLON.WorkerTaskType.UPDATE:
  233. collisionDetector.onUpdate(message.payload);
  234. break;
  235. }
  236. };
  237. self.onmessage = onNewMessage;
  238. }
  239. }
  240. catch (e) {
  241. console.log("single worker init");
  242. }
  243. })(BABYLON || (BABYLON = {}));