Search code examples
three.jsoculusvirtual-realitywebvr

Three.js - VRControls integration - How to move in the scene?


I use Three.js to render and move (my orbitControl changes camera.position) in a small scene.
Now I have an oculus rift. So I added VRControls and VREffect.
There is no problem to move the head.
But I can no more move in the scene because VRControls override the camera parameters :

object.quaternion.copy( state.orientation ); // object is the camera

I thought that it was easy to correct : I have only to update the camera instead of overriding it :

object.quaternion.copy(stateOrientationQuat.multiply(currentCameraQuat));

But it does not work : it renders a moving flicking scene. VRControls and orbitControl seem to fight...

Could you tell me what is to do to integrate VRControls in an existing project ? If you have the update code (I don't really know quaternions...) it would very help.

Thanks


Solution

  • Edit: See my other answer for a better method.


    You can combine both controls by creating a VRControls instance that acts on a fake camera and then apply the transform on top of the orbit controls:

    Relevant snippet:

    var orbitControls = new THREE.OrbitControls(camera);
    
    // Store the position of the VR HMD in a dummy camera.
    var fakeCamera = new THREE.Object3D();
    var vrControls = new THREE.VRControls(fakeCamera);
    
    ...
    
    var render = function() {
      requestAnimationFrame(render);
    
      orbitControls.update();
      vrControls.update();
    
      // Temporarily save the orbited camera position
      var orbitPos = camera.position.clone();
    
      // Apply the VR HMD camera position and rotation
      // on top of the orbited camera.
      var rotatedPosition = fakeCamera.position.applyQuaternion(
        camera.quaternion);
      camera.position.add(rotatedPosition);
      camera.quaternion.multiply(fakeCamera.quaternion);
    
      vrEffect.render(scene, camera);
    
      // Restore the orbit position, so that the OrbitControls can
      // pickup where it left off.
      camera.position.copy(orbitPos);
    };
    

    Full example:

    var renderer = new THREE.WebGLRenderer( { antialias: true } );
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    
    var vrEffect = new THREE.VREffect(renderer, function () {});
    
    var camera = new THREE.PerspectiveCamera(
      75, window.innerWidth / window.innerHeight, 0.1, 1000);
    
    var orbitControls = new THREE.OrbitControls(camera);
    
    // Store the position of the VR HMD in a dummy camera.
    var fakeCamera = new THREE.Object3D();
    var vrControls = new THREE.VRControls(fakeCamera);
    
    var scene;
    var createScene = function () {
      scene = new THREE.Scene();
    
      scene.add(new THREE.PointLight());
    
      var cube = new THREE.Mesh(
        new THREE.BoxGeometry(1, 1, 1),
        new THREE.MeshLambertMaterial({
          color: 'green'
        })
      );
      cube.position.set(-1, -2, -5);
      scene.add(cube);
      orbitControls.target = cube.position;
    
      for (var i = 0; i < 10; i++) {
        cube = new THREE.Mesh(
          new THREE.BoxGeometry(1, 1, 1),
          new THREE.MeshLambertMaterial()
        );
        cube.position.set(
          (Math.random() - 0.5) * 20,
          (Math.random() - 0.5) * 20,
          (Math.random() - 0.5) * 20
        );
        scene.add(cube);
      }
    };
    createScene();
    
    var render = function() {
      requestAnimationFrame(render);
      
      orbitControls.update();
      vrControls.update();
      
      // Temporarily save the orbited camera position
      var orbitPos = camera.position.clone();
      
      // Apply the VR HMD camera position and rotation
      // on top of the orbited camera.
      var rotatedPosition = fakeCamera.position.applyQuaternion(
        camera.quaternion);
      camera.position.add(rotatedPosition);
      camera.quaternion.multiply(fakeCamera.quaternion);
      
      vrEffect.render(scene, camera);
      
      // Restore the orbit position, so that the OrbitControls can
      // pickup where it left off.
      camera.position.copy(orbitPos);
    };
    
    render();
    
    window.addEventListener('resize', function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      vrEffect.setSize( window.innerWidth, window.innerHeight );
    }, false );
    <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/8125c7dac9bf0c7df19bd1d7d9695cbfc0425867/build/three.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/8125c7dac9bf0c7df19bd1d7d9695cbfc0425867/examples/js/effects/VREffect.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/8125c7dac9bf0c7df19bd1d7d9695cbfc0425867/examples/js/controls/VRControls.js"></script>
    <script src="https://cdn.rawgit.com/mrdoob/three.js/8125c7dac9bf0c7df19bd1d7d9695cbfc0425867/examples/js/controls/OrbitControls.js"></script>