babylon.freeCamera.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. var BABYLON = BABYLON || {};
  2. (function () {
  3. BABYLON.FreeCamera = function (name, position, scene) {
  4. this.name = name;
  5. this.id = name;
  6. this._scene = scene;
  7. this.position = position;
  8. scene.cameras.push(this);
  9. this.cameraDirection = new BABYLON.Vector3(0, 0, 0);
  10. this.cameraRotation = new BABYLON.Vector2(0, 0);
  11. this.rotation = new BABYLON.Vector3(0, 0, 0);
  12. this.ellipsoid = new BABYLON.Vector3(0.5, 1, 0.5);
  13. this._keys = [];
  14. this.keysUp = [38];
  15. this.keysDown = [40];
  16. this.keysLeft = [37];
  17. this.keysRight = [39];
  18. if (!scene.activeCamera) {
  19. scene.activeCamera = this;
  20. }
  21. // Collisions
  22. this._collider = new BABYLON.Collider();
  23. this._needMoveForGravity = true;
  24. // Animations
  25. this.animations = [];
  26. // Internals
  27. this._currentTarget = BABYLON.Vector3.Zero();
  28. this._upVector = BABYLON.Vector3.Up();
  29. this._viewMatrix = BABYLON.Matrix.Zero();
  30. this._camMatrix = BABYLON.Matrix.Zero();
  31. this._cameraTransformMatrix = BABYLON.Matrix.Zero();
  32. this._cameraRotationMatrix = BABYLON.Matrix.Zero();
  33. this._referencePoint = BABYLON.Vector3.Zero();
  34. this._transformedReferencePoint = BABYLON.Vector3.Zero();
  35. this._oldPosition = BABYLON.Vector3.Zero();
  36. this._diffPosition = BABYLON.Vector3.Zero();
  37. this._newPosition = BABYLON.Vector3.Zero();
  38. };
  39. BABYLON.FreeCamera.prototype = Object.create(BABYLON.Camera.prototype);
  40. // Members
  41. BABYLON.FreeCamera.prototype.speed = 2.0;
  42. BABYLON.FreeCamera.prototype.checkCollisions = false;
  43. BABYLON.FreeCamera.prototype.applyGravity = false;
  44. // Methods
  45. BABYLON.FreeCamera.prototype._computeLocalCameraSpeed = function () {
  46. return this.speed * ((BABYLON.Tools.GetDeltaTime() / (BABYLON.Tools.GetFps() * 10.0)));
  47. };
  48. // Target
  49. BABYLON.FreeCamera.prototype.setTarget = function (target) {
  50. BABYLON.Matrix.LookAtLHToRef(this.position, target, BABYLON.Vector3.Up(), this._camMatrix);
  51. this._camMatrix.invert();
  52. this.rotation.x = Math.atan(this._camMatrix.m[6] / this._camMatrix.m[10]);
  53. var vDir = target.subtract(this.position);
  54. if (vDir.x >= 0.0) {
  55. this.rotation.y = (-Math.atan(vDir.z / vDir.x) + Math.PI / 2.0);
  56. } else {
  57. this.rotation.y = (-Math.atan(vDir.z / vDir.x) - Math.PI / 2.0);
  58. }
  59. this.rotation.z = -Math.acos(BABYLON.Vector3.Dot(new BABYLON.Vector3(0, 1.0, 0), BABYLON.Vector3.Up()));
  60. if (isNaN(this.rotation.x))
  61. this.rotation.x = 0;
  62. if (isNaN(this.rotation.y))
  63. this.rotation.y = 0;
  64. if (isNaN(this.rotation.z))
  65. this.rotation.z = 0;
  66. };
  67. // Controls
  68. BABYLON.FreeCamera.prototype.attachControl = function (canvas) {
  69. var previousPosition;
  70. var that = this;
  71. var engine = this._scene.getEngine();
  72. if (this._onMouseDown === undefined) {
  73. this._onMouseDown = function (evt) {
  74. previousPosition = {
  75. x: evt.clientX,
  76. y: evt.clientY
  77. };
  78. evt.preventDefault();
  79. };
  80. this._onMouseUp = function (evt) {
  81. previousPosition = null;
  82. evt.preventDefault();
  83. };
  84. this._onMouseOut = function (evt) {
  85. previousPosition = null;
  86. that._keys = [];
  87. evt.preventDefault();
  88. };
  89. this._onMouseMove = function (evt) {
  90. if (!previousPosition && !engine.isPointerLock) {
  91. return;
  92. }
  93. var offsetX;
  94. var offsetY;
  95. if (!engine.isPointerLock) {
  96. offsetX = evt.clientX - previousPosition.x;
  97. offsetY = evt.clientY - previousPosition.y;
  98. } else {
  99. offsetX = evt.movementX || evt.mozMovementX || evt.webkitMovementX || evt.msMovementX || 0;
  100. offsetY = evt.movementY || evt.mozMovementY || evt.webkitMovementY || evt.msMovementY || 0;
  101. }
  102. that.cameraRotation.y += offsetX / 2000.0;
  103. that.cameraRotation.x += offsetY / 2000.0;
  104. previousPosition = {
  105. x: evt.clientX,
  106. y: evt.clientY
  107. };
  108. evt.preventDefault();
  109. };
  110. this._onKeyDown = function (evt) {
  111. if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
  112. that.keysDown.indexOf(evt.keyCode) !== -1 ||
  113. that.keysLeft.indexOf(evt.keyCode) !== -1 ||
  114. that.keysRight.indexOf(evt.keyCode) !== -1) {
  115. var index = that._keys.indexOf(evt.keyCode);
  116. if (index === -1) {
  117. that._keys.push(evt.keyCode);
  118. }
  119. evt.preventDefault();
  120. }
  121. };
  122. this._onKeyUp = function (evt) {
  123. if (that.keysUp.indexOf(evt.keyCode) !== -1 ||
  124. that.keysDown.indexOf(evt.keyCode) !== -1 ||
  125. that.keysLeft.indexOf(evt.keyCode) !== -1 ||
  126. that.keysRight.indexOf(evt.keyCode) !== -1) {
  127. var index = that._keys.indexOf(evt.keyCode);
  128. if (index >= 0) {
  129. that._keys.splice(index, 1);
  130. }
  131. evt.preventDefault();
  132. }
  133. };
  134. this._onLostFocus = function () {
  135. that._keys = [];
  136. };
  137. }
  138. canvas.addEventListener("mousedown", this._onMouseDown, false);
  139. canvas.addEventListener("mouseup", this._onMouseUp, false);
  140. canvas.addEventListener("mouseout", this._onMouseOut, false);
  141. canvas.addEventListener("mousemove", this._onMouseMove, false);
  142. window.addEventListener("keydown", this._onKeyDown, false);
  143. window.addEventListener("keyup", this._onKeyUp, false);
  144. window.addEventListener("blur", this._onLostFocus, false);
  145. };
  146. BABYLON.FreeCamera.prototype.detachControl = function (canvas) {
  147. canvas.removeEventListener("mousedown", this._onMouseDown);
  148. canvas.removeEventListener("mouseup", this._onMouseUp);
  149. canvas.removeEventListener("mouseout", this._onMouseOut);
  150. canvas.removeEventListener("mousemove", this._onMouseMove);
  151. window.removeEventListener("keydown", this._onKeyDown);
  152. window.removeEventListener("keyup", this._onKeyUp);
  153. window.removeEventListener("blur", this._onLostFocus);
  154. };
  155. BABYLON.FreeCamera.prototype._collideWithWorld = function (velocity) {
  156. this.position.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPosition);
  157. this._collider.radius = this.ellipsoid;
  158. this._scene._getNewPosition(this._oldPosition, velocity, this._collider, 3, this._newPosition);
  159. this._newPosition.subtractToRef(this._oldPosition, this._diffPosition);
  160. if (this._diffPosition.length() > BABYLON.Engine.collisionsEpsilon) {
  161. this.position.addInPlace(this._diffPosition);
  162. }
  163. };
  164. BABYLON.FreeCamera.prototype._checkInputs = function () {
  165. if (!this._localDirection) {
  166. this._localDirection = BABYLON.Vector3.Zero();
  167. this._transformedDirection = BABYLON.Vector3.Zero();
  168. }
  169. // Keyboard
  170. for (var index = 0; index < this._keys.length; index++) {
  171. var keyCode = this._keys[index];
  172. var speed = this._computeLocalCameraSpeed();
  173. if (this.keysLeft.indexOf(keyCode) !== -1) {
  174. this._localDirection.copyFromFloats(-speed, 0, 0);
  175. } else if (this.keysUp.indexOf(keyCode) !== -1) {
  176. this._localDirection.copyFromFloats(0, 0, speed);
  177. } else if (this.keysRight.indexOf(keyCode) !== -1) {
  178. this._localDirection.copyFromFloats(speed, 0, 0);
  179. } else if (this.keysDown.indexOf(keyCode) !== -1) {
  180. this._localDirection.copyFromFloats(0, 0, -speed);
  181. }
  182. BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, 0, this._cameraTransformMatrix);
  183. BABYLON.Vector3.TransformCoordinatesToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
  184. this.cameraDirection.addInPlace(this._transformedDirection);
  185. }
  186. };
  187. BABYLON.FreeCamera.prototype._update = function () {
  188. this._checkInputs();
  189. var needToMove = this._needMoveForGravity || Math.abs(this.cameraDirection.x) > 0 || Math.abs(this.cameraDirection.y) > 0 || Math.abs(this.cameraDirection.z) > 0;
  190. var needToRotate = Math.abs(this.cameraRotation.x) > 0 || Math.abs(this.cameraRotation.y) > 0;
  191. // Move
  192. if (needToMove) {
  193. if (this.checkCollisions && this._scene.collisionsEnabled) {
  194. this._collideWithWorld(this.cameraDirection);
  195. if (this.applyGravity) {
  196. var oldPosition = this.position;
  197. this._collideWithWorld(this._scene.gravity);
  198. this._needMoveForGravity = (BABYLON.Vector3.DistanceSquared(oldPosition, this.position) != 0);
  199. }
  200. } else {
  201. this.position.addInPlace(this.cameraDirection);
  202. }
  203. }
  204. // Rotate
  205. if (needToRotate) {
  206. this.rotation.x += this.cameraRotation.x;
  207. this.rotation.y += this.cameraRotation.y;
  208. var limit = (Math.PI / 2) * 0.95;
  209. if (this.rotation.x > limit)
  210. this.rotation.x = limit;
  211. if (this.rotation.x < -limit)
  212. this.rotation.x = -limit;
  213. }
  214. // Inertia
  215. if (needToMove) {
  216. this.cameraDirection.scaleInPlace(this.inertia);
  217. }
  218. if (needToRotate) {
  219. this.cameraRotation.scaleInPlace(this.inertia);
  220. }
  221. };
  222. BABYLON.FreeCamera.prototype.getViewMatrix = function () {
  223. BABYLON.Vector3.FromFloatsToRef(0, 0, 1, this._referencePoint);
  224. // Compute
  225. BABYLON.Matrix.RotationYawPitchRollToRef(this.rotation.y, this.rotation.x, this.rotation.z, this._cameraRotationMatrix);
  226. BABYLON.Vector3.TransformCoordinatesToRef(this._referencePoint, this._cameraRotationMatrix, this._transformedReferencePoint);
  227. this.position.addToRef(this._transformedReferencePoint, this._currentTarget);
  228. BABYLON.Matrix.LookAtLHToRef(this.position, this._currentTarget, this._upVector, this._viewMatrix);
  229. return this._viewMatrix;
  230. };
  231. })();