О кватернионах
#10

Quote:
Originally Posted by Stepashka
View Post
must live simply!!!
PHP Code:
stock GetVehicleRotation(vehicleid,&Float:x,&Float:y,&Float:z) {
    new 
Float:quat_w,Float:quat_x,Float:quat_y,Float:quat_z;
    
GetVehicleRotationQuat(vehicleid,quat_w,quat_x,quat_y,quat_z);
    
atan2(2*((quat_x*quat_y)+(quat_w+quat_z)),(quat_w*quat_w)+(quat_x*quat_x)-(quat_y*quat_y)-(quat_z*quat_z));
    
atan2(2*((quat_y*quat_z)+(quat_w*quat_x)),(quat_w*quat_w)-(quat_x*quat_x)-(quat_y*quat_y)+(quat_z*quat_z));
    
asin(-2*((quat_x*quat_z)+(quat_w*quat_y)));
    return 
1;

Что то не пашет или кони стоят пьяные, а хлопцы запряженные.
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 умножений и 35 сложений. Однако единственная альтернатива - перемножение матриц поворота - требует 27 умножений и 18 сложений. Учитывая, что на операцию сложения (и вычитания, которая тоже считается сложением процессор тратит всего 1 такт, а умножение осуществляется за 4 такта, перемножение кватернионов будет быстрее умножения матриц (83 такта против 126 тактов).
Более того: из этих 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

Найдено на просторах инета.
Reply


Messages In This Thread
О кватернионах - by Romanius - 23.08.2010, 15:46
Re: О кватернионах - by Aleks10 - 23.08.2010, 15:51
Re: О кватернионах - by Stepashka - 23.08.2010, 15:52
Re: О кватернионах - by Romanius - 23.08.2010, 15:53
Re: О кватернионах - by DANGER1979 - 23.08.2010, 16:35
Re: О кватернионах - by ZiGGi - 23.08.2010, 16:38
Re: О кватернионах - by dimonml - 23.08.2010, 20:31
Re: О кватернионах - by Aleks10 - 24.08.2010, 03:33
Re: О кватернионах - by Romanius - 24.08.2010, 06:45
Re: О кватернионах - by DANGER1979 - 24.08.2010, 17:20
Re: О кватернионах - by Stepashka - 24.08.2010, 17:33
Re: О кватернионах - by Stepashka - 24.08.2010, 18:32
Re: О кватернионах - by Aleks10 - 25.08.2010, 01:56
Re: О кватернионах - by DANGER1979 - 25.08.2010, 07:00
Re: О кватернионах - by DANGER1979 - 25.08.2010, 17:32
Re: О кватернионах - by DANGER1979 - 25.08.2010, 19:13
Re: О кватернионах - by DANGER1979 - 25.08.2010, 20:21
Re: О кватернионах - by Stepashka - 26.08.2010, 03:50

Forum Jump:


Users browsing this thread: 2 Guest(s)