babylon.collisionCoordinator.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. var BABYLON;
  2. (function (BABYLON) {
  3. //WebWorker code will be inserted to this variable.
  4. BABYLON.CollisionWorker = "";
  5. (function (WorkerTaskType) {
  6. WorkerTaskType[WorkerTaskType["INIT"] = 0] = "INIT";
  7. WorkerTaskType[WorkerTaskType["UPDATE"] = 1] = "UPDATE";
  8. WorkerTaskType[WorkerTaskType["COLLIDE"] = 2] = "COLLIDE";
  9. })(BABYLON.WorkerTaskType || (BABYLON.WorkerTaskType = {}));
  10. var WorkerTaskType = BABYLON.WorkerTaskType;
  11. (function (WorkerReplyType) {
  12. WorkerReplyType[WorkerReplyType["SUCCESS"] = 0] = "SUCCESS";
  13. WorkerReplyType[WorkerReplyType["UNKNOWN_ERROR"] = 1] = "UNKNOWN_ERROR";
  14. })(BABYLON.WorkerReplyType || (BABYLON.WorkerReplyType = {}));
  15. var WorkerReplyType = BABYLON.WorkerReplyType;
  16. var CollisionCoordinatorWorker = (function () {
  17. function CollisionCoordinatorWorker() {
  18. var _this = this;
  19. this._scaledPosition = BABYLON.Vector3.Zero();
  20. this._scaledVelocity = BABYLON.Vector3.Zero();
  21. this.onMeshUpdated = function (mesh) {
  22. _this._addUpdateMeshesList[mesh.uniqueId] = CollisionCoordinatorWorker.SerializeMesh(mesh);
  23. };
  24. this.onGeometryUpdated = function (geometry) {
  25. _this._addUpdateGeometriesList[geometry.id] = CollisionCoordinatorWorker.SerializeGeometry(geometry);
  26. };
  27. this._afterRender = function () {
  28. if (!_this._init)
  29. return;
  30. if (_this._toRemoveGeometryArray.length == 0 && _this._toRemoveMeshesArray.length == 0 && Object.keys(_this._addUpdateGeometriesList).length == 0 && Object.keys(_this._addUpdateMeshesList).length == 0) {
  31. return;
  32. }
  33. //5 concurrent updates were sent to the web worker and were not yet processed. Abort next update.
  34. //TODO make sure update runs as fast as possible to be able to update 60 FPS.
  35. if (_this._runningUpdated > 4) {
  36. return;
  37. }
  38. ++_this._runningUpdated;
  39. var payload = {
  40. updatedMeshes: _this._addUpdateMeshesList,
  41. updatedGeometries: _this._addUpdateGeometriesList,
  42. removedGeometries: _this._toRemoveGeometryArray,
  43. removedMeshes: _this._toRemoveMeshesArray
  44. };
  45. var message = {
  46. payload: payload,
  47. taskType: 1 /* UPDATE */
  48. };
  49. var serializable = [];
  50. for (var id in payload.updatedGeometries) {
  51. if (payload.updatedGeometries.hasOwnProperty(id)) {
  52. //prepare transferables
  53. serializable.push(message.payload.updatedGeometries[id].indices.buffer);
  54. serializable.push(message.payload.updatedGeometries[id].normals.buffer);
  55. serializable.push(message.payload.updatedGeometries[id].positions.buffer);
  56. }
  57. }
  58. _this._worker.postMessage(message, serializable);
  59. _this._addUpdateMeshesList = {};
  60. _this._addUpdateGeometriesList = {};
  61. _this._toRemoveGeometryArray = [];
  62. _this._toRemoveMeshesArray = [];
  63. };
  64. this._onMessageFromWorker = function (e) {
  65. var returnData = e.data;
  66. if (returnData.error != 0 /* SUCCESS */) {
  67. //TODO what errors can be returned from the worker?
  68. BABYLON.Tools.Warn("error returned from worker!");
  69. return;
  70. }
  71. switch (returnData.taskType) {
  72. case 0 /* INIT */:
  73. _this._init = true;
  74. //Update the worked with ALL of the scene's current state
  75. _this._scene.meshes.forEach(function (mesh) {
  76. _this.onMeshAdded(mesh);
  77. });
  78. _this._scene.getGeometries().forEach(function (geometry) {
  79. _this.onGeometryAdded(geometry);
  80. });
  81. break;
  82. case 1 /* UPDATE */:
  83. _this._runningUpdated--;
  84. break;
  85. case 2 /* COLLIDE */:
  86. _this._runningCollisionTask = false;
  87. var returnPayload = returnData.payload;
  88. if (!_this._collisionsCallbackArray[returnPayload.collisionId])
  89. return;
  90. _this._collisionsCallbackArray[returnPayload.collisionId](returnPayload.collisionId, BABYLON.Vector3.FromArray(returnPayload.newPosition), _this._scene.getMeshByUniqueID(returnPayload.collidedMeshUniqueId));
  91. //cleanup
  92. _this._collisionsCallbackArray[returnPayload.collisionId] = undefined;
  93. break;
  94. }
  95. };
  96. this._collisionsCallbackArray = [];
  97. this._init = false;
  98. this._runningUpdated = 0;
  99. this._runningCollisionTask = false;
  100. this._addUpdateMeshesList = {};
  101. this._addUpdateGeometriesList = {};
  102. this._toRemoveGeometryArray = [];
  103. this._toRemoveMeshesArray = [];
  104. }
  105. CollisionCoordinatorWorker.prototype.getNewPosition = function (position, velocity, collider, maximumRetry, excludedMesh, onNewPosition, collisionIndex) {
  106. if (!this._init)
  107. ;
  108. if (this._collisionsCallbackArray[collisionIndex])
  109. return;
  110. position.divideToRef(collider.radius, this._scaledPosition);
  111. velocity.divideToRef(collider.radius, this._scaledVelocity);
  112. this._collisionsCallbackArray[collisionIndex] = onNewPosition;
  113. var payload = {
  114. collider: {
  115. position: this._scaledPosition.asArray(),
  116. velocity: this._scaledVelocity.asArray(),
  117. radius: collider.radius.asArray()
  118. },
  119. collisionId: collisionIndex,
  120. excludedMeshUniqueId: excludedMesh ? excludedMesh.uniqueId : null,
  121. maximumRetry: maximumRetry
  122. };
  123. var message = {
  124. payload: payload,
  125. taskType: 2 /* COLLIDE */
  126. };
  127. this._worker.postMessage(message);
  128. };
  129. CollisionCoordinatorWorker.prototype.init = function (scene) {
  130. this._scene = scene;
  131. this._scene.registerAfterRender(this._afterRender);
  132. var workerUrl = BABYLON.WorkerIncluded ? BABYLON.Engine.CodeRepository + "Collisions/babylon.collisionWorker.js" : URL.createObjectURL(new Blob([BABYLON.CollisionWorker], { type: 'application/javascript' }));
  133. this._worker = new Worker(workerUrl);
  134. this._worker.onmessage = this._onMessageFromWorker;
  135. var message = {
  136. payload: {},
  137. taskType: 0 /* INIT */
  138. };
  139. this._worker.postMessage(message);
  140. };
  141. CollisionCoordinatorWorker.prototype.destroy = function () {
  142. this._scene.unregisterAfterRender(this._afterRender);
  143. this._worker.terminate();
  144. };
  145. CollisionCoordinatorWorker.prototype.onMeshAdded = function (mesh) {
  146. mesh.registerAfterWorldMatrixUpdate(this.onMeshUpdated);
  147. this.onMeshUpdated(mesh);
  148. };
  149. CollisionCoordinatorWorker.prototype.onMeshRemoved = function (mesh) {
  150. this._toRemoveMeshesArray.push(mesh.uniqueId);
  151. };
  152. CollisionCoordinatorWorker.prototype.onGeometryAdded = function (geometry) {
  153. //TODO this will break if the user uses his own function. This should be an array of callbacks!
  154. geometry.onGeometryUpdated = this.onGeometryUpdated;
  155. this.onGeometryUpdated(geometry);
  156. };
  157. CollisionCoordinatorWorker.prototype.onGeometryDeleted = function (geometry) {
  158. this._toRemoveGeometryArray.push(geometry.id);
  159. };
  160. CollisionCoordinatorWorker.SerializeMesh = function (mesh) {
  161. var submeshes = [];
  162. if (mesh.subMeshes) {
  163. submeshes = mesh.subMeshes.map(function (sm, idx) {
  164. return {
  165. position: idx,
  166. verticesStart: sm.verticesStart,
  167. verticesCount: sm.verticesCount,
  168. indexStart: sm.indexStart,
  169. indexCount: sm.indexCount,
  170. hasMaterial: !!sm.getMaterial(),
  171. sphereCenter: sm.getBoundingInfo().boundingSphere.centerWorld.asArray(),
  172. sphereRadius: sm.getBoundingInfo().boundingSphere.radiusWorld,
  173. boxMinimum: sm.getBoundingInfo().boundingBox.minimumWorld.asArray(),
  174. boxMaximum: sm.getBoundingInfo().boundingBox.maximumWorld.asArray()
  175. };
  176. });
  177. }
  178. var geometryId = mesh.geometry ? mesh.geometry.id : null;
  179. return {
  180. uniqueId: mesh.uniqueId,
  181. id: mesh.id,
  182. name: mesh.name,
  183. geometryId: geometryId,
  184. sphereCenter: mesh.getBoundingInfo().boundingSphere.centerWorld.asArray(),
  185. sphereRadius: mesh.getBoundingInfo().boundingSphere.radiusWorld,
  186. boxMinimum: mesh.getBoundingInfo().boundingBox.minimumWorld.asArray(),
  187. boxMaximum: mesh.getBoundingInfo().boundingBox.maximumWorld.asArray(),
  188. worldMatrixFromCache: mesh.worldMatrixFromCache.asArray(),
  189. subMeshes: submeshes,
  190. checkCollisions: mesh.checkCollisions
  191. };
  192. };
  193. CollisionCoordinatorWorker.SerializeGeometry = function (geometry) {
  194. return {
  195. id: geometry.id,
  196. positions: new Float32Array(geometry.getVerticesData(BABYLON.VertexBuffer.PositionKind) || []),
  197. normals: new Float32Array(geometry.getVerticesData(BABYLON.VertexBuffer.NormalKind) || []),
  198. indices: new Int32Array(geometry.getIndices() || []),
  199. };
  200. };
  201. return CollisionCoordinatorWorker;
  202. })();
  203. BABYLON.CollisionCoordinatorWorker = CollisionCoordinatorWorker;
  204. var CollisionCoordinatorLegacy = (function () {
  205. function CollisionCoordinatorLegacy() {
  206. this._scaledPosition = BABYLON.Vector3.Zero();
  207. this._scaledVelocity = BABYLON.Vector3.Zero();
  208. this._finalPosition = BABYLON.Vector3.Zero();
  209. }
  210. CollisionCoordinatorLegacy.prototype.getNewPosition = function (position, velocity, collider, maximumRetry, excludedMesh, onNewPosition, collisionIndex) {
  211. position.divideToRef(collider.radius, this._scaledPosition);
  212. velocity.divideToRef(collider.radius, this._scaledVelocity);
  213. collider.retry = 0;
  214. collider.initialVelocity = this._scaledVelocity;
  215. collider.initialPosition = this._scaledPosition;
  216. this._collideWithWorld(this._scaledPosition, this._scaledVelocity, collider, maximumRetry, this._finalPosition, excludedMesh);
  217. this._finalPosition.multiplyInPlace(collider.radius);
  218. //run the callback
  219. onNewPosition(null, this._finalPosition, collider.collidedMesh);
  220. };
  221. CollisionCoordinatorLegacy.prototype.init = function (scene) {
  222. this._scene = scene;
  223. };
  224. CollisionCoordinatorLegacy.prototype.destroy = function () {
  225. //Legacy need no destruction method.
  226. };
  227. //No update in legacy mode
  228. CollisionCoordinatorLegacy.prototype.onMeshAdded = function (mesh) {
  229. };
  230. CollisionCoordinatorLegacy.prototype.onMeshUpdated = function (mesh) {
  231. };
  232. CollisionCoordinatorLegacy.prototype.onMeshRemoved = function (mesh) {
  233. };
  234. CollisionCoordinatorLegacy.prototype.onGeometryAdded = function (geometry) {
  235. };
  236. CollisionCoordinatorLegacy.prototype.onGeometryUpdated = function (geometry) {
  237. };
  238. CollisionCoordinatorLegacy.prototype.onGeometryDeleted = function (geometry) {
  239. };
  240. CollisionCoordinatorLegacy.prototype._collideWithWorld = function (position, velocity, collider, maximumRetry, finalPosition, excludedMesh) {
  241. if (excludedMesh === void 0) { excludedMesh = null; }
  242. var closeDistance = BABYLON.Engine.CollisionsEpsilon * 10.0;
  243. if (collider.retry >= maximumRetry) {
  244. finalPosition.copyFrom(position);
  245. return;
  246. }
  247. collider._initialize(position, velocity, closeDistance);
  248. for (var index = 0; index < this._scene.meshes.length; index++) {
  249. var mesh = this._scene.meshes[index];
  250. if (mesh.isEnabled() && mesh.checkCollisions && mesh.subMeshes && mesh !== excludedMesh) {
  251. mesh._checkCollision(collider);
  252. }
  253. }
  254. if (!collider.collisionFound) {
  255. position.addToRef(velocity, finalPosition);
  256. return;
  257. }
  258. if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
  259. collider._getResponse(position, velocity);
  260. }
  261. if (velocity.length() <= closeDistance) {
  262. finalPosition.copyFrom(position);
  263. return;
  264. }
  265. collider.retry++;
  266. this._collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh);
  267. };
  268. return CollisionCoordinatorLegacy;
  269. })();
  270. BABYLON.CollisionCoordinatorLegacy = CollisionCoordinatorLegacy;
  271. })(BABYLON || (BABYLON = {}));
  272. //# sourceMappingURL=babylon.collisionCoordinator.js.map