OpenGL - как переместить сцену в ответ на ввод с помощью мыши, используя gluLookAt
Я использую OpenGL в Qt через QGLWidget
и я пытаюсь реализовать базовое взаимодействие с мышью и клавиатурой.
Так, например, клавиши со стрелками на клавиатуре будут использоваться для "панорамирования" сцены, колесико мыши - для увеличения масштаба сцены, а мышь - для поворота модели.
Я понял, как реализовать панорамирование и масштабирование, но у меня возникли проблемы с реализацией поворота.
Это то, что я до сих пор:
void MyGLWidget::paintGL() {
glLoadIdentity();
gluLookAt(0+camDelta[0],0+camDelta[1],-100+camDelta[2],centerCoords[0]+lookAtDelta[0],centerCoords[1]+lookAtDelta[1],centerCoords[2]+lookAtDelta[2],0,1,0);
// draw stuff here
}
Так что в основном я установил начальный gluLookAt
параметры, а затем я добавил два массива, float camDelta[3]
а также float lookAtDelta[3]
, чтобы отслеживать изменения в положении камеры и где она смотрит в ответ на взаимодействие пользователя со сценой.
Для колесика мыши я делаю:
void MyGLWidget::wheelEvent(QWheelEvent *event) {
camDelta[2] += (event->delta() / 8.0 / 15.0) * WHEEL_DELTA;
lookAtDelta[2] += (event->delta() / 8.0 / 15.0) * WHEEL_DELTA;
updateGL();
}
Точно так же в MyGLWidget::keyPressEvent
Я изменяю дельты [0]
поле для панорамирования влево и вправо, и дельты [1]
для панорамирования вверх и вниз.
Итак, мой вопрос: как мне реализовать нечто подобное для поддержки вращения мышью? Я немного сбит с толку, потому что, полагаю, мне придется каким-то образом изменить не только то, куда смотрит камера, но и вектор повышения, но у меня нет четкого представления о том, как это сделать.
2 ответа
То, что я сделал для таких вещей, называется моделью орбитальной камеры.
Вы отслеживаете положение цели камеры (или посмотрите на нее) и 3 других параметра: азимут, наклон (или наклон) и расстояние (или радиус). Азимут - это вращение камеры вокруг цели по горизонтали (как если бы цель находилась на земле, а вы гуляли по ней по кругу, глядя на нее). Склонение - это вертикальное вращение. Расстояние - это расстояние между целью и камерой.
Они также называются сферическими координатами:
http://mathworld.wolfram.com/SphericalCoordinates.html
Вы хотите уравнения, как это:
x = r * sin(phi) * cos(theta)
y = r * sin(phi) * sin(theta)
z = r * cos(phi)
Где r - расстояние, тета - азимут, а фи - склонение. Это дает вам смещение, чтобы перейти от положения обзора камеры к положению камеры.
Итак, вот что вы делаете. Сохраняйте позицию цели камеры, но не позицию камеры. Когда вы перемещаете камеру, перемещайте целевую позицию. При вращении камеры отрегулируйте азимут и наклон. При увеличении камеры отрегулируйте расстояние. Затем в каждом кадре перед вызовом gluLookAt вычисляйте положение камеры по приведенной выше формуле. Вы просто добавляете эти x, y и z к целевой позиции.
Наилучшим подходом для этого является использование кватернионов. Подобно тому, как комплексные числа весьма полезны для вращения в 2D, кватернионы идеально подходят для трехмерного вращения.
Стандарт "вращаться вокруг оси x, y, z" может работать, он будет вести себя странно и не так, как ожидалось.
Вы можете получить хороший учебник обо всем этом по адресу: http://content.gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation