unexpected turn of the camera (three.js + tween + lookat)

114 Views Asked by At

I have a question about three.js + tween + lookat Here's an example: https://intera3d.ru/tween_test/tokyo.html I want that when the button "TWEEN" is pressed the camera looked at the 3D model from above.

And so it happens, but at the end there is an unexpected turn of the camera / 3D model.

How can you avoid this?

Here is the "tween" function code:

function TWEEN_begin_CAMERA_1() {

    const tweenCamera1 = new TWEEN.Tween( 
        {x: camera.position.x, y: camera.position.y, z: camera.position.z, 
            lookAtX: 0, lookAtY: 0, lookAtZ: 0} 
        )
    .to( {x: 0, y: 20, z: 0, lookAtX: 0, lookAtY: 0, lookAtZ: 0}, 1000 )

    const updateCamera = function (object, elapsed) {
        camera.position.set(object.x, object.y, object.z);
        camera.lookAt(new THREE.Vector3(object.lookAtX, object.lookAtY, object.lookAtZ))
    }
    tweenCamera1.onUpdate(updateCamera)
    tweenCamera1.start()
}

Thanks a lot in advance for your help!

1

There are 1 best solutions below

2
prisoner849 On BEST ANSWER

Here is an example with THREE.Spherical, that doesn't allow camera to be set at x=0 and z=0 (at any y), see in the docs what the method .makeSafe() does:

body{
  overflow: hidden;
  margin: 0;
}
<button id="btn_Tween" style="position:absolute; margin: 10px;">TWEENME</button>
<script type="module">
import * as THREE from "https://cdn.skypack.dev/[email protected]";
import {OrbitControls} from "https://cdn.skypack.dev/[email protected]/examples/jsm/controls/OrbitControls.js";
import {TWEEN} from "https://cdn.skypack.dev/[email protected]/examples/jsm/libs/tween.module.min.js"

let scene = new THREE.Scene();
let camera = new THREE.PerspectiveCamera(60, innerWidth / innerHeight, 1, 1000);
camera.position.set(0, 5, 10);
let renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
window.addEventListener("resize", () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});

let controls = new OrbitControls(camera, renderer.domElement);

let light = new THREE.DirectionalLight(0xffffff, 1);
light.position.setScalar(1);
scene.add(light, new THREE.AmbientLight(0xffffff, 0.5));


scene.add(new THREE.GridHelper());
scene.add(new THREE.Mesh(
  new THREE.BoxGeometry(5, 5, 5), 
  new THREE.MeshLambertMaterial(
    {
      map: new THREE.TextureLoader().load("https://threejs.org/examples/textures/uv_grid_opengl.jpg")
    }
  )
));

btn_Tween.addEventListener("click", ()=> {
  let spherical = new THREE.Spherical();
  spherical.setFromVector3(camera.position);
  spherical.radius = 20;
  spherical.phi = 0;
  spherical.makeSafe();
  let v = new THREE.Vector3().setFromSpherical(spherical);
  let t = new TWEEN.Tween(camera.position).to(v, 2000).onUpdate(() => {
    camera.lookAt(scene.position);
    controls.update();
  });
  t.start();
});

renderer.setAnimationLoop(() => {
  TWEEN.update();
  renderer.render(scene, camera);
});
</script>