FirstPersonCamera.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. * @author alteredq / http://alteredqualia.com/
  4. * @author paulirish / http://paulirish.com/
  5. *
  6. * parameters = {
  7. * fov: <float>,
  8. * aspect: <float>,
  9. * near: <float>,
  10. * far: <float>,
  11. * target: <THREE.Object3D>,
  12. * movementSpeed: <float>,
  13. * lookSpeed: <float>,
  14. * noFly: <bool>,
  15. * lookVertical: <bool>,
  16. * autoForward: <bool>,
  17. * constrainVertical: <bool>,
  18. * verticalMin: <float>,
  19. * verticalMax: <float>,
  20. * heightSpeed: <bool>,
  21. * heightCoef: <float>,
  22. * heightMin: <float>,
  23. * heightMax: <float>,
  24. * domElement: <HTMLElement>,
  25. * }
  26. */
  27. THREE.FirstPersonCamera = function ( parameters ) {
  28. THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target );
  29. this.movementSpeed = 1.0;
  30. this.lookSpeed = 0.005;
  31. this.noFly = false;
  32. this.lookVertical = true;
  33. this.autoForward = false;
  34. this.activeLook = true;
  35. this.heightSpeed = false;
  36. this.heightCoef = 1.0;
  37. this.heightMin = 0.0;
  38. this.constrainVertical = false;
  39. this.verticalMin = 0;
  40. this.verticalMax = 3.14;
  41. this.domElement = document;
  42. this.lastUpdate = new Date().getTime();
  43. this.tdiff = 0;
  44. if ( parameters ) {
  45. if ( parameters.movementSpeed !== undefined ) this.movementSpeed = parameters.movementSpeed;
  46. if ( parameters.lookSpeed !== undefined ) this.lookSpeed = parameters.lookSpeed;
  47. if ( parameters.noFly !== undefined ) this.noFly = parameters.noFly;
  48. if ( parameters.lookVertical !== undefined ) this.lookVertical = parameters.lookVertical;
  49. if ( parameters.autoForward !== undefined ) this.autoForward = parameters.autoForward;
  50. if ( parameters.activeLook !== undefined ) this.activeLook = parameters.activeLook;
  51. if ( parameters.heightSpeed !== undefined ) this.heightSpeed = parameters.heightSpeed;
  52. if ( parameters.heightCoef !== undefined ) this.heightCoef = parameters.heightCoef;
  53. if ( parameters.heightMin !== undefined ) this.heightMin = parameters.heightMin;
  54. if ( parameters.heightMax !== undefined ) this.heightMax = parameters.heightMax;
  55. if ( parameters.constrainVertical !== undefined ) this.constrainVertical = parameters.constrainVertical;
  56. if ( parameters.verticalMin !== undefined ) this.verticalMin = parameters.verticalMin;
  57. if ( parameters.verticalMax !== undefined ) this.verticalMax = parameters.verticalMax;
  58. if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement;
  59. }
  60. this.autoSpeedFactor = 0.0;
  61. this.mouseX = 0;
  62. this.mouseY = 0;
  63. this.lat = 0;
  64. this.lon = 0;
  65. this.phi = 0;
  66. this.theta = 0;
  67. this.moveForward = false;
  68. this.moveBackward = false;
  69. this.moveLeft = false;
  70. this.moveRight = false;
  71. this.freeze = false;
  72. this.mouseDragOn = false;
  73. this.windowHalfX = window.innerWidth / 2;
  74. this.windowHalfY = window.innerHeight / 2;
  75. this.onMouseDown = function ( event ) {
  76. event.preventDefault();
  77. event.stopPropagation();
  78. if ( this.activeLook ) {
  79. switch ( event.button ) {
  80. case 0: this.moveForward = true; break;
  81. case 2: this.moveBackward = true; break;
  82. }
  83. }
  84. this.mouseDragOn = true;
  85. };
  86. this.onMouseUp = function ( event ) {
  87. event.preventDefault();
  88. event.stopPropagation();
  89. if ( this.activeLook ) {
  90. switch ( event.button ) {
  91. case 0: this.moveForward = false; break;
  92. case 2: this.moveBackward = false; break;
  93. }
  94. }
  95. this.mouseDragOn = false;
  96. };
  97. this.onMouseMove = function ( event ) {
  98. this.mouseX = event.clientX - this.windowHalfX;
  99. this.mouseY = event.clientY - this.windowHalfY;
  100. };
  101. this.onKeyDown = function ( event ) {
  102. switch( event.keyCode ) {
  103. case 38: /*up*/
  104. case 87: /*W*/ this.moveForward = true; break;
  105. case 37: /*left*/
  106. case 65: /*A*/ this.moveLeft = true; break;
  107. case 40: /*down*/
  108. case 83: /*S*/ this.moveBackward = true; break;
  109. case 39: /*right*/
  110. case 68: /*D*/ this.moveRight = true; break;
  111. case 82: /*R*/ this.moveUp = true; break;
  112. case 70: /*F*/ this.moveDown = true; break;
  113. case 81: this.freeze = !this.freeze; break;
  114. }
  115. };
  116. this.onKeyUp = function ( event ) {
  117. switch( event.keyCode ) {
  118. case 38: /*up*/
  119. case 87: /*W*/ this.moveForward = false; break;
  120. case 37: /*left*/
  121. case 65: /*A*/ this.moveLeft = false; break;
  122. case 40: /*down*/
  123. case 83: /*S*/ this.moveBackward = false; break;
  124. case 39: /*right*/
  125. case 68: /*D*/ this.moveRight = false; break;
  126. case 82: /*R*/ this.moveUp = false; break;
  127. case 70: /*F*/ this.moveDown = false; break;
  128. }
  129. };
  130. this.update = function() {
  131. var now = new Date().getTime();
  132. this.tdiff = ( now - this.lastUpdate ) / 1000;
  133. this.lastUpdate = now;
  134. if ( !this.freeze ) {
  135. if ( this.heightSpeed ) {
  136. var y = clamp( this.position.y, this.heightMin, this.heightMax ),
  137. delta = y - this.heightMin;
  138. this.autoSpeedFactor = this.tdiff * ( delta * this.heightCoef );
  139. } else {
  140. this.autoSpeedFactor = 0.0;
  141. }
  142. var actualMoveSpeed = this.tdiff * this.movementSpeed;
  143. if ( this.moveForward || ( this.autoForward && !this.moveBackward ) ) this.translateZ( - ( actualMoveSpeed + this.autoSpeedFactor ) );
  144. if ( this.moveBackward ) this.translateZ( actualMoveSpeed );
  145. if ( this.moveLeft ) this.translateX( - actualMoveSpeed );
  146. if ( this.moveRight ) this.translateX( actualMoveSpeed );
  147. if ( this.moveUp ) this.translateY( actualMoveSpeed );
  148. if ( this.moveDown ) this.translateY( - actualMoveSpeed );
  149. var actualLookSpeed = this.tdiff * this.lookSpeed;
  150. if ( !this.activeLook ) {
  151. actualLookSpeed = 0;
  152. }
  153. this.lon += this.mouseX * actualLookSpeed;
  154. if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed;
  155. this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
  156. this.phi = ( 90 - this.lat ) * Math.PI / 180;
  157. this.theta = this.lon * Math.PI / 180;
  158. var targetPosition = this.target.position,
  159. position = this.position;
  160. targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
  161. targetPosition.y = position.y + 100 * Math.cos( this.phi );
  162. targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );
  163. }
  164. this.lon += this.mouseX * actualLookSpeed;
  165. if( this.lookVertical ) this.lat -= this.mouseY * actualLookSpeed;
  166. this.lat = Math.max( - 85, Math.min( 85, this.lat ) );
  167. this.phi = ( 90 - this.lat ) * Math.PI / 180;
  168. this.theta = this.lon * Math.PI / 180;
  169. if ( this.constrainVertical ) {
  170. this.phi = map_linear( this.phi, 0, 3.14, this.verticalMin, this.verticalMax );
  171. }
  172. var targetPosition = this.target.position,
  173. position = this.position;
  174. targetPosition.x = position.x + 100 * Math.sin( this.phi ) * Math.cos( this.theta );
  175. targetPosition.y = position.y + 100 * Math.cos( this.phi );
  176. targetPosition.z = position.z + 100 * Math.sin( this.phi ) * Math.sin( this.theta );
  177. this.supr.update.call( this );
  178. };
  179. this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
  180. this.domElement.addEventListener( 'mousemove', bind( this, this.onMouseMove ), false );
  181. this.domElement.addEventListener( 'mousedown', bind( this, this.onMouseDown ), false );
  182. this.domElement.addEventListener( 'mouseup', bind( this, this.onMouseUp ), false );
  183. this.domElement.addEventListener( 'keydown', bind( this, this.onKeyDown ), false );
  184. this.domElement.addEventListener( 'keyup', bind( this, this.onKeyUp ), false );
  185. function bind( scope, fn ) {
  186. return function () {
  187. fn.apply( scope, arguments );
  188. };
  189. };
  190. function map_linear( x, sa, sb, ea, eb ) {
  191. return ( x - sa ) * ( eb - ea ) / ( sb - sa ) + ea;
  192. };
  193. function clamp_bottom( x, a ) {
  194. return x < a ? a : x;
  195. };
  196. function clamp( x, a, b ) {
  197. return x < a ? a : ( x > b ? b : x );
  198. };
  199. };
  200. THREE.FirstPersonCamera.prototype = new THREE.Camera();
  201. THREE.FirstPersonCamera.prototype.constructor = THREE.FirstPersonCamera;
  202. THREE.FirstPersonCamera.prototype.supr = THREE.Camera.prototype;
  203. THREE.FirstPersonCamera.prototype.translate = function ( distance, axis ) {
  204. this.matrix.rotateAxis( axis );
  205. if ( this.noFly ) {
  206. axis.y = 0;
  207. }
  208. this.position.addSelf( axis.multiplyScalar( distance ) );
  209. this.target.position.addSelf( axis.multiplyScalar( distance ) );
  210. };
粤ICP备19079148号