Search code examples
three.jsquaternions

three.js: Limiting camera's rotation


I'm working with three.js, attempting to model a real world camera. As such, I'd like to limit its axis of rotation to 90 degrees along x and y axises.

Is there a simply way to do this? My current code isn't working particularly well (and goes crazy when you attempt to move the camera past the X and Y boundaries simultaneously)

if(xRot != null && xRot != undefined){
    camera.rotateX(xRot);            
}

if(yRot != null && yRot != undefined){
    camera.rotateY(yRot);
}

if(camera.rotation.x < minCameraRotX){
    camera.rotation.x = minCameraRotX;
}else if (camera.rotation.x > maxCameraRotX){
    camera.rotation.x = maxCameraRotX;
}     

if(camera.rotation.y < minCameraRotY){
    camera.rotation.y = minCameraRotY;
}else if(camera.rotation.y > maxCameraRotY){
    camera.rotation.y = maxCameraRotY;
}  

Any advice would be greatly appreciated!!!


Solution

  • I actually managed to find a solution by checking some of the existing code in a Three.js demo for a library called PointerLock. The idea is to actually stack multiple objects inside each other: start with an object that moves horizontally (the yaw object), place another object inside the yaw object that moves vertically (the pitch object), and then place the actual camera inside the pitch object.

    Then, you only rotate the outside objects (yaw and pitch) along their respective axises, so if you rotate both, they'll self-correct. For example, if you rotate the yaw 45 degrees along the y-axis (making it turn to the right) and then rotate the pitch 45 degrees (making it turn downward), the pitch will go 45 degrees downward from the yaw's already rotated position.

    Given that the camera is inside both, it just points wherever the yaw and pitch direct it.

    Here is the code

    /*
     * CAMERA SETUP
     *
     * Root object is a Yaw object (which controls horizontal movements)
     * Yaw object contains a Pitch object (which controls vertical movement)
     * Pitch object contains camera (which allows scene to be viewed)
     *
     * Entire setup works like an airplane with a 
     * camera embedded in the propellor...
     *
     */
    
    // Yaw Object
    var yawObject = new THREE.Object3D();
    
    // Pitch Object
    var pitchObject = new THREE.Object3D();    
    
    // Camera Object
    var camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    
    // Max Camera angles (in radians)
    var minCameraRotX = 0.5;
    var maxCameraRotX = 0.5;
    var minCameraRotY = 1;
    var maxCameraRotY = 1;
    
    
    // Setup
    yawObject.add( pitchObject );
    pitchObject.add( camera );
    
    scene.add(yawObject);
    
    ...
    
    var rotateCamera = function(xRot, yRot, zRot){
        yawObject.rotation.y += yRot;
        pitchObject.rotation.x += xRot;
    
        // Enforce X-axis boundaries (rotates around y-axis)
        yawObject.rotation.y = Math.max( minCameraRotY, Math.min( maxCameraRotY, yawObject.rotation.y ) );
    
        // Enforce Y-axis boundaries (rotates around x-axis)
        pitchObject.rotation.x = Math.max( minCameraRotX, Math.min( maxCameraRotX, pitchObject.rotation.x ) );
    }

    Here is the source code I referenced: https://github.com/mrdoob/three.js/blob/acda8a7c8f90ce9b71088e903d8dd029e229678e/examples/js/controls/PointerLockControls.js

    Also, this is sort of cheesy, but this little plane cartoon helped me visual exactly what was going on in my setupenter image description here