3

I would like to recreate the Three.js OrbitControl movement without the click & drag, i.e. simply making the camera following mouse movement.

I tried to recreate it from scratch, but it was too much effort as the problem is that the camera moves on three axis, not just two. I'm pretty sure some has done before.

Specifically I would like the camera to move around the scene origin keeping the same distance from it.

a.barbieri
  • 2,398
  • 3
  • 30
  • 58
  • In order to solve the problem you have to understand how `OrbitControls` works: it uses a target and a camera, essentially a vector. The input to `OrbitControls` makes calculations on this vector "camera -> target". E.g. a rotation would take the current angle of that vector (relative to some axis), modify that angle by the desired amount, and then move the camera to the new endpoint of the vector plus rotate it towards the target. The length of the vector stays constant, and so does your distance to the target. – Leeft Sep 06 '16 at 20:31
  • I see what you mean, but how do I tell OrbitControls the new position? I've been looking in the [script](https://github.com/mrdoob/three.js/blob/master/examples/js/controls/OrbitControls.js) and I've seen no method to input the new vector. I've seen though that it does remove the mousemove event [here](https://github.com/mrdoob/three.js/blob/master/examples/js/controls/OrbitControls.js#L221). Should I hack/fork this script to make a new version? – a.barbieri Sep 06 '16 at 21:02
  • You'll have to make several changes to get it to do what you want such as removing the click detection, making the mousemove and touchmove events always active. Also look at the `rotateLeft` and `rotateUp` methods (they also handle Right and Down), these are already used to change the angle of the vector in `handleMouseMoveRotate`. – Leeft Sep 06 '16 at 21:10

1 Answers1

6

I had the same requirement as OP. This is how I solved it, with help from Leeft's comments:

  1. Update OrbitControls.js to change scope of function handleMouseMoveRotate from

    function handleMouseMoveRotate( event )
    

    to

    this.handleMouseMoveRotate = function ( event )
    

    This is required for you to manually use this method from within your own code.

  2. In the JS code which loads the model, use the dispose method to remove the default mouse controls and add your own event handler for mousemove which manually calls handleMouseMoveRotate:

    init();
    animate();
    
    function init() {
        // Set up Camera, Scene and OrbitControls
        camera = new THREE.PerspectiveCamera( 45, containerWidth / containerHeight );
        scene = new THREE.Scene();
        controls = new THREE.OrbitControls(camera);
    
        // Remove default OrbitControls event listeners
        controls.dispose();
        controls.update();
    
        ... // omitted for brevity: Load model and Renderer
    
        document.addEventListener('mousemove', onDocumentMouseMove, false);
    }
    
    function onDocumentMouseMove( event ) {
        // Manually fire the event in OrbitControls
        controls.handleMouseMoveRotate(event);
    }
    
    function animate() {
        requestAnimationFrame( animate );
        render();
    }
    
    function render() {
        controls.update();
        camera.lookAt( scene.position );
        renderer.render( scene, camera );
    }
    

NOTE: this solution removes ALL library listeners. If you are interested you can enable them again copying them from here to the end of the update method.

a.barbieri
  • 2,398
  • 3
  • 30
  • 58
timray
  • 588
  • 1
  • 9
  • 24
  • Thank you for putting some effort to find a solution. I haven't tested it yet, but I've seen `dispose()` [will remove every event listener set by the library](https://github.com/mattdesl/three-orbit-controls/blob/f7703452f6373d870e9e5bae4df46e7b53a4aa3e/index.js#L212-L229) and the `update()` method doesn't set them back as [they are called outside that method](https://github.com/mattdesl/three-orbit-controls/blob/f7703452f6373d870e9e5bae4df46e7b53a4aa3e/index.js#L874-L883). Does this monkey patch will remove OrbitControl functionalities (eg. zoom on scroll)? – a.barbieri Aug 17 '18 at 12:11
  • `dispose()` _does_ remove the native OrbitControl functionalities (e.g. zoom and scroll). They aren't re-added when the `update()` method runs, which means you can create your own event handler methods - in this case a call to the only mouse control we're interested in - `handleMouseMoveRotate`. – timray Aug 21 '18 at 10:24
  • 1
    It's important to be aware of that. I update the answer if it's ok with you. – a.barbieri Aug 21 '18 at 15:24
  • This seems to throw Maximum call stack size exceeded error – user3112634 Mar 13 '20 at 22:20