# Move camera with quaternions and tween.js

**URL:** <https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392>\
**Category:** Questions\
**Tags:** animation\
**Created:** [September 30, 2021, 11:07am UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392 "2021-09-30T11:07:57Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Dexylon](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/dexylon/32/17329_2.png) [@Dexylon](https://discourse.threejs.org/u/Dexylon)\
**Post date:** [September 30, 2021, 11:07am UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/1 "2021-09-30T11:07:58Z")

</div>

I want to move the camera with a rotation from one point to another one (following the surface of a sphere). The camera is looking at the center of one object.

I use the following code that works, but I’m not sure if it is correct.

```javascript
rotateCameraTo (cameraX, cameraY, cameraZ, time) {
    const camera = this._camera.camera;
    const initialCamera = new Vector3().copy(camera.position);

    const cameraVectorStart = new Vector3(camera.position.x, camera.position.y, camera.position.z);
    const cameraVectorEnd = new Vector3(cameraX, cameraY, cameraZ);
    cameraVectorStart.normalize();
    cameraVectorEnd.normalize();

    let qa = new Quaternion(0, 0, 0, 1);
    let qb = new Quaternion().setFromUnitVectors(cameraVectorStart, cameraVectorEnd);
    let qm = new Quaternion();

    let ti = { t: 0 };

    new TWEEN.Tween(ti)
      .to({ t: 1 }, time)
      .easing(TWEEN.Easing.Quadratic.InOut)
      .onUpdate(function () {
        camera.position.set(initialCamera.x, initialCamera.y, initialCamera.z);
        qm.slerpQuaternions(qa, qb, ti.t);
        camera.position.applyQuaternion(qm);
        //At the moment the object is centered in the origin
        camera.lookAt(0, 0, 0);
      })
      .onComplete(function () {
        window.cancelAnimationFrame(animationID);
      })
      .start();
  }

```

Things that I don’t know if there are correct:

- I set the camera to initial position every .onUpdate().
- I use let qa = new Quaternion(0, 0, 0, 1) because it works but I’m not sure about this.
- If there is a better solution than use quaternions

Another doubt is if it is possible to get another path instead the shorter from one point to the other one. This is because I prefer to rotate with Y as a pivot, but If I use points with different values of Y it does not work.

Any suggestions will be greatly appreciated!

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [December 7, 2023, 9:20pm UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/3 "2023-12-07T21:20:17Z")

</div>

first off… if you’re getting the behavior you want, then your solution might be fine… until it’s not. 😃

An alternative to interpolating/slerping quaternion, is to set up a new point called cameraLookTarget…

Then you tween that point between the different places you want the camera to look at, and each frame, you camera.lookAt(cameraLookTarget);

So then you camera code is kinda reduced to tweening the 2 points… camera position and cameraLookTarget.

I find that setup to be simpler/easier to reason about… but both approaches have their uses.

---

<div class="post-metadata">

**Author:** ![BenedictLang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/benedictlang/32/26387_2.png) [@BenedictLang](https://discourse.threejs.org/u/BenedictLang)\
**Post date:** [December 9, 2023, 5:21am UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/4 "2023-12-09T05:21:51Z")

</div>

@Dexylon I think this should be a bit clearer:

```javascript
rotateCamera (cameraVectorEnd, time) {
        const camera = this._camera.camera;

        const cameraVectorStart = camera.position.clone()

        let qa = new Quaternion(0, 0, 0, 1).normalize();
        let qb = new Quaternion().setFromUnitVectors(cameraVectorStart, cameraVectorEnd).normalize();
        let qm = new Quaternion();

        let ti = { t: 0 };

        new TWEEN.Tween(ti)
          .to({ t: 1 }, time)
          .easing(TWEEN.Easing.Quadratic.InOut)
          .onUpdate(function () {
            camera.position.copy(cameraVectorStart);
            qm.slerpQuaternions(qa, qb, ti.t);
            camera.position.applyQuaternion(qm);
            //Center of the object
            camera.lookAt(0, 0, 0);
          })
          .onComplete(function () {
            window.cancelAnimationFrame(animationID);
          })
          .start();
      }

```

---

<div class="post-metadata">

**Author:** ![BenedictLang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/benedictlang/32/26387_2.png) [@BenedictLang](https://discourse.threejs.org/u/BenedictLang)\
**Post date:** [December 9, 2023, 2:41pm UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/5 "2023-12-09T14:41:30Z")

</div>

What if I use OrbitControls, where the camera is always looking at the target, but I want to use a button that also starts a movement above the target which would also trigger a gimble lock? Would I need to disable the controls, tween the quaternion, tween the position and then turn it back on?  
Sadly when setting `orbitControls.enable = false` I still can control it which seems to be a [bug](https://github.com/mrdoob/three.js/pull/23832).

At the moment I have exactly that issue [Animation-with-tween-js/18549](https://discourse.threejs.org/t/animation-with-tween-js/18549)

---

<div class="post-metadata">

**Author:** ![Dexylon](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/dexylon/32/17329_2.png) [@Dexylon](https://discourse.threejs.org/u/Dexylon)\
**Post date:** [December 9, 2023, 3:34pm UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/6 "2023-12-09T15:34:17Z")

</div>

In theory, using quaternions avoids gimbal lock. With the code in my post, I achieved rotation without experiencing gimbal lock. Another issue I encountered was that I didn’t want to take the shortest path. One solution was to chain two tweens (with one point more) to modify the path and avoidgo over the model like in this image.

 ![image](https://canada1.discourse-cdn.com/flex035/uploads/threejs/original/3X/8/8/886704d90564b957f74759cccf802ce9f6e5cdcc.jpeg)  
Hopefully it is helpful to you.

---

<div class="post-metadata">

**Author:** ![BenedictLang](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/benedictlang/32/26387_2.png) [@BenedictLang](https://discourse.threejs.org/u/BenedictLang)\
**Post date:** [December 10, 2023, 6:09am UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/7 "2023-12-10T06:09:15Z")

</div>

I came up with that [solution](https://discourse.threejs.org/t/animation-with-tween-js/18549/3) to work around the poles.

How did you calculate the intermediate non-direct point?

---

<div class="post-metadata">

**Author:** ![Dexylon](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/dexylon/32/17329_2.png) [@Dexylon](https://discourse.threejs.org/u/Dexylon)\
**Post date:** [December 11, 2023, 11:15am UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/8 "2023-12-11T11:15:01Z")

</div>

I don’t remember, it was 1-2 years ago, and I don’t work there anymore so I don’t have access to the code. I think it was related to finding the midpoint and moving it in the X or Z direction based on certain values. However, there should be a better way.

---

<div class="post-metadata">

**Author:** ![manthrax](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.threejs.org/manthrax/32/2596_2.png) [@manthrax](https://discourse.threejs.org/u/manthrax)\
**Post date:** [December 12, 2023, 5:19am UTC](https://discourse.threejs.org/t/move-camera-with-quaternions-and-tween-js/30392/9 "2023-12-12T05:19:22Z")

</div>

To avoid gimbal lock on the camera, sometimes you can do this:

at init time:  
`camera.up = camera.up.clone();`

in your render loop:

```javascript
camera.up.set(0,1,0).applyQuaternion(camera.quaternion);

```
