Мне будет сложно объяснять это, поэтому, пожалуйста, потерпите меня.
Я уже реализовал большинство типов движений и вращений в своем классе камеры, все работает с клавиатурой, теперь я хочу реализовать мышь. Я фиксирую движение мыши вот так:
#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);
}
}
После всего, что я прочитал, я считаю, что в моей ситуации этого достаточно. Однако я должен заявить, что сначала я попытался вызвать функции камеры Pitch()
и Yaw()
, но это было бесполезно, мне пришлось создать дополнительную функцию для вращения обеих осей «одновременно».
Эта функция поворота выглядит примерно так:
#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);
}
Reference
- это направление обзора, точка, на которую смотрит камера. А поскольку это нормализованный вектор, он изменяется от -1,0 до 1,0. Этот вектор или точка позже используется вместе с другим вектором (Position
, который является местоположением камеры) для вычисления реальной точки обзора для использования в gluLookAt
, например:
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
);
}
Все векторные операции выше, такие как +
, -
и *
, конечно, перегружены.
Теперь попробую описать свою проблему ...
Вышеупомянутая функция поворота работает отлично в том смысле, что она правильно выполняет наклон и рыскание с помощью мыши. Однако эти повороты не похожи на те, что в играх-шутерах от первого лица. В этих играх, когда человек смотрит на небо, а затем смотрит влево / вправо, он ожидает, что продолжит смотреть на небо. Представьте, что мы внутри сферы, подобное движение должно «нарисовать» круг в верхней части сферы.
Но это не то, что происходит, потому что это не то, что делает рыскание. Движение по рысканью будет вращаться вокруг произвольной оси, которая, я думаю, является вектором вверх в этой ситуации. Итак, проблема в рысканье, потому что шаг, кажется, работает нормально.
Другими словами, мой код выше не может удерживать горизонт выровненным, и это должно произойти, потому что это происходит в играх, когда вы смотрите на небо, а затем смотрите влево / вправо, горизонт всегда выровнен. То же самое не произойдет с моим кодом, я смотрю вверх, а затем влево / вправо, и горизонт будет искажен.
Я достаточно ясно выразился? Я не уверен, как лучше это объяснить. :( Надеюсь, этого хватит, чтобы кто-нибудь понял.
Я не уверен, как мне решить эту проблему ... Как мне правильно смотреть влево / вправо после того, как я посмотрел вверх / вниз, сохраняя горизонт выровненным?
РЕДАКТИРОВАТЬ:
Мой код функции поворота взят из функций Yaw и Pitch, которые также существуют, поэтому я могу вызывать эти вращения независимо. Для справки я добавлю их ниже вместе с функцией Roll (которую я, вероятно, никогда не буду использовать, но, если она мне понадобится, она есть):
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);
}