Мне будет сложно объяснить, поэтому, пожалуйста, потерпите меня.
Я уже реализовал большинство типов движений и вращений в своем классе камеры, все работает с клавиатурой, теперь я хочуреализовать мышь.Я фиксирую движение мыши так:
#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);
}