TrackballCamera.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. /**
  2. * @author Eberhard Gräther / http://egraether.com/
  3. * parameters = {
  4. * fov: <float>,
  5. * aspect: <float>,
  6. * near: <float>,
  7. * far: <float>,
  8. * target: <THREE.Object3D>,
  9. * radius: <float>,
  10. * zoomSpeed: <float>,
  11. * panSpeed: <float>,
  12. * noZoom: <bool>,
  13. * noPan: <bool>,
  14. * domElement: <HTMLElement>,
  15. * }
  16. */
  17. // TODO: onWindowResize();
  18. THREE.TrackballCamera = function ( parameters ) {
  19. THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target );
  20. this.radius = ( window.innerWidth + window.innerHeight ) / 4;
  21. this.zoomSpeed = 1.0;
  22. this.panSpeed = 1.0;
  23. this.noZoom = false;
  24. this.noPan = false;
  25. this.domElement = document;
  26. if ( parameters ) {
  27. if ( parameters.radius !== undefined ) this.radius = parameters.radius;
  28. if ( parameters.zoomSpeed !== undefined ) this.zoomSpeed = parameters.zoomSpeed;
  29. if ( parameters.panSpeed !== undefined ) this.panSpeed = parameters.panSpeed;
  30. if ( parameters.noZoom !== undefined ) this.noZoom = parameters.noZoom;
  31. if ( parameters.noPan !== undefined ) this.noPan = parameters.noPan;
  32. if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement;
  33. }
  34. this.useTarget = true;
  35. this.state = this.STATE.NONE;
  36. this.screen = this.getScreenDimensions();
  37. this.mouse = new THREE.Vector2();
  38. this.start = new THREE.Vector3();
  39. this.end = new THREE.Vector3();
  40. function bind( scope, fn ) {
  41. return function () {
  42. fn.apply( scope, arguments );
  43. };
  44. };
  45. this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
  46. this.domElement.addEventListener( 'mousemove', bind( this, this.mousemove ), false );
  47. this.domElement.addEventListener( 'mousedown', bind( this, this.mousedown ), false );
  48. this.domElement.addEventListener( 'mouseup', bind( this, this.mouseup ), false );
  49. window.addEventListener( 'keydown', bind( this, this.keydown ), false );
  50. window.addEventListener( 'keyup', bind( this, this.keyup ), false );
  51. };
  52. THREE.TrackballCamera.prototype = new THREE.Camera();
  53. THREE.TrackballCamera.prototype.constructor = THREE.TrackballCamera;
  54. THREE.TrackballCamera.prototype.supr = THREE.Camera.prototype;
  55. THREE.TrackballCamera.prototype.STATE = {
  56. NONE : -1,
  57. ROTATE : 0,
  58. ZOOM : 1,
  59. PAN : 2
  60. };
  61. THREE.TrackballCamera.prototype.handleEvent = function ( event ) {
  62. if ( typeof this[ event.type ] == 'function' ) {
  63. this[ event.type ]( event );
  64. }
  65. };
  66. THREE.TrackballCamera.prototype.keydown = function( event ) {
  67. };
  68. THREE.TrackballCamera.prototype.keyup = function( event ) {
  69. };
  70. THREE.TrackballCamera.prototype.mousedown = function(event) {
  71. event.preventDefault();
  72. event.stopPropagation();
  73. if ( this.state === this.STATE.NONE ) {
  74. this.state = event.button;
  75. if ( this.state === this.STATE.ROTATE ) {
  76. this.start = this.getMouseProjectionOnBall( event.clientX, event.clientY );
  77. } else {
  78. this.mouse = this.getMouseOnScreen( event.clientX, event.clientY );
  79. }
  80. }
  81. };
  82. THREE.TrackballCamera.prototype.mousemove = function( event ) {
  83. if ( this.state === this.STATE.NONE ) {
  84. return;
  85. } else if ( this.state === this.STATE.ROTATE ) {
  86. this.rotateCamera( event.clientX, event.clientY );
  87. } else if ( this.state === this.STATE.ZOOM && !this.noZoom ) {
  88. this.zoomCamera( event.clientX, event.clientY );
  89. } else if ( this.state === this.STATE.PAN && !this.noPan ) {
  90. this.panCamera( event.clientX, event.clientY );
  91. }
  92. };
  93. THREE.TrackballCamera.prototype.mouseup = function( event ) {
  94. event.preventDefault();
  95. event.stopPropagation();
  96. this.state = this.STATE.NONE;
  97. };
  98. THREE.TrackballCamera.prototype.getScreenDimensions = function() {
  99. if ( this.domElement != document ) {
  100. return {
  101. width : this.domElement.offsetWidth,
  102. height : this.domElement.offsetHeight,
  103. offsetLeft : this.domElement.offsetLeft,
  104. offsetTop : this.domElement.offsetTop
  105. };
  106. } else {
  107. return {
  108. width : window.innerWidth,
  109. height : window.innerHeight,
  110. offsetLeft : 0,
  111. offsetTop : 0
  112. };
  113. }
  114. };
  115. THREE.TrackballCamera.prototype.getMouseOnScreen = function( clientX, clientY ) {
  116. return new THREE.Vector2(
  117. ( clientX - this.screen.offsetLeft ) / this.radius * 0.5,
  118. ( clientY - this.screen.offsetTop ) / this.radius * 0.5
  119. );
  120. };
  121. THREE.TrackballCamera.prototype.getMouseProjectionOnBall = function( clientX, clientY ) {
  122. var mouseOnBall = new THREE.Vector3(
  123. ( clientX - this.screen.width * 0.5 - this.screen.offsetLeft ) / this.radius,
  124. ( this.screen.height * 0.5 + this.screen.offsetTop - clientY ) / this.radius,
  125. 0.0
  126. );
  127. var length = mouseOnBall.length();
  128. if ( length > 1.0 ) {
  129. mouseOnBall.normalize();
  130. } else {
  131. mouseOnBall.z = Math.sqrt( 1.0 - length * length );
  132. }
  133. var projection = this.up.clone().setLength( mouseOnBall.y );
  134. projection.addSelf( this.up.clone().crossSelf( this.position ).setLength( mouseOnBall.x ) );
  135. projection.addSelf( this.position.clone().setLength( mouseOnBall.z ) );
  136. return projection;
  137. };
  138. THREE.TrackballCamera.prototype.rotateCamera = function( clientX, clientY ) {
  139. this.end = this.getMouseProjectionOnBall( clientX, clientY );
  140. var angle = Math.acos( this.start.dot( this.end ) / this.start.length() / this.end.length() );
  141. if ( angle ) {
  142. var axis = (new THREE.Vector3()).cross( this.end, this.start ).normalize(),
  143. quaternion = new THREE.Quaternion();
  144. quaternion.setFromAxisAngle( axis, angle );
  145. quaternion.multiplyVector3( this.position );
  146. quaternion.multiplyVector3( this.up );
  147. }
  148. };
  149. THREE.TrackballCamera.prototype.zoomCamera = function( clientX, clientY ) {
  150. var newMouse = this.getMouseOnScreen( clientX, clientY ),
  151. eye = this.position.clone().subSelf( this.target.position ),
  152. factor = 1.0 + ( newMouse.y - this.mouse.y ) * this.zoomSpeed;
  153. if ( factor > 0.0 ) {
  154. this.position.add( this.target.position, eye.multiplyScalar( factor ) );
  155. this.mouse = newMouse;
  156. }
  157. };
  158. THREE.TrackballCamera.prototype.panCamera = function( clientX, clientY ) {
  159. var newMouse = this.getMouseOnScreen( clientX, clientY ),
  160. mouseChange = newMouse.clone().subSelf(this.mouse),
  161. factor = this.position.distanceTo( this.target.position ) * this.panSpeed;
  162. mouseChange.multiplyScalar( factor );
  163. var pan = this.position.clone().crossSelf( this.up ).setLength( mouseChange.x );
  164. pan.addSelf( this.up.clone().setLength( mouseChange.y ) );
  165. this.position.addSelf(pan);
  166. this.target.position.addSelf(pan);
  167. this.mouse = newMouse;
  168. };
粤ICP备19079148号