In Three.js, I would like to have the camera looking at an object in the scene, and when I click on another object, to have the camera rotate smoothly to look at the new object. (i.e animate the rotation of the camera).
I´ve checked in SO and this is the most similar question :
Three.js How to use quaternion to rotate camera
I've also tried modifying the code in this website and I manage to get something like this http://jsfiddle.net/F7Bh3/
var quat0 = mesh2.quaternion;
var eye = mesh2.position;
var center = mesh.position;
var mat = new THREE.Matrix4();
mat.lookAt(center, eye, new THREE.Vector3(0,1,0));
var quat1 = new THREE.Quaternion();
quat1.setFromRotationMatrix( mat );
var qm = new THREE.Quaternion();
deltaTheta = angleBetweenQuats(quat0,quat1);
var frac = 0.2/deltaTheta;
if (frac>1) frac=1;
mesh2.quaternion.slerp(quat1,frac);
mesh2.quaternion.normalize();
But when I try to rotate the camera instead of the object all I get is: http://jsfiddle.net/5Peq9/1/
What am I missing? Thanks in advance
I managed to animate a camera smoothly in three.js using quaternions. It took me a while to figure it out, but once it is done it is beautiful to watch how nicely quaternions work.
The method is:
And a quick example with the key parts of the code:
var camera // camera
var cameraPos0 // initial camera position
var cameraUp0 // initial camera up
var cameraZoom // camera zoom
var iniQ // initial quaternion
var endQ // target quaternion
var curQ // temp quaternion during slerp
var vec3 // generic vector object
var tweenValue // tweenable value
// init camera
function setup()
{
camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 2000)
camera.position = new THREE.Vector3(0, 0, 80)
cameraPos0 = camera.position.clone()
cameraUp0 = camera.up.clone()
cameraZoom = camera.position.z
}
// set a new target for the camera
function moveCamera(euler, zoom)
{
// reset everything
endQ = new THREE.Quaternion()
iniQ = new THREE.Quaternion().copy(camera.quaternion)
curQ = new THREE.Quaternion()
vec3 = new THREE.Vector3()
tweenValue = 0
endQ.setFromEuler(euler)
TweenLite.to(this, 5, { tweenValue:1, cameraZoom:zoom, onUpdate:onSlerpUpdate })
}
// on every update of the tween
function onSlerpUpdate()
{
// interpolate quaternions with the current tween value
THREE.Quaternion.slerp(iniQ, endQ, curQ, tweenObj.value)
// apply new quaternion to camera position
vec3.x = cameraPos0.x
vec3.y = cameraPos0.y
vec3.z = cameraZoom
vec3.applyQuaternion(curQ)
camera.position.copy(vec3)
// apply new quaternion to camera up
vec3 = cameraUp0.clone()
vec3.applyQuaternion(curQ)
camera.up.copy(vec3)
}
The last step is to find the target Euler rotation to pass to moveCamera
. In my case I was using TrackballControls to find some interesting camera positions/rotations, then retrieving them with euler = camera.rotation.clone()
and passing that as a target. For example:
moveCamera(new THREE.Euler(2.20, -0.15, 0.55), 120)
An application of this method can be seen here: http://brunoimbrizi.com/experiments/#/08