I hear yeah, I ended up using a modified version of rodrigues rotation formula.
// camera.tilt is a preset value determined for best intended effect, ignore for the question.
// camera.tilt_value is a preset value determined for best result, ignore for the question.
if( keyboard.pressed('d')){
// Move right
camera.camPosi = rotatePoint( angleToRadians( camera.rotationSpeed ), 1, camera.camPosi, camera.upAxis, true );
camera.position.set(camera.camPosi.x * camera.Zoom, camera.camPosi.y * camera.Zoom , camera.camPosi.z * camera.Zoom);
camera.up = camera.upAxis.clone();
if ( camera.Zoom <=camera._tilt ) {
camera.lookAtVector = newLookAt( camera.upAxis , camera.Zoom , camera._tilt , camera._tilt_value );
camera.lookAt( camera.lookAtVector.clone() );
} else {
camera.lookAtVector = newLookAt( camera._base , camera.Zoom , camera._tilt , camera._tilt_value );
camera.lookAt( camera.lookAtVector.clone() );
}
}
if( keyboard.pressed('s') ){
// Move down
camera.crossVector = rotatePoint( angleToRadians( 90 ), 1, camera.camPosi, camera.upAxis, true );
camera.upAxis = rotatePoint( angleToRadians( camera.rotationSpeed ), 1, camera.upAxis, camera.crossVector, true );
camera.camPosi = rotatePoint( angleToRadians( camera.rotationSpeed ), 1, camera.camPosi, camera.crossVector, true );
camera.position.set(camera.camPosi.x * camera.Zoom, camera.camPosi.y * camera.Zoom , camera.camPosi.z * camera.Zoom);
camera.up = camera.upAxis.clone();
if ( camera.Zoom <=camera._tilt ) {
camera.lookAtVector = newLookAt( camera.upAxis , camera.Zoom , camera._tilt , camera._tilt_value );
camera.lookAt( camera.lookAtVector.clone() );
} else {
camera.lookAtVector = newLookAt( camera._base , camera.Zoom , camera._tilt , camera._tilt_value );
camera.lookAt( camera.lookAtVector.clone() );
}
}
if( keyboard.pressed('e')){
// Rotate left
camera.upAxis = rotatePoint( angleToRadians( 5 * camera.rotationSpeed), 1, camera.upAxis, camera.camPosi, true);
camera.position.set(camera.camPosi.x * camera.Zoom, camera.camPosi.y * camera.Zoom , camera.camPosi.z * camera.Zoom);
camera.up = camera.upAxis.clone();
if ( camera.Zoom <=camera._tilt ) {
camera.lookAtVector = newLookAt( camera.upAxis , camera.Zoom , camera._tilt , camera._tilt_value );
camera.lookAt( camera.lookAtVector.clone() );
} else {
camera.lookAtVector = newLookAt( camera._base , camera.Zoom , camera._tilt , camera._tilt_value );
camera.lookAt( camera.lookAtVector.clone() );
}
}
function rotatePoint( angle , inverseSpeed , v1 , v2 , toNormalize ){
var c = Math.cos(angle);
var s = Math.sin(angle);
// inverseSpeed directly affects the speed of the camera. so a higher inverseSpeed = slower speed.
var v3 = new THREE.Vector3(
inverseSpeed * ( c * v1.x ) + ( s * ( ( v2.y * v1.z ) - ( v2.z * v1.y ) ) ) ,
inverseSpeed * ( c * v1.y ) + ( s * ( ( v2.z * v1.x ) - ( v2.x * v1.z ) ) ),
inverseSpeed * ( c * v1.z ) + ( s * ( ( v2.x * v1.y ) - ( v2.y * v1.x ) ) )
);
if ( toNormalize ){ v3.normalize(); }
return v3;
}; // used to rotate position of camera.
function newLookAt( axisVector , zoom , tilt , tiltIncrement ) {
var a = new THREE.Vector3( axisVector.x * ( ( tilt - zoom ) * tilt * 0.5 ) , axisVector.y * ( ( tilt - zoom ) * tilt * 0.5 ) , axisVector.z * ( ( tilt - zoom ) * tiltIncrement * 0.5 ) );
return a;
}; // used to update camera lookat position.
As the camera gets closer to the world the true lookAt vector is no longer the center of the planet, but rather a point that gradually gets further from the center the closer to the planet the camera gets. That way the camera tilts upwards when zooming in closer to give a better field of view for the user.
This is the code I’m currently using for my camera. If it’s what you need copy and modify the 3 directions for their sister directions.