О кватернионах -
Romanius - 23.08.2010
Для чего их можно использовать?
Я как понял если их перевести с помощью
этого конвертера то можно узнать поворот тачки в пространстве те если она перевернута, лежит боком и тп. Я правильно думаю?
Re: О кватернионах -
Aleks10 - 23.08.2010
а зачем они вообще нужны??
сделали бы сразу поворот машины да и всё
п.с. да, и что это такое?
Re: О кватернионах -
Stepashka - 23.08.2010
Да, получишь угол поворота тачки по всем осям.
Re: О кватернионах -
Romanius - 23.08.2010
2 Вопрос. Нахрена мне их получать если я их задать не могу

?
Re: О кватернионах -
DANGER1979 - 23.08.2010
Я уже писал для чего бы я использовал.
Во-первых: для правильной установки шипов на дороге, т.е. для передачи этих углов зависимым объектам.
Re: О кватернионах -
ZiGGi - 23.08.2010
Quote:
Originally Posted by Romanius
2 Вопрос. Нахрена мне их получать если я их задать не могу  ?
|
кстати да

куй забыл про такую ф-ию
но он сделал ускорение:
https://sampwiki.blast.hk/wiki/SetVehicleAngularVelocity
Re: О кватернионах -
dimonml - 23.08.2010
Кватернионы очень удобны для задания поворота объекта в пространстве и по этой причине очень часто используются в компьютерных играх
Re: О кватернионах -
Aleks10 - 24.08.2010
ыы, решил посмотреть в википедии, что это такое...
а оказывается, это ж самые простые... x y z w !
я делал программу 3D на сишке, но там я матрицы трансформировал, в обычные координаты x y z...
вот примерно тааак:
Code:
void multiplication (Vector4& v, Matrix& m)
{
float x = v.x, y = v.y, z = v.z, w = v.w;
v.x = x * m._11 + y * m._21 + z * m._31 + w * m._41;
v.y = x * m._12 + y * m._22 + z * m._32 + w * m._42;
v.z = x * m._13 + y * m._23 + z * m._33 + w * m._43;
v.w = x * m._14 + y * m._24 + z * m._34 + w * m._44;
}
void transformation (Vertex& vertex, Vector4& vector, Matrix& matWorld,
Matrix& matCam, Matrix& matProj)
{
Vector4 tempv = vector;
multiplication(tempv, matWorld);
multiplication(tempv, matCam);
multiplication(tempv, matProj);
tempv.x /= tempv.w;
tempv.z /= tempv.w;
tempv.y /= tempv.w;
tempv.w /= tempv.w;
vertex.x = tempv.x;
vertex.y = tempv.y;
vertex.z = tempv.z;
}
Re: О кватернионах -
Romanius - 24.08.2010
алекс было бы лучше еслиб ты еще классы (Vector4, Matrix) или то у тя там кинул
Re: О кватернионах -
DANGER1979 - 24.08.2010
Quote:
Originally Posted by Stepashka
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);
x = 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));
y = 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));
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
Найдено на просторах инета.
Re: О кватернионах -
Stepashka - 24.08.2010
Пашет, но углы неверно определяет =(
Короче косяк, кватернионы это не углы, это само вращение по осям, грубо говоря действие в цифрах
Re: О кватернионах -
Stepashka - 24.08.2010
Нашел вот что, смотрите вложение
Re: О кватернионах -
Aleks10 - 25.08.2010
хехе

ну вобщем смотрите, чтобы определить координаты, нужно знать матрицу
мы её не знаем... и + нам нужно из матрицы как то вытрясти углы поворота
вот вращение вокруг осей:
x - [ 1 0 0 ]
[ 0 cos(a) sin(a) ]
[ 0 -sin(a) cos(a) ]
это был heading(поворот)
y - [cos(a) 0 -sin(a) ]
[ 0 1 0 ]
[ sin(a) 0 cos(a) ]
это был pitch(наклон)
z - [ cos(a) sin(a) 0 ]
[ -sin(a) cos(a) 0 ]
[ 0 0 1 ]
ну а это - bank(крен)

вот функция вращения вокруг осей координат:
Код:
void Matrix::RotationAroundAxis(Vector3& v, float a)
{
_11 = v.x * v.x * (1 - cos(a)) + cos(a);
_12 = v.x * v.y * (1 - cos(a)) + v.z * sin(a);
_13 = v.x * v.z * (1 - cos(a)) - v.y * sin(a);
_21 = v.x * v.y * (1 - cos(a)) - v.z * sin(a);
_22 = v.y * v.y * (1 - cos(a)) + cos(a);
_23 = v.y * v.z * (1 - cos(a)) + v.x * sin(a);
_31 = v.x * v.z * (1 - cos(a)) + v.y * sin(a);
_32 = v.y * v.z * (1 - cos(a)) - v.x * sin(a);
_33 = v.z * v.z * (1 - cos(a)) + cos(a);
}
а так же мультипликация(перемножение матрицы на вектор):
Код:
void multiplication (Vector4& v, Matrix& m)
{
float x = v.x, y = v.y, z = v.z, w = v.w;
v.x = x * m._11 + y * m._21 + z * m._31 + w * m._41;
v.y = x * m._12 + y * m._22 + z * m._32 + w * m._42;
v.z = x * m._13 + y * m._23 + z * m._33 + w * m._43;
v.w = x * m._14 + y * m._24 + z * m._34 + w * m._44;
}
Кароче смотрите все сдесь:
http://shatalov.su/directx_primer/transformation.php
http://shatalov.su/directx_primer/camera_1.php
п.с. multiplication - моя версия правильная. в уроке на сайте в ней ошибка...
п.с.с. может нам нужно только разделить вс компоненты на четвёртую и всё?
попробуйте!
Re: О кватернионах -
DANGER1979 - 25.08.2010
Stepashka решил вставить сюда для наглядности
Код:
w x y z Описание
1 0 0 0 Идентичный кватернион, нет вращения
0 1 0 0 Поворот на 180° вокруг оси X
0 0 1 0 Поворот на 180° вокруг оси Y
0 0 0 1 Поворот на 180° вокруг оси Z
sqrt(0.5) sqrt(0.5) 0 0 Поворот на 90° вокруг оси X
sqrt(0.5) 0 sqrt(0.5) 0 Поворот на 90° вокруг оси Y
sqrt(0.5) 0 0 sqrt(0.5) Поворот на 90° вокруг оси Z
sqrt(0.5) -sqrt(0.5) 0 0 Поворот на -90° вокруг оси X
sqrt(0.5) 0 -sqrt(0.5) 0 Поворот на -90° вокруг оси Y
sqrt(0.5) 0 0 -sqrt(0.5) Поворот на -90° вокруг оси Z
Это может пригодиться
Как кватернионы конвертируются в углы Эйлера?
sqw = q1.w*q1.w = 0.5
sqx = q1.x*q1.x = 0.5
sqy = q1.y*q1.y = 0
sqz = q1.z*q1.z =0
heading = atan2(2.0 * (q1.x*q1.y + q1.z*q1.w),(sqx - sqy - sqz + sqw)) = atan2(0,2) = 0
bank = atan2(2.0 * (q1.y*q1.z + q1.x*q1.w),(-sqx - sqy + sqz + sqw)) = atan2(0.5,0) = 90 degrees
attitude = asin(-2.0 * (q1.x*q1.z - q1.y*q1.w)/sqx + sqy + sqz + sqw) = asin(0/2) = 0
heading = atan2(2*qy*qw-2*qx*qz , 1 - 2*qy2 - 2*qz2)
attitude = asin(2*qx*qy + 2*qz*qw)
bank = atan2(2*qx*qw-2*qy*qz , 1 - 2*qx2 - 2*qz2)
Как углы Эйлера конвертируются в кватернионы?
w = c1 c2 c3 - s1 s2 s3
x = s1 s2 c3 + c1 c2 s3
y = s1 c2 c3 + c1 s2 s3
z = c1 s2 c3 - s1 c2 s3
where:
c1 = cos(heading / 2)
c2 = cos(attitude / 2) if attitude = 90° then c2 = cos(45°) = 0.7071 if attitude = -90° then c2 = cos(-45°) = 0.7071
c3 = cos(bank / 2)
s1 = sin(heading / 2)
s2 = sin(attitude / 2) if attitude = 90° then s2 = cos(45°) = 0.7071 if attitude = -90° then s2 = sin(-45°) = -0.7071
s3 = sin(bank / 2)
w = cos(rZ/2) * cos(rY/2) * cos(rX/2) + sin(rZ/2) * sin(rY/2) * sin(rX/2)
x = cos(rZ/2) * cos(rY/2) * sin(rX/2) + sin(rZ/2) * sin(rY/2) * cos(rX/2)
y = cos(rZ/2) * sin(rY/2) * cos(rX/2) + sin(rZ/2) * cos(rY/2) * sin(rX/2)
z = sin(rZ/2) * cos(rY/2) * cos(rX/2) + cos(rZ/2) * sin(rY/2) * sin(rX/2)
Что такое Yaw(Heading) - рысканье(курс), Pitch(Attitude) - тангаж (килевая качка), Roll(Bank) - крен (бортовая качка) ?
Рысканье, тангаж и крен - авиационные термины, обозначающие вращения в Декартовой системе координат (по Эйлеровым углам), относительно локальной системы координат самолёта.
Вообразите, что вы видите впереди и ниже себя самолёт, горизонтально летящий на север.
Ось Z направлена снизу прямо вверх. Рысканье - вращение вокруг оси Z.
Ось X идёт от конца левого крыла к концу правого. Тангаж - это вращение вокруг оси X.
Ось Y проходит от хвоста к носу самолёта. Крен - вращение вокруг оси Y.
Код HTML:
airplane telescope symbol angular velocity
applied first heading azimuth theta yaw
applied second attitude elevation phi pitch
applied last bank tilt psi roll
http://www.rossprogrammproduct.com/t...%20FAQ.htm#Q51
http://www.euclideanspace.com/maths/...ples/index.htm
http://www.euclideanspace.com/maths/...uler/index.htm
Re: О кватернионах -
DANGER1979 - 25.08.2010
В итоге
pawn Код:
stock ConvertNonNormaQuatToEuler(Float: qw, Float: qx, Float:qy, Float:qz,
&Float:heading, &Float:attitude, &Float:bank)
{
new Float: sqw = qw*qw;
new Float: sqx = qx*qx;
new Float: sqy = qy*qy;
new Float: sqz = qz*qz;
new Float: unit = sqx + sqy + sqz + sqw; // if normalised is one, otherwise is correction factor
//если normalised, - один, в противном случае - показатель коррекции
new Float: test = qx*qy + qz*qw;
if (test > 0.499*unit)
{ // singularity at north pole - особенность на северном полюсе
heading = 2*atan2(qx,qw);
attitude = 3.141592653/2;
bank = 0;
return 1;
}
if (test < -0.499*unit)
{ // singularity at south pole - особенность на южном полюсе
heading = -2*atan2(qx,qw);
attitude = -3.141592653/2;
bank = 0;
return 1;
}
heading = atan2(2*qy*qw - 2*qx*qz, sqx - sqy - sqz + sqw);
attitude = asin(2*test/unit);
bank = atan2(2*qx*qw - 2*qy*qz, -sqx + sqy - sqz + sqw);
return 1;
}
Продолжение следует
Re: О кватернионах -
DANGER1979 - 25.08.2010
Затем доводим до ума ф-ию
pawn Код:
stock GetVehicleRotation(vehicleid,&Float:heading, &Float:attitude, &Float:bank)
{
new Float:quat_w,Float:quat_x,Float:quat_y,Float:quat_z, Float:angle;
GetVehicleRotationQuat(vehicleid,quat_w,quat_x,quat_y,quat_z);
ConvertNonNormaQuatToEuler(quat_w,quat_x,quat_z,quat_y, heading, attitude, bank);
bank = -1*bank;
//ИНФОРМИРОВАНИЕ
new string[MAX_STRING];
GetVehicleZAngle(vehicleid, angle);
format(string, sizeof(string), "GetVehicleRotation(quat_w:%.2f, quat_x:%.2f, quat_y:%.2f, quat_z:%.2f, рыскание:%.1f, крен:%.1f, тангаж:%.1f(angle:%.1f))", quat_w,quat_x,quat_z,quat_y, heading, attitude, bank, angle);
SendClientMessageToAll(COLOR_YELLOW, string);
return 1;
}
Внимание1: кай наверно попутал местами quat_z и quat_y. Исправил.
Внимание2: тангаж домножил на -1, т.к. почему то положительный тангаж определялся как отрицательный.
Итак:
Рысканье (heading) - вращение вокруг оси Z.
Тангаж (тангаж) - это вращение вокруг оси X.
Крен (attitude) - вращение вокруг оси Y.
Теперь осталось правильно определить координаты вдоль оси машины на нужном растоянии для правильной установки шипов.
Пример использования:
pawn Код:
new Float:x,Float:y,Float:z, Float:rotX,Float:rotY,Float:rotZ, Float:angle;
GetVehiclePos(GetPlayerVehicleID(playerid), x, y, z);
GetVehicleZAngle(GetPlayerVehicleID(playerid), angle);
GetVehicleRotation(GetPlayerVehicleID(playerid), rotZ, rotX, rotY);
CreateObject(2899, x, y, z-0.65, rotX, rotY, angle-90.0, 200.0);
Re: О кватернионах -
DANGER1979 - 25.08.2010
Как доказательство, что всё отлично пашет вот скрин
Stepashka
Код:
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);
x = 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));
y = 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));
z = asin(-2*((quat_x*quat_z)+(quat_w*quat_y)));
return 1;
}
полная лажа. Кто-то пошутил.
P.S если кому не ясно я всё расписал, то обращайтесь.
Re: О кватернионах -
Stepashka - 26.08.2010
Quote:
Originally Posted by DANGER1979
Stepashka
Код:
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);
x = 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));
y = 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));
z = asin(-2*((quat_x*quat_z)+(quat_w*quat_y)));
return 1;
}
полная лажа. Кто-то пошутил.
|
топикстартер той темы