Как я могу вращаться вокруг камеры относительно ее целевой точки?


18

Я рисую сцену, где камера свободно перемещается по вселенной. Класс камеры отслеживает точку обзора (или просмотра ), положение камеры и вектор вверх. Эти векторы / точки затем передаются в gluLookAt.

Панорамирование и масштабирование почти тривиальны для реализации. Тем не менее, я нахожу поворот вокруг взгляда на точку гораздо более серьезной проблемой. Я хочу написать функцию Camera.rotate, которая принимает 2 угла, один, который вращается вверх / вниз, и другой, который вращается влево / вправо вдоль воображаемой сферы, которая сосредоточена вокруг взгляда на точку.

Есть простой способ сделать это?

Я (кратко) прочитал о кватернионах, но я хотел посмотреть, было ли более простое решение, учитывая относительно простую конструкцию моей сцены.


У вас есть что-нибудь в вашем наборе инструментов, чтобы повернуть точку вокруг начала координат, учитывая ось и угол?
— Сэм Хочевар

Ничего, кроме моего свободного понимания кватернионов, нет. Чем больше я смотрю на это, я думаю, что Quaternions может быть ответом. Однако я не уверен, как рассчитать значения осей x, y и z для использования в формулах кватернионов.
— Люк

Я не скажу вам, что кватернионы - это не путь. Это очень хорошее решение вашей проблемы. Но вам понадобится кватернионный класс и способы взаимодействия с GL и GLU, и я чувствую, что вы должны сначала попытаться ознакомиться с матрицами преобразования. Другие могут не согласиться.
— Сэм Хоцевар

подумайте, в каком порядке вы выполняете вращения. Применение вращений для перемещения в мировое пространство или для перемещения в пространство камеры отличается
— Чарли

Ответы:


25

То, что вы просите, называется ротацией Arcball. Кватернионы - это простое решение, только если вы понимаете, как они работают. Однако вы можете достичь того же самого без кватернионов.

Предпосылки

Вы знаете, как вращать объекты в целом? Допустим, у вас есть объект в начале координат. Знаете ли вы, как вы поворачиваете его (подсказка: умножьте на некоторую матрицу вращения)? Если да, то я предполагаю, что вы знаете, что произойдет, если вы сначала переведите объект, а затем поверните его?

Вы должны знать, как рассчитать матрицу вращения по оси угла (просто, как круговая диаграмма, посмотрите на множество онлайн-уравнений, многие из них также дают вам код)

Решение

  • Получить камеры вверх и вправо векторов. Обратите внимание, что они должны быть нормализованы.
  • Получить вектор от точки фокусировки на камеру (camPosition - Focus). Это вектор, который вы собираетесь вращать. Давайте назовем это camFocusVector .
  • Решите, сколько вы хотите повернуть в рысканье / тангаже по отношению к камере
  • Создайте две матрицы вращения. Матрица первого поворота будет использовать вверх камеры как оси и поворот вокруг вертикальной оси под углом , что вы решили. Матрица второго поворота будет использовать право камеры в качестве оси и тангажа угла , который вы решили.
  • Теперь поверните camFocusVector с новыми матрицами вращения. Теперь это ваша новая позиция камеры относительно начала координат. Мы, конечно, хотим, чтобы это было относительно точки фокуса ...
  • Добавьте положение точки фокусировки в camFocusVector . Теперь это новая позиция вашей камеры. Переведите свою камеру соответственно.
  • Наконец, попросите камеру сфокусироваться на точке фокусировки, вызвав функцию lookAt ()

Предостережения

Вам придется следить за определенными случаями или особенностями, при которых ваша камера перестанет работать. Глядя прямо вниз / вверх, например. Я дам вам понять, как с этим справиться.

EDIT1: Как пересчитать ортонормированные векторы камеры

Вы уже знаете направление камеры ((cameraPos - focusPoint) .normalize ()). Теперь предположим, что у вашей камеры вверх + Y (или если текущая верхняя ось вашего мира ... это зависит от вас). Теперь просто пересечь направление с вверх , чтобы получить право . Выполнено? Нет! Ваш верхний вектор больше не является ортогональным к двум другим. Чтобы исправить это, перекрестное право с руководством , и вы получите ваш новый вверх .

Обратите внимание, что Грам-Шмидт действительно то, что следует использовать для ортонормирования векторов.

Опять же, обратите внимание на предостережения, так как в некоторых случаях это не сработает (например, направление параллельно вверх ).


Обратите внимание, что правый вектор можно получить с помощью normalize(up ^ camFocusVector)(или его противоположность, если левша).
— Сам Хочевар

Выглядел хорошо до сих пор, прекрасно работал для вращения влево / вправо (у меня есть вектор вверх, так что это легко). Что означает «^» в вашем комментарии @SamHocevar? Это перекрестный продукт? Кроме того, как я могу пересчитать вектор повышения после выполнения переводов?
— Люк

@Luke: Проверьте мой EDIT1
— Самаурса

1
@Samaursa Большое спасибо. Ваше решение работает отлично, и я многому научился в процессе!
— Люк

2
это ОТЛИЧНЫЙ ответ, большое спасибо за ваше объяснение. В моем случае я хотел, чтобы камера вращалась только вокруг целевой точки в плоскости XY, и поэтому после выполнения всех вычислений я всегда устанавливал cameraRight.z в 0, а затем вычислял вектор cameraUp. Это дало желаемый эффект. Просто подумал поделиться
— codemonkey

1

Что вам нужно, это обычная камера ArcBall, которая в основном представляет собой камеру, которая сохраняет местоположение цели и позволяет вам перемещать камеру «сферически» вокруг этой цели.

Это в XNA, но IIRC я ​​использовал эту реализацию раньше, и она работала довольно хорошо:

http://roy-t.nl/index.php/2010/02/21/xna-simple-arcballcamera/


Эта реализация, кажется, движется только по правому вектору, который будет приближаться к небольшому значению величины . Он также перемещает точку LookAt, как то, куда я хочу переместить камеру (близко, но немного по-другому). Я считаю, что Самаурса предоставил самый простой и полный способ достижения этой цели.
— Люк

Спасибо за ваш отзыв. Я должен признать, что я использовал эту реализацию немного как «черный ящик», но я не заметил никаких проблем. Чтобы уточнить, возможно, вы говорили о методах MoveCameraRight / MoveCameraForward? Эти методы были добавлены для перемещения камеры, но не являются частью интерфейса Arcball. Если вы хотите повернуть камеру вокруг цели, вы просто измените свойства Yaw или Pitch.
— Дэвид Гувея

Извините, вы правы, это методы панорамирования. Я не заметил, как он установил грязный флаг для матрицы при изменении рыскания и высоты тона.
— Люк

0

Вот мой код для поворота вокруг точки, и я часто использую его.

float distance;      // Straight line distance between the camera and look at point

// Calculate the camera position using the distance and angles
float camX = distance * -sinf(camAngleX*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));
float camY = distance * -sinf((camAngleY)*(M_PI/180));
float camZ = -distance * cosf((camAngleX)*(M_PI/180)) * cosf((camAngleY)*(M_PI/180));

// Set the camera position and lookat point
gluLookAt(camX,camY,camZ,   // Camera position
          0.0, 0.0, 0.0,    // Look at point
          0.0, 1.0, 0.0);   // Up vector

1
Это в основном так, как я сделал это изначально. Есть много проблем с этим (по крайней мере, для меня). В основном эта реализация вращает только около 2 фиксированных осей. Допустим, вы поворачиваете вверх почти до северного полюса . Затем поверните направо . Вы обнаружите, что вращаетесь по крошечному кругу, а не следите за правильным вектором камеры по всему земному шару .
— Люк

Теперь, когда вы упомянули об этом, я думаю, что есть два разных взгляда на проблему. В моем приложении я использовал камеру ArcBall для вращения вокруг целевого острова на море, и если бы я использовал 3 оси свободы, это выглядело бы совершенно неправильно (например, видя остров вверх ногами или сбоку).
— Дэвид Гувейя

Как мне получить углы камеры здесь?
— rafvasq

0

Этот очень простой алгоритм для достижения этого довольно крутой:

Будучи P центральной точкой, которую вы хотите повернуть (точка «взгляда» или «цели»):

translate(-P)

rotate horizontal
rotate vertical

translate(P)

Я использовал это, и это приятно.

Источник найден на дочернем сайте stackoverflow: /programming/287655/opengl-rotating-a-camera-around-a-point

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.