Q:

y-orbit tumbles from top to bottom as mouseY changes in Processing IDE

NOTE: this is in the Processing IDE
I am trying to get spherical orbiting down and i've almost got it. this is what i have so far:
float cameraTheta, cameraPhi, cameraRadius; //camera position in spherical coordinates
float camx, camy, camz;

void setup() {
  size(500, 500, P3D);
  background(255);
  cameraRadius = 200.0f;
  cameraTheta = 2.80;
  cameraPhi = 2.0;
  recomputeOrientation();
}

void draw() {
  background(255);
  lights();
  mouseMotion();
  camera(camx, camy, camz, 0, 0, 0, 0, -1, 0);
  sphereDetail(10);
  sphere(25);
}

void mouseMotion()
{
  if (mousePressed) {
    cameraTheta += (mouseX - pmouseX)*0.05;
    cameraPhi   += (mouseY - pmouseY)*0.05;
  }
  recomputeOrientation();     //update camera (x,y,z) based on (radius,theta,phi)
}

void recomputeOrientation()
{
  camx = cameraRadius * sin(cameraTheta)*sin(cameraPhi);
  camz = cameraRadius * -cos(cameraTheta)*sin(cameraPhi);
  camy = cameraRadius * -cos(cameraPhi);
  redraw();
}

the x rotation works great however the y rotation sort of tumbles from the top to the bottom and then back up again over and over as the mouseY changes, what i need is for it to continue to tumble in one direction as long as the mouse moves up and back the other direction as the mouse moves down. can anyone help me figure this out?

A:

The problem has to do with the up vector for the camera. If you imagine holding the camera and bringing it closer and closer to the pole of the sphere, how do you hold the camera when you go past the pole? Processing knows what to do because of the upY argument of the camera function.
In your current code, the upY is always -1, which means when the camera orients itself, it will always use the vector <0, -1, 0> as its reference for up. You need to change this so that when it gets to the pole of the sphere, it flips upside down.
boolean flip = false;
...
void draw() {
    ...
    camera(camx, camy, camz, 0, 0, 0, 0, flip ? 1.0 : -1.0, 0);
    ...
}

void mouseMotion()
{
    if (mousePressed) {
        cameraTheta += (mouseX - pmouseX) * 0.05;

        if (cameraTheta < 0) cameraTheta += 2 * PI;
        else if (cameraTheta >= 2 * PI) cameraTheta -= 2 * PI;

        if (flip)
            cameraPhi += (mouseY - pmouseY) * 0.05;
        else
            cameraPhi -= (mouseY - pmouseY) * 0.05;

        if (cameraPhi >= PI) {
            cameraPhi = PI - 0.01;
            cameraTheta += PI;
            flip = !flip;
        }
        else if (cameraPhi <= 0) {
            cameraPhi = 0.01;
            cameraTheta -= PI;
            flip = !flip;
        }
    }

    recomputeOrientation();
}

Notable things:

I added code to keep cameraTheta in the range [0, 2 * PI) and cameraPhi in the range [0.01, PI - 0.01). Mathematically, cameraPhi should be in the range [0, PI), but this causes a flicker at the poles. For the math behind this, check here.
cameraPhi is incremented inversely when flip is true.

