babylon.collider.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. var BABYLON = BABYLON || {};
  2. (function () {
  3. BABYLON.Collider = function () {
  4. this.radius = new BABYLON.Vector3(1, 1, 1);
  5. this.retry = 0;
  6. };
  7. // Methods
  8. BABYLON.Collider.prototype._initialize = function (source, dir, e) {
  9. this.velocity = dir;
  10. this.normalizedVelocity = BABYLON.Vector3.Normalize(dir);
  11. this.basePoint = source;
  12. this.basePointWorld = source.multiply(this.radius);
  13. this.velocityWorld = dir.multiply(this.radius);
  14. this.velocityWorldLength = this.velocityWorld.length();
  15. this.epsilon = e;
  16. this.collisionFound = false;
  17. };
  18. var checkPointInTriangle = function (point, pa, pb, pc, n) {
  19. var e0 = pa.subtract(point);
  20. var e1 = pb.subtract(point);
  21. var d = BABYLON.Vector3.Dot(BABYLON.Vector3.Cross(e0, e1), n);
  22. if (d < 0)
  23. return false;
  24. var e2 = pc.subtract(point);
  25. d = BABYLON.Vector3.Dot(BABYLON.Vector3.Cross(e1, e2), n);
  26. if (d < 0)
  27. return false;
  28. d = BABYLON.Vector3.Dot(BABYLON.Vector3.Cross(e2, e0), n);
  29. return d >= 0;
  30. };
  31. var intersectBoxAASphere = function (boxMin, boxMax, sphereCenter, sphereRadius) {
  32. var boxMinSphere = new BABYLON.Vector3(sphereCenter.X - sphereRadius, sphereCenter.Y - sphereRadius, sphereCenter.Z - sphereRadius);
  33. var boxMaxSphere = new BABYLON.Vector3(sphereCenter.X + sphereRadius, sphereCenter.Y + sphereRadius, sphereCenter.Z + sphereRadius);
  34. if (boxMin.X > boxMaxSphere.X)
  35. return false;
  36. if (boxMinSphere.X > boxMax.X)
  37. return false;
  38. if (boxMin.Y > boxMaxSphere.Y)
  39. return false;
  40. if (boxMinSphere.Y > boxMax.Y)
  41. return false;
  42. if (boxMin.Z > boxMaxSphere.Z)
  43. return false;
  44. if (boxMinSphere.Z > boxMax.Z)
  45. return false;
  46. return true;
  47. };
  48. var getLowestRoot = function (a, b, c, maxR) {
  49. var determinant = b * b - 4.0 * a * c;
  50. var result = { root: 0, found: false };
  51. if (determinant < 0)
  52. return result;
  53. var sqrtD = Math.sqrt(determinant);
  54. var r1 = (-b - sqrtD) / (2.0 * a);
  55. var r2 = (-b + sqrtD) / (2.0 * a);
  56. if (r1 > r2) {
  57. var temp = r2;
  58. r2 = r1;
  59. r1 = temp;
  60. }
  61. if (r1 > 0 && r1 < maxR) {
  62. result.root = r1;
  63. result.found = true;
  64. return result;
  65. }
  66. if (r2 > 0 && r2 < maxR) {
  67. result.root = r2;
  68. result.found = true;
  69. return result;
  70. }
  71. return result;
  72. };
  73. BABYLON.Collider.prototype._canDoCollision = function (sphereCenter, sphereRadius, vecMin, vecMax) {
  74. var vecTest = this.basePointWorld.subtract(sphereCenter);
  75. var distance = vecTest.length();
  76. var max = Math.max(this.radius.x, this.radius.y);
  77. max = Math.max(max, this.radius.z);
  78. if (distance > this.velocityWorldLength + max + sphereRadius) {
  79. return false;
  80. }
  81. if (!intersectBoxAASphere(vecMin, vecMax, this.basePointWorld, this.velocityWorldLength + max))
  82. return false;
  83. return true;
  84. };
  85. BABYLON.Collider.prototype._testTriangle = function (subMesh, p1, p2, p3) {
  86. var t0;
  87. var embeddedInPlane = false;
  88. var trianglePlane = BABYLON.CollisionPlane.CreateFromPoints(p1, p2, p3);
  89. if ((!subMesh.getMaterial()) && !trianglePlane.isFrontFacingTo(this.normalizedVelocity, 0))
  90. return;
  91. var signedDistToTrianglePlane = trianglePlane.signedDistanceTo(this.basePoint);
  92. var normalDotVelocity = BABYLON.Vector3.Dot(trianglePlane.normal, this.velocity);
  93. if (normalDotVelocity == 0) {
  94. if (Math.abs(signedDistToTrianglePlane) >= 1.0)
  95. return;
  96. embeddedInPlane = true;
  97. t0 = 0;
  98. }
  99. else {
  100. t0 = (-1.0 - signedDistToTrianglePlane) / normalDotVelocity;
  101. var t1 = (1.0 - signedDistToTrianglePlane) / normalDotVelocity;
  102. if (t0 > t1) {
  103. var temp = t1;
  104. t1 = t0;
  105. t0 = temp;
  106. }
  107. if (t0 > 1.0 || t1 < 0.0)
  108. return;
  109. if (t0 < 0)
  110. t0 = 0;
  111. if (t0 > 1.0)
  112. t0 = 1.0;
  113. }
  114. var collisionPoint = BABYLON.Vector3.Zero();
  115. var found = false;
  116. var t = 1.0;
  117. if (!embeddedInPlane) {
  118. var planeIntersectionPoint = (this.basePoint.subtract(trianglePlane.normal)).add(this.velocity.scale(t0));
  119. if (checkPointInTriangle(planeIntersectionPoint, p1, p2, p3, trianglePlane.normal)) {
  120. found = true;
  121. t = t0;
  122. collisionPoint = planeIntersectionPoint;
  123. }
  124. }
  125. if (!found) {
  126. var velocitySquaredLength = this.velocity.lengthSquared();
  127. var a = velocitySquaredLength;
  128. var b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this.basePoint.subtract(p1)));
  129. var c = p1.subtract(this.basePoint).lengthSquared() - 1.0;
  130. var lowestRoot = getLowestRoot(a, b, c, t);
  131. if (lowestRoot.found) {
  132. t = lowestRoot.root;
  133. found = true;
  134. collisionPoint = p1;
  135. }
  136. b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this.basePoint.subtract(p2)));
  137. c = p2.subtract(this.basePoint).lengthSquared() - 1.0;
  138. lowestRoot = getLowestRoot(a, b, c, t);
  139. if (lowestRoot.found) {
  140. t = lowestRoot.root;
  141. found = true;
  142. collisionPoint = p2;
  143. }
  144. b = 2.0 * (BABYLON.Vector3.Dot(this.velocity, this.basePoint.subtract(p3)));
  145. c = p3.subtract(this.basePoint).lengthSquared() - 1.0;
  146. lowestRoot = getLowestRoot(a, b, c, t);
  147. if (lowestRoot.found) {
  148. t = lowestRoot.root;
  149. found = true;
  150. collisionPoint = p3;
  151. }
  152. var edge = p2.subtract(p1);
  153. var baseToVertex = p1.subtract(this.basePoint);
  154. var edgeSquaredLength = edge.lengthSquared();
  155. var edgeDotVelocity = BABYLON.Vector3.Dot(edge, this.velocity);
  156. var edgeDotBaseToVertex = BABYLON.Vector3.Dot(edge, baseToVertex);
  157. a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
  158. b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
  159. c = edgeSquaredLength * (1.0 - baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
  160. lowestRoot = getLowestRoot(a, b, c, t);
  161. if (lowestRoot.found) {
  162. var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
  163. if (f >= 0.0 && f <= 1.0) {
  164. t = lowestRoot.root;
  165. found = true;
  166. collisionPoint = p1.add(edge.scale(f));
  167. }
  168. }
  169. edge = p3.subtract(p2);
  170. baseToVertex = p2.subtract(this.basePoint);
  171. edgeSquaredLength = edge.lengthSquared();
  172. edgeDotVelocity = BABYLON.Vector3.Dot(edge, this.velocity);
  173. edgeDotBaseToVertex = BABYLON.Vector3.Dot(edge, baseToVertex);
  174. a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
  175. b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
  176. c = edgeSquaredLength * (1.0 - baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
  177. lowestRoot = getLowestRoot(a, b, c, t);
  178. if (lowestRoot.found) {
  179. var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
  180. if (f >= 0.0 && f <= 1.0) {
  181. t = lowestRoot.root;
  182. found = true;
  183. collisionPoint = p2.add(edge.scale(f));
  184. }
  185. }
  186. edge = p1.subtract(p3);
  187. baseToVertex = p3.subtract(this.basePoint);
  188. edgeSquaredLength = edge.lengthSquared();
  189. edgeDotVelocity = BABYLON.Vector3.Dot(edge, this.velocity);
  190. edgeDotBaseToVertex = BABYLON.Vector3.Dot(edge, baseToVertex);
  191. a = edgeSquaredLength * (-velocitySquaredLength) + edgeDotVelocity * edgeDotVelocity;
  192. b = edgeSquaredLength * (2.0 * BABYLON.Vector3.Dot(this.velocity, baseToVertex)) - 2.0 * edgeDotVelocity * edgeDotBaseToVertex;
  193. c = edgeSquaredLength * (1.0 - baseToVertex.lengthSquared()) + edgeDotBaseToVertex * edgeDotBaseToVertex;
  194. lowestRoot = getLowestRoot(a, b, c, t);
  195. if (lowestRoot.found) {
  196. var f = (edgeDotVelocity * lowestRoot.root - edgeDotBaseToVertex) / edgeSquaredLength;
  197. if (f >= 0.0 && f <= 1.0) {
  198. t = lowestRoot.root;
  199. found = true;
  200. collisionPoint = p3.add(edge.scale(f));
  201. }
  202. }
  203. }
  204. if (found) {
  205. var distToCollision = t * this.velocity.length();
  206. if (!this.collisionFound || distToCollision < this.nearestDistance) {
  207. this.nearestDistance = distToCollision;
  208. this.intersectionPoint = collisionPoint;
  209. this.collisionFound = true;
  210. }
  211. }
  212. };
  213. BABYLON.Collider.prototype._collide = function (subMesh, pts, indices, indexStart, indexEnd, decal) {
  214. for (var i = indexStart; i < indexEnd; i += 3) {
  215. var p1 = pts[indices[i] - decal];
  216. var p2 = pts[indices[i + 1] - decal];
  217. var p3 = pts[indices[i + 2] - decal];
  218. this._testTriangle(subMesh, p3, p2, p1);
  219. }
  220. };
  221. BABYLON.Collider.prototype._getResponse = function(pos, vel) {
  222. var destinationPoint = pos.add(vel);
  223. var V = vel.scale((this.nearestDistance / vel.length()));
  224. var newPos = this.basePoint.add(V);
  225. var slidePlaneNormal = newPos.subtract(this.intersectionPoint);
  226. slidePlaneNormal.normalize();
  227. var displacementVector = slidePlaneNormal.scale(this.epsilon);
  228. newPos = newPos.add(displacementVector);
  229. this.intersectionPoint = this.intersectionPoint.add(displacementVector);
  230. var slidePlaneOrigin = this.intersectionPoint;
  231. var slidingPlane = new BABYLON.CollisionPlane(slidePlaneOrigin, slidePlaneNormal);
  232. var newDestinationPoint = destinationPoint.subtract(slidePlaneNormal.scale(slidingPlane.signedDistanceTo(destinationPoint)));
  233. var newVel = newDestinationPoint.subtract(this.intersectionPoint);
  234. return { position: newPos, velocity: newVel };
  235. };
  236. })();