提交 3fcc3930 编写于 作者: E Eberhard Gräther

restructured TrackballCamera, final static moving version

上级 b71b063f
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
* target: <THREE.Object3D>, * target: <THREE.Object3D>,
* radius: <float>, * radius: <float>,
* screen: { width : <float>, height : <float>, offsetLeft : <float>, offsetTop : <float> },
* zoomSpeed: <float>, * zoomSpeed: <float>,
* panSpeed: <float>, * panSpeed: <float>,
...@@ -16,307 +17,286 @@ ...@@ -16,307 +17,286 @@
* noZoom: <bool>, * noZoom: <bool>,
* noPan: <bool>, * noPan: <bool>,
* keys: <Array>, // [ rotateKey, zoomKey, panKey ] * keys: <Array>, // [ rotateKey, zoomKey, panKey ],
* domElement: <HTMLElement>, * domElement: <HTMLElement>,
* } * }
*/ */
// TODO: onWindowResize();
THREE.TrackballCamera = function ( parameters ) { THREE.TrackballCamera = function ( parameters ) {
THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target ); // target.position is modified when panning
this.radius = ( window.innerWidth + window.innerHeight ) / 4;
this.zoomSpeed = 1.0;
this.panSpeed = 1.0;
this.noZoom = false;
this.noPan = false;
this.keys = [ 65, 83, 68 ];
this.keyPressed = false;
this.domElement = document; parameters = parameters || {};
if ( parameters ) { THREE.Camera.call( this, parameters.fov, parameters.aspect, parameters.near, parameters.far, parameters.target );
if ( parameters.radius !== undefined ) this.radius = parameters.radius;
if ( parameters.zoomSpeed !== undefined ) this.zoomSpeed = parameters.zoomSpeed; this.domElement = parameters.domElement || document;
if ( parameters.panSpeed !== undefined ) this.panSpeed = parameters.panSpeed;
if ( parameters.noZoom !== undefined ) this.noZoom = parameters.noZoom; this.screen = parameters.screen || { width : window.innerWidth, height : window.innerHeight, offsetLeft : 0, offsetTop : 0 };
if ( parameters.noPan !== undefined ) this.noPan = parameters.noPan; this.radius = parameters.radius || ( this.screen.width + this.screen.height ) / 4;
if ( parameters.keys !== undefined ) this.keys = parameters.keys; this.zoomSpeed = parameters.zoomSpeed || 1.5;
this.panSpeed = parameters.panSpeed || 0.3;
if ( parameters.domElement !== undefined ) this.domElement = parameters.domElement; this.noZoom = parameters.noZoom || false;
this.noPan = parameters.noPan || false;
} this.keys = parameters.keys || [ 65 /*A*/, 83 /*S*/, 68 /*D*/ ];
this.useTarget = true; this.useTarget = true;
this.state = this.STATE.NONE;
this.screen = this.getScreenDimensions();
this.mouse = new THREE.Vector2(); //internals
this.start = new THREE.Vector3(); var _keyPressed = false,
this.end = new THREE.Vector3();
function bind( scope, fn ) { _state = this.STATE.NONE,
_mouse = new THREE.Vector2(),
_start = new THREE.Vector3(),
_end = new THREE.Vector3();
return function () {
fn.apply( scope, arguments ); // methods
}; this.handleEvent = function ( event ) {
}; if ( typeof this[ event.type ] == 'function' ) {
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousemove', bind( this, this.mousemove ), false );
this.domElement.addEventListener( 'mousedown', bind( this, this.mousedown ), false );
this.domElement.addEventListener( 'mouseup', bind( this, this.mouseup ), false );
window.addEventListener( 'keydown', bind( this, this.keydown ), false ); this[ event.type ]( event );
window.addEventListener( 'keyup', bind( this, this.keyup ), false );
};
THREE.TrackballCamera.prototype = new THREE.Camera(); }
THREE.TrackballCamera.prototype.constructor = THREE.TrackballCamera;
THREE.TrackballCamera.prototype.supr = THREE.Camera.prototype;
THREE.TrackballCamera.prototype.STATE = { };
NONE : -1,
ROTATE : 0,
ZOOM : 1,
PAN : 2
};
THREE.TrackballCamera.prototype.handleEvent = function ( event ) { this.getMouseOnScreen = function( clientX, clientY ) {
if ( typeof this[ event.type ] == 'function' ) { return new THREE.Vector2(
( clientX - this.screen.offsetLeft ) / this.radius * 0.5,
( clientY - this.screen.offsetTop ) / this.radius * 0.5
);
this[ event.type ]( event ); };
} this.getMouseProjectionOnBall = function( clientX, clientY ) {
}; var mouseOnBall = new THREE.Vector3(
( clientX - this.screen.width * 0.5 - this.screen.offsetLeft ) / this.radius,
( this.screen.height * 0.5 + this.screen.offsetTop - clientY ) / this.radius,
0.0
);
THREE.TrackballCamera.prototype.keydown = function( event ) { var length = mouseOnBall.length();
if ( this.state !== this.STATE.NONE ) {
return; if ( length > 1.0 ) {
} else if ( event.keyCode === this.keys[ this.STATE.ROTATE ] ) { mouseOnBall.normalize();
this.state = this.STATE.ROTATE; } else {
this.keyPressed = true;
} else if ( event.keyCode === this.keys[ this.STATE.ZOOM ] ) { mouseOnBall.z = Math.sqrt( 1.0 - length * length );
this.state = this.STATE.ZOOM; }
this.keyPressed = true;
} else if ( event.keyCode === this.keys[ this.STATE.PAN ] ) { var projection = this.up.clone().setLength( mouseOnBall.y );
projection.addSelf( this.up.clone().crossSelf( this.position ).setLength( mouseOnBall.x ) );
projection.addSelf( this.position.clone().setLength( mouseOnBall.z ) );
this.state = this.STATE.PAN; return projection;
this.keyPressed = true;
} };
}; this.rotateCamera = function( clientX, clientY ) {
THREE.TrackballCamera.prototype.keyup = function( event ) { _end = this.getMouseProjectionOnBall( clientX, clientY );
if ( this.state !== this.STATE.NONE ) { var angle = Math.acos( _start.dot( _end ) / _start.length() / _end.length() );
this.state = this.STATE.NONE; if ( angle ) {
} var axis = (new THREE.Vector3()).cross( _end, _start ).normalize(),
quaternion = new THREE.Quaternion();
}; quaternion.setFromAxisAngle( axis, angle );
THREE.TrackballCamera.prototype.mousedown = function(event) { quaternion.multiplyVector3( this.position );
quaternion.multiplyVector3( this.up );
event.preventDefault(); // quaternion.setFromAxisAngle( axis, angle * -0.1 );
event.stopPropagation(); // quaternion.multiplyVector3( _start );
if ( this.state === this.STATE.NONE ) { }
this.state = event.button; };
if ( this.state === this.STATE.ROTATE ) { this.zoomCamera = function( clientX, clientY ) {
this.start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); var newMouse = this.getMouseOnScreen( clientX, clientY ),
eye = this.position.clone().subSelf( this.target.position ),
factor = 1.0 + ( newMouse.y - _mouse.y ) * this.zoomSpeed;
} else { if ( factor > 0.0 ) {
this.mouse = this.getMouseOnScreen( event.clientX, event.clientY ); this.position.add( this.target.position, eye.multiplyScalar( factor ) );
_mouse = newMouse;
} }
} };
};
THREE.TrackballCamera.prototype.mousemove = function( event ) { this.panCamera = function( clientX, clientY ) {
if ( this.keyPressed ) {
this.start = this.getMouseProjectionOnBall( event.clientX, event.clientY ); var newMouse = this.getMouseOnScreen( clientX, clientY ),
this.mouse = this.getMouseOnScreen( event.clientX, event.clientY ); mouseChange = newMouse.clone().subSelf( _mouse ),
factor = this.position.distanceTo( this.target.position ) * this.panSpeed;
this.keyPressed = false; mouseChange.multiplyScalar( factor );
} var pan = this.position.clone().crossSelf( this.up ).setLength( mouseChange.x );
pan.addSelf( this.up.clone().setLength( mouseChange.y ) );
if ( this.state === this.STATE.NONE ) { this.position.addSelf( pan );
this.target.position.addSelf( pan );
return; _mouse = newMouse;
} else if ( this.state === this.STATE.ROTATE ) { };
// this.update = function( parentMatrixWorld, forceUpdate, camera ) {
//
// this.rotateCamera();
//
// this.supr.update.call( this, parentMatrixWorld, forceUpdate, camera );
//
// };
this.rotateCamera( event.clientX, event.clientY ); // listeners
} else if ( this.state === this.STATE.ZOOM && !this.noZoom ) { function keydown( event ) {
this.zoomCamera( event.clientX, event.clientY ); if ( _state !== this.STATE.NONE ) {
} else if ( this.state === this.STATE.PAN && !this.noPan ) { return;
this.panCamera( event.clientX, event.clientY ); } else if ( event.keyCode === this.keys[ this.STATE.ROTATE ] ) {
} _state = this.STATE.ROTATE;
_keyPressed = true;
}; } else if ( event.keyCode === this.keys[ this.STATE.ZOOM ] ) {
THREE.TrackballCamera.prototype.mouseup = function( event ) { _state = this.STATE.ZOOM;
_keyPressed = true;
event.preventDefault(); } else if ( event.keyCode === this.keys[ this.STATE.PAN ] ) {
event.stopPropagation();
this.state = this.STATE.NONE; _state = this.STATE.PAN;
_keyPressed = true;
}; }
THREE.TrackballCamera.prototype.getScreenDimensions = function() { };
if ( this.domElement != document ) { function keyup( event ) {
return { if ( _state !== this.STATE.NONE ) {
width : this.domElement.offsetWidth,
height : this.domElement.offsetHeight,
offsetLeft : this.domElement.offsetLeft,
offsetTop : this.domElement.offsetTop
};
} else { _state = this.STATE.NONE;
return { }
width : window.innerWidth,
height : window.innerHeight,
offsetLeft : 0,
offsetTop : 0
};
} };
}; function mousedown(event) {
THREE.TrackballCamera.prototype.getMouseOnScreen = function( clientX, clientY ) { event.preventDefault();
event.stopPropagation();
return new THREE.Vector2( if ( _state === this.STATE.NONE ) {
( clientX - this.screen.offsetLeft ) / this.radius * 0.5,
( clientY - this.screen.offsetTop ) / this.radius * 0.5
);
}; _state = event.button;
THREE.TrackballCamera.prototype.getMouseProjectionOnBall = function( clientX, clientY ) { if ( _state === this.STATE.ROTATE ) {
var mouseOnBall = new THREE.Vector3( _start = this.getMouseProjectionOnBall( event.clientX, event.clientY );
( clientX - this.screen.width * 0.5 - this.screen.offsetLeft ) / this.radius,
( this.screen.height * 0.5 + this.screen.offsetTop - clientY ) / this.radius,
0.0
);
var length = mouseOnBall.length(); } else {
if ( length > 1.0 ) { _mouse = this.getMouseOnScreen( event.clientX, event.clientY );
mouseOnBall.normalize(); }
} else { }
mouseOnBall.z = Math.sqrt( 1.0 - length * length ); };
} function mousemove( event ) {
var projection = this.up.clone().setLength( mouseOnBall.y ); if ( _keyPressed ) {
projection.addSelf( this.up.clone().crossSelf( this.position ).setLength( mouseOnBall.x ) );
projection.addSelf( this.position.clone().setLength( mouseOnBall.z ) );
return projection; _start = this.getMouseProjectionOnBall( event.clientX, event.clientY );
_mouse = this.getMouseOnScreen( event.clientX, event.clientY );
}; _keyPressed = false;
THREE.TrackballCamera.prototype.rotateCamera = function( clientX, clientY ) { }
this.end = this.getMouseProjectionOnBall( clientX, clientY ); if ( _state === this.STATE.NONE ) {
var angle = Math.acos( this.start.dot( this.end ) / this.start.length() / this.end.length() ); return;
if ( angle ) { } else if ( _state === this.STATE.ROTATE ) {
var axis = (new THREE.Vector3()).cross( this.end, this.start ).normalize(), // _end = this.getMouseProjectionOnBall( event.clientX, event.clientY );
quaternion = new THREE.Quaternion();
quaternion.setFromAxisAngle( axis, angle ); this.rotateCamera( event.clientX, event.clientY );
quaternion.multiplyVector3( this.position ); } else if ( _state === this.STATE.ZOOM && !this.noZoom ) {
quaternion.multiplyVector3( this.up );
} this.zoomCamera( event.clientX, event.clientY );
}; } else if ( _state === this.STATE.PAN && !this.noPan ) {
THREE.TrackballCamera.prototype.zoomCamera = function( clientX, clientY ) { this.panCamera( event.clientX, event.clientY );
var newMouse = this.getMouseOnScreen( clientX, clientY ), }
eye = this.position.clone().subSelf( this.target.position ),
factor = 1.0 + ( newMouse.y - this.mouse.y ) * this.zoomSpeed;
if ( factor > 0.0 ) { };
this.position.add( this.target.position, eye.multiplyScalar( factor ) ); function mouseup( event ) {
this.mouse = newMouse;
} event.preventDefault();
event.stopPropagation();
}; _state = this.STATE.NONE;
THREE.TrackballCamera.prototype.panCamera = function( clientX, clientY ) { };
var newMouse = this.getMouseOnScreen( clientX, clientY ), function bind( scope, fn ) {
mouseChange = newMouse.clone().subSelf(this.mouse),
factor = this.position.distanceTo( this.target.position ) * this.panSpeed; return function () {
fn.apply( scope, arguments );
mouseChange.multiplyScalar( factor ); };
var pan = this.position.clone().crossSelf( this.up ).setLength( mouseChange.x ); };
pan.addSelf( this.up.clone().setLength( mouseChange.y ) );
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.position.addSelf( pan ); this.domElement.addEventListener( 'mousemove', bind( this, mousemove ), false );
this.target.position.addSelf( pan ); this.domElement.addEventListener( 'mousedown', bind( this, mousedown ), false );
this.domElement.addEventListener( 'mouseup', bind( this, mouseup ), false );
this.mouse = newMouse; window.addEventListener( 'keydown', bind( this, keydown ), false );
window.addEventListener( 'keyup', bind( this, keyup ), false );
}; };
THREE.TrackballCamera.prototype = new THREE.Camera();
THREE.TrackballCamera.prototype.constructor = THREE.TrackballCamera;
THREE.TrackballCamera.prototype.supr = THREE.Camera.prototype;
THREE.TrackballCamera.prototype.STATE = { NONE : -1, ROTATE : 0, ZOOM : 1, PAN : 2 };
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册