Расчет матрицы вида модели для 2D-камеры с использованием Eigen

Я пытаюсь рассчитать матрицу просмотра модели моей 2D-камеры, но не могу правильно понять формулу. Я использую класс преобразования Affine3f, поэтому матрица совместима с OpenGL. Это самое близкое, что я получил методом проб и ошибок. Этот код нормально поворачивает и масштабирует камеру, но если я применяю перемещение и вращение одновременно, движение камеры искажается: камера движется повернутым образом, а это не то, чего я хочу. (И это, вероятно, связано с тем, что я сначала применяю матрицу вращения, а затем перевод)

Eigen::Affine3f modelview;
modelview.setIdentity();
modelview.translate(Eigen::Vector3f(camera_offset_x, camera_offset_y, 0.0f));
modelview.scale(Eigen::Vector3f(camera_zoom_x, camera_zoom_y, 0.0f));
modelview.rotate(Eigen::AngleAxisf(camera_angle, Eigen::Vector3f::UnitZ()));
modelview.translate(Eigen::Vector3f(camera_x, camera_y, 0.0f));
[loadmatrix_to_gl]

Я хочу, чтобы камера вращалась и масштабировалась вокруг положения смещения в экранном пространстве {(0,0) в этом случае - середина экрана}, а затем располагалась вдоль глобальных осей xy в мировом пространстве {(0,0) также Initialy в середине экрана} до конечной позиции. Как бы я это сделал?

Обратите внимание, что я также настроил матрицу орфографической проекции, которая может повлиять на эту проблему.


person JATothrim    schedule 18.05.2012    source источник


Ответы (2)


Если вы хотите, чтобы 2D-изображение, визуализируемое в плоскости XY с помощью OpenGL, (1) вращалось против часовой стрелки на a вокруг точки P, (2) масштабируется по S, а затем (3) преобразуется так, чтобы пиксели в C (в новом масштабированное и повернутое изображение) находятся в начале координат, вы должны использовать это преобразование:

  1. перевести с помощью -P (это перемещает пиксели в точке P в исходное положение)
  2. повернуть на a
  3. перевести на P (это перемещает источник обратно туда, где он был)
  4. масштабировать на S (если бы вы сделали это раньше, ваше вращение было бы испорчено)
  5. перевести с помощью -C

Если 2D-изображение мы визуализируем в начале координат, вам также нужно будет в конце перевести на некоторое значение вдоль отрицательной оси z, чтобы увидеть его.

Обычно вы просто делаете это с основами OpenGL (glTranslatef, glScalef, glRotatef и т. д.). И вы бы сделали их в порядке, обратном тому, что я перечислил. Поскольку вы хотите использовать glLoadMatrix, вы должны делать действия в том порядке, в котором я описал Эйгена. Важно помнить, что OpenGL ожидает матрицу Column Major (но, похоже, это значение по умолчанию для Eigen, так что это, вероятно, не проблема).

person JCooper    schedule 18.05.2012
comment
Спасибо, теперь вроде работает лучше. Однако камера не движется так, как я ожидал: увеличение координаты x также повлияет на координату y, поэтому камера движется по повернутым осям xy, а не по невращающимся осям xy. Это была вторая часть моей проблемы, чтобы заставить камеру двигаться так, как я хотел. Я хочу, чтобы камера просто вращалась и масштабировалась вокруг точки, а затем перемещала камеру в ее положение таким образом, чтобы примененное вращение не влияло на этот перевод. PS: я собираюсь максимально избегать вещей с фиксированным конвейером, поэтому переход на GL 3.0 + шейдеры и новее будет безболезненным. - person JATothrim; 18.05.2012
comment
@JATothrim Я взглянул на спецификацию Eigen. В нем говорится, что используемые вами преобразования применяются справа от матрицы. Я ожидал, что они будут применены слева. Поскольку они применяются справа, вам нужно применить их в обратном порядке. Кроме того, вы можете использовать предварительный поворот и предварительный перевод. - person JCooper; 19.05.2012
comment
Это так близко, но не совсем. Камера теперь вращается и масштабируется вокруг точки, и она нормально перемещается, если нет вращения. Вращение портит перевод (или наоборот), и камера не будет двигаться так, как я это исключаю. Поверните на 90 градусов, и ось Y превратится в ось X при движении камеры! Как предотвратить это? - person JATothrim; 22.06.2012
comment
Я думаю, что наконец-то решил эту проблему с переездом. Ошибка заключалась в том, что я сбросил представление модели, чтобы идентифицировать каждый кадр, даже при перемещении камеры относительно ее текущего положения. Из-за этого извлечение вектора X из представления модели и последующее перемещение в этом направлении не сработало! Я чувствую себя таким глупым сейчас. C: Урок: можно бесконечно цеплять преобразования, никогда не возвращаясь к матрице идентичности. - person JATothrim; 21.09.2012

JCooper отлично объяснил шаги по построению исходной матрицы.

Однако в конце концов я решил проблему немного по-другому. Было несколько дополнительных вещей и шагов, которые не были очевидны для меня в то время. См. комментарии ответа JCooper. Во-первых, нужно понять, что все матричные операции относительны.

Таким образом, если вы хотите расположить или переместить камеру с абсолютными осями xy, вы должны сначала разложить матрицу, чтобы извлечь ее абсолютное положение с неизменными осями. Затем вы переводите матрицу на разницу старой и новой позиции.

Вот способ сделать это с Eigen:

Сначала вычислите скалярный определитель D матрицы Affine2f cmat. С Eigen это делается с помощью D = cmat.linear().determinant();. Затем вычислите «обратную» матрицу matrev текущей матрицы поворота + масштаба R, используя D. matrev = (RS.array() / (1.0f / determ)).matrix());, где RS равно cmat.matrix().topLeftCorner(2,2) Абсолютное положение камеры P определяется как P = invmat * -C, где C равно cmat.matrix().col(2).head<2>()

Теперь мы можем перемещать камеру в любом месте по абсолютным осям, сохраняя вращение и масштабирование одинаковыми: V = RS * (T - P), где RS такое же, как и раньше, T — новая позиция vec, а P — разложенная позиция vec. Затем cmat просто переводится как V для перемещения камеры: cmat.pretranslate(V)

person JATothrim    schedule 19.11.2016