babylon.collisionCoordinator.js 12 KB

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