Search code examples
javaopenglgraphicscamerascene

Orbit controls make scene disappear after a while


I am using JOGL to build a point cloud viewer and I have implemented my own orbit controls. It works very well for a while, but at some point (I think after dragging the mouse left and right very quickly) the scene completely disappears. Here is my code:

public void mouseDragged(MouseEvent e) {
    if (oldX < 0.0005 && oldY < 0.0005) {
        // when the mouse drag starts initially           

        oldX = e.getX();
        oldY = e.getY();
    } else {
        float differenceX = e.getX() - oldX;
        float differenceY = e.getY() - oldY;

        oldX = e.getX();
        oldY = e.getY();

        float speedX = differenceX / 2;
        float speedY = differenceY / 2;

        Vector3f velocityX = new Vector3f();
        Vector3f velocityY = new Vector3f();

        Vector3f oldTarget = camera.getTarget();
        Vector3f cameraRight = new Vector3f();

        // getting right vector of the camera in the world space

        camera.getDirection().cross(camera.getWorldUp(), cameraRight);

        /* moving the camera first along its right vector
         * then setting its target to what it was originally
         * looking at */

        cameraRight.mul(-speedX, velocityX);
        camera.translate(velocityX);
        camera.setTarget(oldTarget);

        /* moving the camera second along its up vector
         * then setting its target to what it was originally
         * looking at */

        camera.getUp().mul(-speedY, velocityY);
        camera.translate(velocityY);
        camera.setTarget(oldTarget);
    }
}

I first thought that it would be because when the camera direction vector and the world up vector are identical, the camera right vector (cross product between the two) would be zero, but that would only mean for the controls to lose one dimension of movement; this should not cause the entire scene to go away.


Solution

  • The idea I originally came up with distanced the camera from its point of focus with each rotation (at some point beyod the far plane). The solution to this problem is to implement the orbit controls using the polar coordinate system. As such, in your mouseDragged() method:

    if (oldX < 0.0005 && oldY < 0.0005) {
        oldX = e.getX();
        oldY = e.getY();
    } else {
        float differenceX = e.getX() - oldX;
        float differenceY = e.getY() - oldY;
    
        oldX = e.getX();
        oldY = e.getY();
    
        // getting the current position of the camera in the spherical coordinate system
    
        Vector3f sphericalCoords = MathUtils.toSphericalCoords(camera.getPosition());
    
        float speedY = (float)Math.toRadians(differenceY / 4.0f);
        float speedX = (float)Math.toRadians(differenceX / 4.0f);
    
        // adding speedY to the theta angle and speedX to the phi angle
    
        sphericalCoords.add(new Vector3f(0, speedY, speedX));
    
        // making sure the angles are not outside the [0, 2 * PI] interval
    
        polarCoords.y = MathUtils.wrapTo2Pi(sphericalCoords.y);
        polarCoords.z = MathUtils.wrapTo2Pi(sphericalCoords.z);
    
        // updating the position of the camera
    
        camera.setPosition(MathUtils.toCartesianCoords(sphericalCoords));
    }