This will be confusing for me to explain so please bear with me.
I've already implemented most type of movements and rotations in my camera class, everything is working with the keyboard, now I want to implement the mouse. I capture the mouse movement like this:
#define SENSITIVITY 25.0f
void main(void) {
(...)
glutPassiveMotionFunc(processPassiveMotion);
glutWarpPointer(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2);
glutSetCursor(GLUT_CURSOR_NONE);
(...)
}
void processPassiveMotion(int x, int y) {
int centerX = WINDOW_WIDTH / 2;
int centerY = WINDOW_HEIGHT / 2;
int deltaX = -1 * (x - centerX);
int deltaY = -1 * (y - centerY);
if(deltaX != 0 || deltaY != 0) {
mainCamera.Rotate(deltaX / SENSITIVITY, deltaY / SENSITIVITY);
glutWarpPointer(centerX, centerY);
}
}
After everything I've read, I believe this is enough in my situation. However I must state that first I tried to call the Pitch()
and Yaw()
camera functions but it was a no go, I had to create an extra function to rotate both axis "at the same time".
That rotate function goes something like this:
#define DEG2RAD(a) (a * (M_PI / 180.0f))
#define SINDEG(a) sin(DEG2RAD(a))
#define COSDEG(a) cos(DEG2RAD(a))
void Camera::Rotate(GLfloat angleX, GLfloat angleY) {
Reference = NormalizeVector(
Reference * COSDEG(angleY) + UpVector * SINDEG(angleY)
);
Reference = NormalizeVector(
Reference * COSDEG(angleX) - RightVector * SINDEG(angleX)
);
UpVector = CrossProduct(&Reference, &RightVector) * (-1);
RightVector = CrossProduct(&Reference, &UpVector);
}
The Reference
is the viewing direction, the point the camera is looking at. And since it's a normalized vector, it goes from -1.0 to 1.0. This vector, or point, is later used together with another vector (Position
, which is the camera location) to calculate the real look at point to use in gluLookAt
, like this:
void Camera::LookAt(void) {
Vector3D viewPoint = Position + Reference;
gluLookAt(
Position.x, Position.y, Position.z,
viewPoint.x, viewPoint.y, viewPoint.z,
UpVector.x, UpVector.y, UpVector.z
);
}
All vector operations above like +
, -
and *
are overloaded of course.
Now I'm going to try to describe my problem...
The rotate function above works just fine in the sense that it correctly performs a pitch and yaw by using the mouse. However, those rotations don't look like the ones in First Person Shooter games. In those games, when one looks at sky and then looks left/right, one expects to keep looking at the sky. Imagining we are inside a sphere, a movement like that should "draw" a circle in the top part of the sphere.
But that's not what happens because that's not what a yaw does. A yaw movement will rotate around an arbitrary axis, which I think is the up vector in this situation. So, the problem is in the yaw movement because the pitch seems to work fine.
In other words, my code above can't keep the horizon leveled and that's what must happen cause that's happens in games when one looks at the sky and then look left/right, the horizon is always leveled. The same will not happen with my code, I look up and then left/right, and the horizon will be all twisted.
Did I make myself clear enough? I'm not sure how can I explain this any better. :( Hopefully it's enough for anyone to understand.
I'm not sure how can I fix this problem... How can I look left/right correctly after looking up/down, keeping the horizon leveled?
EDIT:
My rotate function code is taken from both the Yaw and Pitch functions which also exist so I can call those rotations independently. For reference purposes I'll add them below along with the Roll function too (which I'll probably never use, but in case I need it, it's there):
void Camera::Pitch(GLfloat angle) {
Reference = NormalizeVector(
Reference * COSDEG(angle) + UpVector * SINDEG(angle)
);
UpVector = CrossProduct(&Reference, &RightVector) * (-1);
}
void Camera::Yaw(GLfloat angle) {
Reference = NormalizeVector(
Reference * COSDEG(angle) - RightVector * SINDEG(angle)
);
RightVector = CrossProduct(&Reference, &UpVector);
}
void Camera::Roll(GLfloat angle) {
RightVector = NormalizeVector(
RightVector * COSDEG(angle) - UpVector * SINDEG(angle)
);
UpVector = CrossProduct(&Reference, &RightVector) * (-1);
}