Smooth camera control switch on Three.js

- 1 answer

Ad

I'm working on a website that allows users to see the objects in the sky with VRControls and look into their favorite one with Trackball controls, which is initialized by a click on the object. Here's the demo. https://jsfiddle.net/tushuhei/4f1Lum5n/6/

function focus (obj, target) {
  var dummyCamera = camera.clone();
  controls = new THREE.TrackballControls(dummyCamera);
  controls.target.set(obj.point.x, obj.point.y, obj.point.z);
  new TWEEN.Tween(camera.position)
    .to(target, 1000)
    .onComplete(function() {
      transitioning = false;
      controls.dispose();
      controls = new THREE.TrackballControls(camera);
      controls.target.set(obj.point.x, obj.point.y, obj.point.z);
  }).start();
}

TWEEN works great to make the transitions from WebVR to Trackball mode and vice versa, but there is still a little gap at the end of the transition. I guess this comes from the gap of the camera rotation on the transition completion phase.

Is the any way to make the transition between two different camera controls smooth considering both of camera position and rotation?

Thank you,

Ad

Answer

Ad

You were on the right track with dummyCamera. You need to get the final quaternion and slerp between the initial quaternion and the final one while the tween takes care of the position.

// Save the initial quaternion so that we can use it as a 
// starting point for the slerp.
var startQuaternion = camera.quaternion.clone();

// Apply the tracking controls to a cloned dummy camera so 
// that we can get the final quaternion.
var dummyCamera = camera.clone();
dummyCamera.position.set(target.x, target.y, target.z);
var dummyControls = new THREE.TrackballControls(dummyCamera);
dummyControls.target.set(obj.point.x, obj.point.y, obj.point.z);
dummyControls.update();

// Disable VR controls, so that it doesn't compete with 
// the tween for control  of the camera.
// (Note: now you need to check if the controls are 
// null in the animate function)
controls.dispose();
controls = null;

new TWEEN.Tween(camera.position)
.to(target, 1000)
.onUpdate(function (timestamp){
  // Slerp the camera quaternion as well. 
  // timestamp is the eased time value from the tween.
  THREE.Quaternion.slerp(
    startQuaternion, dummyCamera.quaternion, camera.quaternion, timestamp);
})
.onComplete(function() {
  controls = new THREE.TrackballControls(camera);
  controls.target.set(obj.point.x, obj.point.y, obj.point.z);
}).start();

https://jsfiddle.net/4f1Lum5n/10/

P.S. The way you've implemented this so far may cause a lot of nausea for VR users. It's generally bad practice to take over control of the user's point of view. An alternate solution might be to put the user on a spaceship or platform and tween the platform instead, so that the user has control of the camera at all times.

Ad
source: stackoverflow.com
Ad