24.08.2010, 17:20
Quote:
must live simply!!!
PHP Code:
|
dimonml философии много конкретики мало.
Сам по себе кватернион - это гиперкомплексное число. Состоит из 4х компонент (X, Y, Z и W). Первые три компоненты задают направление оси, а четвертая задает угол поворота вокруг этой оси в радианах. Это правда не совсем правда, но так проще понять. Кватернион это число + вектор (образно говоря).
Кватернион это (если не вдаваться в математические подробности) просто 4D-вектор:
q=(x; y; z; w),
подобранный так, что x*x+y*y+z*z+w*w=1 (это т.н. нормированный кватернион - именно их обычно и используют).
Его можно также условно разбить на два компонента: векторный - v=(x; y; z) и скалярный - w.
Чем удобен кватернион? Да тем, что позволяет очень просто работать с вращениями. Например, все операции с матрицами крайне ресурсоёмки (чего стоит, к примеру, нахождение обратной матрицы поворота!), а работа с углами Эйлера - вообще самый ненадёжный способ представления вращения.
.
Новички чаще всего (по себе знаю!) в своих программах реализуют вращение с помощью углов Эйлера - т.е. простых поворотов вокруг осей x,y,z. В "профессиональных" играх такой подход не используется, т.к.:
Результат зависит от порядка вращения (т.е. если менять порядок следования осей, то результаты будут различны);
Очень трудно вычислить углы поворота, переводящего "взгляд" камеры из позиции A в позицию B. Например, требуется сделать плавную анимацию - поворот объекта. Простым плавным изменением углов тут не обойдёшься: в большинстве случаев подобные развороты будут выглядеть неестественно, камера ведёт себя "неправильно" - не так, как ожидает программист. Некоторые трятят часы, пытаясь понять, почему всё работает не так, как надо.
Тут можно посоветовать лишь отказаться от углов Эйлера.
.
Кватернион задаёт поворот не вокруг осей x,y,z, а вокруг любой, ПРОИЗВОЛЬНОЙ оси.
Итак, если нужно повернуть сцену вокруг некоторого вектора с координатами (x;y;z) на угол A, то кватернион, осуществляющий такой поворот, можно вычислить так:
q.x=x*Sin(A/2)
q.y=y*Sin(A/2)
q.z=z*Sin(A/2)
q.w=Cos(A/2)
Только потом важно не забыть нормировать кватернион - т.е. сделать так, чтобы выполнялось вышеуказанное правило - x*x+y*y+z*z+w*w=1
Это можно сделать, например, так:
n=1/sqrt(q.x*q.x+q.y*q.y+q.z*q.z+q.w*q.w)
q.x=q.x*n
q.y=q.y*n
q.z=q.z*n
q.w=q.w*n
Кватернионы хороши тем, что с ними очень легко работать. Например, их можно складывать (покомпонентно). Сумма кватернионов - это "смесь" тех поворотов, которые они задают. Т.е. конечный кватернион будет представлять некий усреднённый поворот. Кватернионы, как и матрицы, можно перемножать. Допустим, объект нужно повернуть сперва с помощью кватерниона A, затем - с помощью кватерниона B. Тогда поворот можно осуществить одной операцией, повернув объект кватернионом C=A*B. Произведение кватернионов не коммутативно, т.е. AB не равно BA.
Перемножение кватернионов описывается довольно сложной формулой, но есть способы его ускорить - в сети полно "быстрых" методов умножения кватернионов. Вот, например, так можно вычислить произведение q1*q2:
Code:
A=(q1.w+q1.x)*(q2.w+q2.x) B=(q1.z-q1.y)*(q2.y-q2.z) C=(q1.x-q1.w)*(q2.y+q2.z) D=(q1.y+q1.z)*(q2.x-q2.w) E=(q1.x+q1.z)*(q2.x+q2.y) F=(q1.x-q1.z)*(q2.x-q2.y) G=(q1.w+q1.y)*(q2.w-q2.z) H=(q1.w-q1.y)*(q2.w+q2.z) result.w= B + (-E - F + G + H) * 0.5 result.x= A - ( E + F + G + H) * 0.5 result.y=-C + ( E - F + G - H) * 0.5 result.z=-D + ( E - F - G + H) * 0.5
Более того: из этих 12 перемножений здесь есть 4 умножения на 0.5, которые вычисляются тоже за 1 такт. В результате перемножения нормированных кватернионов всегда получается нормированный кватернион.
.
Ну, а теперь - чуть ближе к сути вопроса. Допустим, нам нужно сперва повернуть объект вокруг оси X на угол A, затем - вокруг оси Y на угол B, и наконец - вокруг оси Z на угол C. Кватернион, задающий вращение, эквивалентное всем трём поворотам, можно вычислить так:
qx.x=sin(A/2)
qx.y=0
qx.z=0
qx.w=cos(A/2)
qy.x=0
qy.y=sin(B/2)
qy.z=0
qy.w=cos(B/2)
qz.x=0
qz.y=0
qz.z=sin(C/2)
qz.w=cos(C/2)
q=qx*qy*qz
ну, о перемножении кватернионов я уже говорил. Кстати, в DirectX (точнее, в D3dx9.lib) есть специальная функция для умножения кватернионов - D3DXQuaternionMultiply, хотя она работает не слишком быстро. Бесконечные преобразования поворотов (кватерниона в матрицу, углов Эйлера - в кватернион и др.) очень ресурсоёмки, т.к. используют тригонометрические функции и требуют кучи умножений. Поэтому в высокоскоростных 3D-приложениях (играх, например) все повороты нужно хранить единообразно - чтобы обходиться без преобразований.
Где можно подробнее почитать о кватернионах? Ну, например, на Gamedev'е:
http://www.gamedev.ru/articles/?id=30129 - статья М. Нореля "Вращение и кватернионы: сборник рецептов"
http://www.gamedev.ru/coding/10805.shtml - статья С. Ваткина "Кватернионы в программировании игр"
Статьи излагают самые основы кватернионной математики, т.е. на самом деле у кватернионов куда больше возможностей.
Углы Эйлера
Вращение задаётся yaw, pitch и roll. Тогда кватернион вычисляется следующим образом:
qroll = [cos (y/2), (sin(y/2), 0, 0)]
qpitch = [cos (q/2), (0, sin(q/2), 0)]
qyaw = [cos (f/2), (0, 0, sin(f/2))]
q = qyaw qpitch qroll
Найдено на просторах инета.