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

Другие вопросы по тегам