Camera.lookAt() but smoothly

Hello, is there a simple way to add a time pera meter to camera.lookAt() function?
for example…

Camera.lookAt(object.position, time);

I’ve been looking into tween and quaternion. Slerp but they are update/animation frame based so a solution for say scrolling events, where a camera is moving on scroll, becomes pretty complex!

any suggestions would be greatly appreciated

Hi!

What difficulty you had with it?

If the time per meter is known, then you just calculate the duration of tweening, by multiplying distance (between current location and destination) with that time value.

Thanks for the reply, ideally I want to use pure threejs without having to use tween library, if I don’t find a way I will have to, but trying to use minimal resources, trying a few things out but I will let you know if I end up using tween!

A bit of background info about tween.js
It is included in the libs when you run
npm install three@latest

And one of it earliest contributing developers was mrdoob.

So I consider it as good as being official.

You could use Vector3#lerp – three.js docs and then calculate alpha depending on time since last update * your meter unit * a percentage of how long it should take. I’ve never tried it it, so i don’t know the function. But you’d also use the lerp inside your animation loop, or other regularly called render update function otherwise you wouldn’t see it update on the canvas.

Hey dude, thanks for your reply! I have done a few really simple bits with tween before but didn’t seem necessary for what I needed, I’ve managed to do it by simply setting up a 3d object as cameraTarget, then with camera.lookAt(cameraTarget) in animation loop it’s just a case of moving the cameraTarget from one point to another with cameraTarget.position.lerp(new.position, 0.1) works a charm and is super simple just had to get my head around it!

Thanks everyone x

How did you do it in the end @forerunrun can you post some code?

You can do it very simply with Greensock. Here’s how I’ve done it in a recent project:

import * as THREE from "three";
import {gsap} from "gsap/all";

const RotationParameters = {
    StartRotation: new THREE.Quaternion(),
    EndQuaternion: new THREE.Quaternion(),
    SlerpResultQuaternion: new THREE.Quaternion(),
    SlerpFactor: 0
};

// I set this up to call NavInteraction() on a PointerUp event when the raycaster sees the mouse over an object with this class:

class WallNavMesh extends THREE.Mesh {

    constructor(geometry, material, app) {

        super(geometry, material);
        this.app = app; // a reference to the main class of the app that contains the scene, camera, etc.

    }

    NavInteraction(point) {

        RotationParameters.StartRotation.copy(this.app.ViewportCamera.quaternion);

        this.app.ViewportCamera.lookAt(point);
        RotationParameters.EndQuaternion.copy(this.app.ViewportCamera.quaternion);
        
// if you call lookAt() and then move the object back to the original rotation in the same frame, it won’t actually move.

        gsap.fromTo(RotationParameters, {SlerpFactor: 0},
            {
                SlerpFactor: 1,
                duration: 0.5,
                onUpdate: SlerpRotation.bind(this), // sets the camera rotation to this quaternion computed each frame
                ease: "power1.inOut"
            }    
        );
        
        function SlerpRotation() {
            RotationParameters.SlerpResultQuaternion.slerpQuaternions(
                RotationParameters.StartRotation,
                RotationParameters.EndQuaternion,
                RotationParameters.SlerpFactor
            );

            this.app.ViewportCamera.setRotationFromQuaternion(RotationParameters.SlerpResultQuaternion);

        }

    }

No reason why you couldn’t do this in the tick/loop function instead of GSAP, too. You’d have to control for frame rate with a time delta and all that, so I think this is a lot simpler.