3

Where can I change the zoom direction in three.js? I would like to zoom in the direction of the mouse cursor but I don't get where you can change the zoom target.

Kromster
  • 7,181
  • 7
  • 63
  • 111
Niekes
  • 400
  • 1
  • 4
  • 11

6 Answers6

10

updated wetwipe's solution to support revision 71 of Three.js, and cleaned it up a little bit, works like a charm, see http://www.tectractys.com/market_globe.html for a full usage example:

mX = ( event.clientX / window.innerWidth ) * 2 - 1;
mY = - ( event.clientY / window.innerHeight ) * 2 + 1;
var vector = new THREE.Vector3(mX, mY, 1 );
vector.unproject(camera);
vector.sub(camera.position);
camera.position.addVectors(camera.position,vector.setLength(factor));
controls.target.addVectors(controls.target,vector.setLength(factor));
RAM
  • 109
  • 2
  • 5
4

OK! I solved the problem like this...just disable the zoom which is provided by THREEJS.

controls.noZoom = true;

$('body').on('mousewheel', function (e){

        var mouseX = (e.clientX - (WIDTH/2)) * 10;
        var mouseY = (e.clientY - (HEIGHT/2)) * 10;

        if(e.originalEvent.deltaY < 0){ // zoom to the front
            camera.position.x -= mouseX * .00125;
            camera.position.y += mouseY * .00125;
            camera.position.z += 1.1 * 10;
            controls.target.x -= mouseX * .00125;
            controls.target.y += mouseY * .00125;
            controls.target.z += 1.1 * 10;
        }else{                          // zoom to the back
            camera.position.x += mouseX * .00125;
            camera.position.y -= mouseY * .00125;
            camera.position.z -= 1.1 * 10;
            controls.target.x += mouseX * .00125;
            controls.target.y -= mouseY * .00125;
            controls.target.z -= 1.1 * 10;
        }
});

I know it's not perfect...but I hop it will help you a little bit....anyway...I'll work on it to make it even better.

Niekes
  • 400
  • 1
  • 4
  • 11
2

So I recently ran into a similar problem, but I need the zoom to apply in a broader space. I've taken the code presented by Niekes in his solution, and come up with the following:

container.on('mousewheel', function ( ev ){

        var factor = 10;

        var WIDTH = window.innerWidth;
        var HEIGHT = window.innerHeight;

        var mX = ( ev.clientX / WIDTH ) * 2 - 1;
        var mY = - ( ev.clientY / HEIGHT ) * 2 + 1;

        var vector = new THREE.Vector3(mX, mY, 1 );
        projector.unprojectVector( vector, camera );
        vector.sub( camera.position ).normalize();

        if( ev.originalEvent.deltaY < 0 ){
            camera.position.x += vector.x * factor;
            camera.position.y += vector.y * factor;
            camera.position.z += vector.z * factor;
            controls.target.x += vector.x * factor;
            controls.target.y += vector.y * factor;
            controls.target.z += vector.z * factor;
        } else{
            camera.position.x -= vector.x * factor;
            camera.position.y -= vector.y * factor;
            camera.position.z -= vector.z * factor;
            controls.target.x -= vector.x * factor;
            controls.target.y -= vector.y * factor;
            controls.target.z -= vector.z * factor;
        }
});

Its not pretty, but is at least functional. Improvements are welcome :)

Community
  • 1
  • 1
  • It is not working for orthographic camera.Do you have any work around for orthographic camera? – Aasha joney Aug 03 '17 at 04:50
  • @Aashajoney : I haven't worked on three.js in quite some time. Maybe this helps?: https://stackoverflow.com/a/41583081/2299557 – zaSmilingIdiot Aug 07 '17 at 10:42
  • Thank for your response.But the link is for fitting object to the scene. – Aasha joney Aug 07 '17 at 10:58
  • Fair enough... and I see that it was actually your post that I linked to previously. So I found [this](https://blender.stackexchange.com/a/649) which seems to make sense. Ignoring that though, I also found an example [here](https://threejs.org/examples/canvas_camera_orthographic2.html) which from the source seems to get you most of the way there. The rest is moving the camera/scene so as to centre the target object. Should be a combo of some of the coords of the object under the mouse, the camera position/centre, and the scene position/centre. Might be wrong but thats my few cents... – zaSmilingIdiot Aug 07 '17 at 15:06
  • Tysm for your reply – Aasha joney Aug 08 '17 at 06:19
0

Never heard of zoom direction,

you might want to inspect the FOV parameter of the camera,

as well as call this to apply the change:

yourCam.updateProjectionMatrix();
pailhead
  • 5,162
  • 2
  • 25
  • 46
  • 1
    Well, want I mean is that I want the zoom behavior like in Google Maps...the mouse cursor is the point of interest and when you zoom the camera moves in the direction of the mouse cursor...right now you you just can zoom to the center of the document...any idea ? – Niekes Jun 04 '14 at 15:52
  • umm... sort of, it's not trivial. You have to modify the projection matrix. If you look at the opengl matrix, you need to modify the fields with left right top and bottom. So you would have to find your new center, skew the projection, and then scale it (basically the same as changing the fov). – pailhead Jun 04 '14 at 17:28
0

If you are using trackball controls,set

trackBallControls.noZoom=true;

and in mousewheel event use this code,

mousewheel = function (event) {

            event.preventDefault();
            var factor = 15;
            var mX = (event.clientX / jQuery(container).width()) * 2 - 1;
            var mY = -(event.clientY / jQuery(container).height()) * 2 + 1;
            var vector = new THREE.Vector3(mX, mY, 0.1);

            vector.unproject(Camera);
            vector.sub(Camera.position);
            if (event.deltaY < 0) {
                Camera.position.addVectors(Camera.position, vector.setLength(factor));
                trackBallControls.target.addVectors(trackBallControls.target, vector.setLength(factor));
                Camera.updateProjectionMatrix();
            } else {
                Camera.position.subVectors(Camera.position, vector.setLength(factor));
                trackBallControls.target.subVectors(trackBallControls.target, vector.setLength(factor));

            }

        };
Aasha joney
  • 508
  • 5
  • 23
0

I am completely new to Three.js but it's.... wonderful. I am not even a good developer. I am practicing. I was facing the problem of zooming to the mouse location and I think I improved the code a little bit. Here it is.

// zooming to the mouse position
window.addEventListener('mousewheel', function (e) { mousewheel(e); }, false); 
function mousewheel(event) {
    orbitControl.enableZoom = false;
    event.preventDefault();

    // the following are constants depending on the scale of the scene
    // they need be adjusted according to your model scale  
    var factor = 5; 
    // factor determines how fast the user can zoom-in/out  
    var minTargetToCameraDistanceAllowed = 15; 
    // this is the minimum radius the camera can orbit around a target. 

    // calculate the mouse distance from the center of the window
    var mX = (event.clientX / window.innerWidth) * 2 - 1;
    var mY = -(event.clientY / window.innerHeight) * 2 + 1;
    var vector = new THREE.Vector3(mX, mY, 0.5);

    vector.unproject(camera);
    vector.sub(camera.position);

    if (event.deltaY < 0) { 
        // zoom-in -> the camera is approaching the scene
        // with OrbitControls the target is always in front of the camera (in the center of the screen)
        // So when the user zoom-in, the target distance from the camera decrease.
        // This is achieved because the camera position changes, not the target.
        camera.position.addVectors(camera.position, vector.setLength(factor));
    } else { 
        // zoom-out -> the camera is moving away from the scene -> the target distance increase
        camera.position.subVectors(camera.position, vector.setLength(factor));
    }
    // Now camera.position is changed but not the control target. As a result: 
    //  - the distance from the camera to the target is changed, and this is ok.
    //  - the target is no more in the center of the screen and needs to be repositioned. 
    // The new target will be in front of the camera (in the direction of the camera.getWorldDirection() )
    // at a suitable distance (no less than the value of minTargetToCameraDistanceAllowed constant).
    // Thus, the target is pushed a little further if the user approaches too much the target.
    var targetToCameraDistance = Math.max(minTargetToCameraDistanceAllowed, 
                                            orbitControl.target.distanceTo(camera.position));
    var newTarget = camera.getWorldDirection().setLength( targetToCameraDistance ).add(camera.position);
    orbitControl.target = newTarget;

    camera.updateProjectionMatrix();

}

Another improvement could be to set the targetToCameraDistance to the distance of an object hit by the mouse when the user starts orbiting.
If the mouse hit an object, and the distance > minTargetToCameraDistanceAllowed, then the new target is calculated and set.
... but I still don't know how to do this.

fra_rug
  • 1
  • 1