Kevin Jardine
Kevin Jardine

Reputation: 127

How to animate camera.lookAt using gsap?

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

Answers (1)

Mugen87
Mugen87

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

Related Questions