Arcball camera zooming

Viewed 323

I am trying to change the camera view with mouse movement and want the camera to move around the origin in an arcball fashion without going under the scene; so sort of a dome-like view.

The following works satisfactorily for getting the eye coordinates and making this half-arcball view. I hardcoded a condition in order that I would not be able to view underneath the scene. The consequence of this condition is that instead of going under the scene, the camera will zoom into the center instead. I can't wrap my mind around how to impede the camera from doing this 'zoom'. When I get to the lowest part of the dome view, I'd like to only be able to move left or right. Distance is constant. Any guidance?

void onMotion(int x, int y) {
    camX = distance * -sinf(x*(M_PI / 180)) * cosf((y)*(M_PI / 180));
    camY = distance * -sinf((y)*(M_PI / 180));
    camZ = -distance * cosf((x)*(M_PI / 180)) * cosf((y)*(M_PI / 180));
    if (camY < 4) 
        camY = 4;
    glutPostRedisplay();
}
2 Answers

You don't need to constrain the resulting coordinates but the input angle:

4 <= distance * -sin(y)
-4 / distance >= sin(y)
//Assuming y is always between -PI/2 and PI/2
arc sin(-4 / distance) >= y

Hence, at the beginning do the following:

double yAngle = y * M_PI / 180;
double yThreshold = std::asin(-4.0 / distance);
if(yAngle > yThreshold)
    yAngle = yThreshold;

And then use yAngle instead of y.

Btw, your mapping from mouse coordinates to angle seems a bit strange. I am not sure if the assumption in the above formula holds. So you might need to adapt the code. Better yet, adapt the way you calculate the angle. It should probably take the window size into account.

I think this is due to the fact that you aren't fixing the distance when camY < 4. Think about when the cameras nears the south pole of your sphere. You'll set the y coordinate to 4, but the x and z are still near the axis.

Instead of just setting the camY variable, you need to recalculate everything with the new y coord. You could set camY to 4 and then push camX and camZ back to the proper distance in the new direction. Something like this:

if (camY < 4)
{
    camY = 4;
    // Normalize the new vector
    mag = sqrt(camX * camX + camY * camY + camZ * camZ);
    camX /= mag;
    camY /= mag;
    camZ /= mag;

    // Now push it out to distance
    camX *= distance;
    camY *= distance;
    camZ *= distance;
}
Related