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

Для чего их можно использовать?

Я как понял если их перевести с помощью этого конвертера то можно узнать поворот тачки в пространстве те если она перевернута, лежит боком и тп. Я правильно думаю?
Reply
#2

а зачем они вообще нужны??
сделали бы сразу поворот машины да и всё

п.с. да, и что это такое?
Reply
#3

Да, получишь угол поворота тачки по всем осям.
Reply
#4

2 Вопрос. Нахрена мне их получать если я их задать не могу ?
Reply
#5

Я уже писал для чего бы я использовал.
Во-первых: для правильной установки шипов на дороге, т.е. для передачи этих углов зависимым объектам.
Reply
#6

Quote:
Originally Posted by Romanius
View Post
2 Вопрос. Нахрена мне их получать если я их задать не могу ?
кстати да куй забыл про такую ф-ию
но он сделал ускорение:https://sampwiki.blast.hk/wiki/SetVehicleAngularVelocity
Reply
#7

Кватернионы очень удобны для задания поворота объекта в пространстве и по этой причине очень часто используются в компьютерных играх
Reply
#8

ыы, решил посмотреть в википедии, что это такое...
а оказывается, это ж самые простые... 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;
}
Reply
#9

алекс было бы лучше еслиб ты еще классы (Vector4, Matrix) или то у тя там кинул
Reply
#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
#11

Пашет, но углы неверно определяет =(

Короче косяк, кватернионы это не углы, это само вращение по осям, грубо говоря действие в цифрах
Reply
#12

Нашел вот что, смотрите вложение
Reply
#13

хехе
ну вобщем смотрите, чтобы определить координаты, нужно знать матрицу
мы её не знаем... и + нам нужно из матрицы как то вытрясти углы поворота
вот вращение вокруг осей:
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 - моя версия правильная. в уроке на сайте в ней ошибка...
п.с.с. может нам нужно только разделить вс компоненты на четвёртую и всё?
попробуйте!
Reply
#14

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
Reply
#15

В итоге
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;
}
Продолжение следует
Reply
#16

Затем доводим до ума ф-ию

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);
Reply
#17

Как доказательство, что всё отлично пашет вот скрин


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 если кому не ясно я всё расписал, то обращайтесь.
Reply
#18

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; 
}
полная лажа. Кто-то пошутил.
топикстартер той темы
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)