Reputation: 127
camera.lookAt(myObject) will instantly rotate the three.js camera towards the given object.
I would like to animate this rotation using gsap. I have no problem using gsap to animate a change in camera position, but the camera rotation code below does nothing.
const targetOrientation = myObject.quaternion.normalize();
gsap.to({}, {
duration: 2,
onUpdate: function() {
controls.update();
camera.quaternion.slerp(targetOrientation, this.progress());
}
});
How can I animate a camera rotation in this way?
OK this is now fixed. The main problem was a controls.update() line in my render() function. Orbit controls do not work well with camera rotation so you need to make sure that they are completely disabled during the animation.
My revised code that includes rotation and position animations:
const camrot = {'x':camera.rotation.x,'y':camera.rotation.y,'z':camera.rotation.z}
camera.lookAt(mesh.position);
const targetOrientation = camera.quaternion.clone().normalize();
camera.rotation.x = camrot.x;
camera.rotation.y = camrot.y;
camera.rotation.z = camrot.z;
const aabb = new THREE.Box3().setFromObject( mesh );
const center = aabb.getCenter( new THREE.Vector3() );
const size = aabb.getSize( new THREE.Vector3() );
controls.enabled = false;
const startOrientation = camera.quaternion.clone();
gsap.to({}, {
duration: 2,
onUpdate: function() {
camera.quaternion.copy(startOrientation).slerp(targetOrientation, this.progress());
},
onComplete: function() {
gsap.to( camera.position, {
duration: 8,
x: center.x,
y: center.y,
z: center.z+4*size.z,
onUpdate: function() {
camera.lookAt( center );
},
onComplete: function() {
controls.enabled = true;
controls.target.set( center.x, center.y, center.z);
}
} );
}
});
Upvotes: 2
Views: 4138
Reputation: 31076
Try it like so:
let mesh, renderer, scene, camera, controls;
init();
animate();
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setPixelRatio( window.devicePixelRatio );
document.body.appendChild( renderer.domElement );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
camera.position.set( 20, 10, 20 );
camera.lookAt( 0, 0, 0 );
// ambient
scene.add( new THREE.AmbientLight( 0x222222 ) );
// light
const light = new THREE.DirectionalLight( 0xffffff, 1 );
light.position.set( 20,20, 0 );
scene.add( light );
// axes
scene.add( new THREE.AxesHelper( 20 ) );
// geometry
const geometry = new THREE.SphereBufferGeometry( 5, 12, 8 );
// material
const material = new THREE.MeshPhongMaterial( {
color: 0x00ffff,
flatShading: true,
transparent: true,
opacity: 0.7,
} );
// mesh
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
const startOrientation = camera.quaternion.clone();
const targetOrientation = mesh.quaternion.clone().normalize();
gsap.to( {}, {
duration: 2,
onUpdate: function() {
camera.quaternion.copy(startOrientation).slerp(targetOrientation, this.progress());
}
} );
}
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.4.0/gsap.min.js"></script>
You have to ensure to call Quaternion.slerp()
always with the start orientation and not with camera.quaternion
. Otherwise the interpolation will be incorrect.
Upvotes: 6