Search code examples
three.jscamerapan

ThreeJS - pan camera vertically without tilting?


I am using Mr Doob's periodic table code in my web app:

https://threejs.org/examples/css3d_periodictable.html

I am using it in Helix view. When I rotate the object left, I shift the camera's Y position by a certain amount too. My desire is to give the impression that the Helix is corkscrewing vertically up and down as you rotate the camera. This is the code I'm using, where angle and panAmount are constants that control how much rotation and vertical pan takes place per second:

    let g_RotationMatrix = new THREE.Matrix4();

    g_RotationMatrix.makeRotationY(angle);

    // Apply matrix like this to rotate the camera.
    self.object.position.applyMatrix4(g_RotationMatrix);

    // Shift it vertically too.         
    self.object.position.y += panAmount;

    // Make camera look at the target.
    self.object.lookAt(self.target);

The problem I'm having is that from the camera's perspective, the object appears to tilt towards you and away from you respectively, depending on the rotation direction, as the camera shifts vertically. This makes sense to me because the I'm guessing that the lookat() function causes the camera to look at the center of the target, and not at point on the target that is closest point to it, so the camera has to tilt to focus on the targe's center of mass. I see the same effect when I use the mouse to pan vertically using the Orbit controls. I believe another way to describe the effect is that the object appears to pitch up and down as the camera shifts vertically.

The effect I want instead is that of a window washer on an automated lift being raised up and down the side of building, with the side of the building appearing perfectly flat to the camera regardless of the camera's current Y position.

How can I achieve this effect with the camera?


Solution

  • Make the camera lookAt the target, but at the same y level as the camera.

    Assuming self.target is a vector3 object and self.object is the camera:

    If, for example, self.target is the camera's rotation center of the object, you wouldn't want to change the actual self.target vector. Make a copy of it first.

    const newTarget = new THREE.Vector3( );
    
    function render( ){
    
        // copy the target vector to newTarget so that the original self.target 
        // will not change and the camera can still rotate around the original
        // target.
        newTarget.copy( self.target );
    
        // Set newTarget's Y from the camera Y. So that is looks horizontal.
        newTarget.y = self.object.position.y; 
    
        // Make the camera look at the objects newTarget
        self.object.lookAt( newTarget);
    
    }