Вращение камеры вокруг центра экрана
Для создания матрицы вида я использую две матрицы: матрица вращения (mRotation) и матрица трансляции (mTranslation).
Я хочу сделать так чтобы вращение было вокруг центра экрана вместо [0, 0, 0] в мировом пространстве.
Код вращения:
void Camera::rotate(float angleX, float angleY)
{
transform.rotation.x += angleX;
transform.rotation.y += angleY;
const glm::vec3 center{mTranslation[3][0], mTranslation[3][1], 0.0f};
glm::mat4 rot{1.0f};
rot = glm::rotate(rot, transform.rotation.y, glm::vec3(1.0f, 0.0f, 0.0f));
rot = glm::rotate(rot, transform.rotation.x, glm::vec3(0.0f, 1.0f, 0.0f));
rot = glm::rotate(rot, transform.rotation.z, glm::vec3(0.0f, 0.0f, 1.0f));
mRotation = glm::translate(center) * rot * glm::translate(-center);
mView = mTranslation * mRotation;
mViewInverse = glm::inverse(mView);
}
Кстати я пробовал менять местами переумножение матриц:
mRotation = glm::translate(-center) * rot * glm::translate(center);
Результат тот же
Паномирование:
void Camera::pan(float x, float y)
{
const float zoomAmount = std::abs(mTranslation[3][2]);
glm::vec4 motion(x * zoomAmount, y * zoomAmount, 0.f, 0.f);
mTranslation = glm::translate(glm::vec3(motion)) * mTranslation;
updateViewMatrix();
}
В качестве центра вращения я использую данные из матрицы трансляции. По идее данные верны. Центр вращения изначально идёт в [0, 0, 0]. Далее я двигаю сцену, масштабирую и данные с центра трансляции изменяются в соответствии с паномированием и масштабированием.
Но у меня происходит какая-то ошибка. Если я паномирую, вращаю, паномирую и снова вращаю, то сцена куда-то сдвигается. Это как-то странно ведь в первых двух шагах(паномирование, затем вращение) ничего не сдвигается. Подскажите пожалуйста что не так? Такое ощущение что центр трансляции сбивается и становится [0, 0, 0]
Ошибка выглядит так:
P.S.: Кстати, если для вектора center я указываю статичные данные (к примеру, [1.0f, 1.0f, 0.0f]), то трансляция как тут не сбивается
UPD: Кажется я понял в чём проблема. Я когда менял матрицу при вращении менял все углы. Но центр же изменился. И изменять поидее нужны только новые углы. Т.е. был центр в [0, 0], произошло вращение. Далее центр сместился, скажем вправо. И менять нужны только те изменения которые возникли при новом центре. Но я пока не знаю как это пофиксить. У меня получается какая-то аркбол камера.
const glm::vec3 center = {mTranslation[3][0], mTranslation[3][1], 0.0f};
glm::quat rotationQuat{{angleY, -angleX, 0.0f}};
glm::quat reverseOrient = glm::conjugate(rotationQuat);
glm::mat4 rotationChanges = glm::translate(-center) * mat4_cast(reverseOrient) * glm::translate(center);
mRotation = mRotation * rotationChanges;
Как можно сложить 2 матрицы вращения?
UPD: Ещё раз погуглил похожие вопросы. Ничего так и не вышло. Попробовал упростить. Даже без изменения углов матрица сдвигается. При этом я заметил что если изначальная позиция находится в +Z (к примеру, когда изначально формируем матрицу через glm::lookAt), то сцена почти не сдвигается. А если в -Z, то происходит деформация.
Чтобы было почти минимальное искажение для +Z:
mRotation = glm::translate(center) * rot * glm::translate(-center);
Для -Z:
mRotation = glm::translate(center) * rot * glm::translate(center);
Я не очень понимаю как это связано. При этом если рассмотрим вариант с -Z, то результат будет идентичным:
mRotation = glm::translate(center) * rot * glm::translate(-center);
mRotation = glm::translate(center) * rot;
Почему ничего не меняется когда я обратно транслирую на pivot point?
Ответы (1 шт):
Ошибка была в неправильном порядке умножения матриц. Было:
mRotation = glm::translate(-center) * rot * glm::translate(center);
mView = mTranslation * mRotation;
Надо:
mRotation = rot;
mView = glm::translate(-center) * mTranslation * mRotation * glm::translate(center);

