OrbitControl - restrict panning movement

2020-03-26 11:49发布

Is there any way to restrict the panning movement of a camera in scene?

Tried altering the pan method in orbitControls but I'm not really satisfied with the result, I wish there was more convenient/proper way to do it..

if ( scope.object instanceof THREE.PerspectiveCamera ) {
    // perspective
    var position = scope.object.position;

    var offset = position.clone().sub( scope.target );
    var targetDistance = offset.length();

    // half of the fov is center to top of screen
    targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );

    // we actually don't use screenWidth, since perspective camera is fixed to screen height
    var dist_l = ( 2 * deltaX * targetDistance / screenHeight );
    var dist_u = ( 2 * deltaY * targetDistance / screenHeight );

    /////// X,Y limit calculation //////
    var limit = 100;
    if( (position.x - dist_l) <= -limit ){
        dist_l = -0.1;
    }else if( (position.x - dist_l)  >= limit){
        dist_l = 0.1;
    }
    if( (position.z - dist_u) <= -limit ){
        dist_u = -0.1;
    }else if( (position.z - dist_u) >= (limit*2.5) ){
        dist_u = 0.1;
    }
    /////// X,Y limit calculation //////

    scope.panLeft( dist_l );
    scope.panUp( dist_u );

} else if ( scope.object instanceof THREE.OrthographicCamera ) {

    // orthographic
    scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth );
    scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight );

}

2条回答
家丑人穷心不美
2楼-- · 2020-03-26 12:02

I have encountered the same problem. The solution is not to touch the pan() function but to check the limits in the update() function. Locate the line 162:

// move target to panned location
scope.target.add( panOffset );

Do your limit calculations right after this line:

if (scope.target.x > 1000)
    scope.target.setX(1000);
if (scope.target.x < 0)
    scope.target.setX (0);
...

This will clamp the target x-position. It works quite smoothly.

查看更多
我只想做你的唯一
3楼-- · 2020-03-26 12:16

I have the exact same problem and thanks to David's solution, which gives me a lot of inspiration. I've some add up to David's answer:

If we only set target X, when keep panning to that limit, I have some unwanted rotation effect. This is because OrbitControls is working with 2 things: the target and the camera. To solve that, we need to set both target and the camera.

scope.target.setX(0); 
camera.position.setX(0);

In this way, we guarantee the camera is always on the top of the object, hence no unwanted rotation happens.

If we want to keep the current rotation angle, we need to do some math. For example in my case, I only enabled the polar rotation:

let polarAngle = scope.getPolarAngle(); 
scope.target.set(0, camera.position.y + camera.position.z * Math.tan(polarAngle), 0);
camera.position.setX(0);

The idea is to set both target and camera position, but don't try to change the rotation angle. If there is rotation, do some math to calculate the target position first.

查看更多
登录 后发表回答