У меня есть объект в мировом пространстве, скажем, в (0,0,0), и я хочу повернуть его в лицо (10,10,10).
Как мне сделать это с помощью кватернионов?
Этот вопрос не совсем имеет смысла. Вы сказали, что хотите, чтобы объект «смотрел» на определенную точку, но это не дает достаточно информации.
Во-первых, что это значит для лицо это направление? В OpenGL это означает, что -Z ось в локальной системе отсчета выровнена с указанным направлением в некоторой внешней системе отсчета. Чтобы это выравнивание произошло, нам нужно знать, в каком направлении соответствующая ось объекта в данный момент «обращена».
Однако это все еще не определяет уникальную трансформацию. Даже если вы знаете, в каком направлении -Z ось точки, объект все еще может вращаться вокруг эта ось. Вот почему функция gluLookAt()
требует, чтобы вы указали направление «в» а также направление «вверх».
Следующее, что нам нужно знать, — это в каком формате должен быть конечный результат? Ориентация объекта часто сохраняется в формате кватерниона. Однако, если вы хотите графически поверните объект, тогда вам может понадобиться матрица вращения.
Итак, давайте сделаем несколько предположений. Я предполагаю, что ваш объект центрирован в точке мира с и имеет выравнивание по умолчанию. Т.е. объект Икс, Y, а также Z оси выровнены с миром Икс, Y, а также Z Оси. Это означает, что ориентация объекта относительно мира может быть представлена как единичная матрица или кватернион идентичности: [1 0 0 0]
(используя кватернионное соглашение, где вес приходит первым).
Если вы хотите самое короткое вращение, которое выровняет объект -Z ось с точкой п: = [p.x p.y p.z], то вы будете вращаться на φ вокруг оси . Теперь мы найдем эти значения. Сначала мы находим ось нормализуя вектор ПК а затем взять перекрестное произведение с длиной единицы -Z вектор, а затем снова нормализуется:
= нормализовать (crossProduct (-Z, нормализуют (ПК)));
Самый короткий угол между этими двумя единичными векторами, найденными путем взятия обратного косинуса их точечного произведения:
φ = acos (dotProduct (-Z, нормализуют (ПК)));
К сожалению, это мера абсолютного значения угла, образованного двумя векторами. Нам нужно выяснить, является ли он положительным или отрицательным при вращении вокруг . Должен быть более элегантный способ, но первый способ, который приходит на ум, — это найти третью ось, перпендикулярную обоим а также -Z и затем возьмите знак от его точечного произведения с нашей целевой осью. Вис:
б = crossProduct (, -Z );
if (dotProduct (б, нормализуют (ПК))<0) φ = -φ;
Когда у нас есть ось и угол, легко превратить его в кватернион:
Q = [cos (φ / 2) sin (φ / 2)];
Этот новый кватернион представляет новую ориентацию объекта. Он может быть преобразован в матрицу для целей рендеринга, или вы можете использовать его для непосредственного вращения вершин объекта, если это необходимо, используя правила умножения кватернионов.
Пример вычисления кватерниона, представляющего вращение между двумя векторами, можно найти в исходном коде OGRE для Огре :: Класс Vector3.
В ответ на ваше разъяснение и просто на это я бесстыдно скопировал очень интересный и аккуратный алгоритм поиска квата между двумя векторами, который, как я никогда раньше не видел, Вот. Математически это кажется правильным, и, поскольку ваш вопрос касается математики, я уверен, что вы сможете конвертировать этот псевдокод в C ++.
quaternion q;
vector3 c = cross(v1,v2);
q.v = c;
if ( vectors are known to be unit length ) {
q.w = 1 + dot(v1,v2);
} else {
q.w = sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2);
}
q.normalize();
return q;
Дайте мне знать, если вам нужна помощь в разъяснении каких-либо фрагментов этого псевдокода. Должно быть простым, хотя.
dot(a,b) = a1*b1 + a2*b2 + ... + an*bn
а также
cross(a,b) = well, the cross product. it's annoying to type out and
can be found anywhere.
Вы можете использовать SLERP (сферическая линейная интерполяция). Видеть это статья для справки о том, как сделать это в C ++