とりあえず日記

VIM→秀丸エディタ→VIM→秀丸エディタ→VIM→秀丸エディタ→VIM→秀丸エディタ→VIM→秀丸エディタ→VIM→秀丸エディタ(いまここ🍄)

Euler angle(xyz/zxy/xzy/yxz/yzx/zyx) to quaternion.

オイラーの各軸(X/Y/Z軸)からクォータニオンへ変換する。

void	XToQuaternion(Quaternion& q, float  x){
	q.x = sin(x * 0.5f);
	q.y = 0.0f;
	q.z = 0.0f;
	q.w = cos(x * 0.5f);
};

void	YToQuaternion(Quaternion& q, float  y){
	q.x = 0.0f;
	q.y = sin(y * 0.5f);
	q.z = 0.0f;
	q.w = cos(y * 0.5f);
};

void	ZToQuaternion(Quaternion& q, float  z){
	q.x = 0.0f;
	q.y = 0.0f;
	q.z = sin(z * 0.5f);
	q.w = cos(z * 0.5f);
};

数式は「実例で学ぶゲーム3D数学」を参照。

実例で学ぶゲーム3D数学

実例で学ぶゲーム3D数学

Euler angle(xyz/zxy/xzy/yxz/yzx/zyx) to quaternion.

void	XYZToQuaternion(Quaternion& q, float  x, float  y, float  z){
	float cx = cos(x * 0.5f);
	float cy = cos(y * 0.5f);
	float cz = cos(z * 0.5f);
	float sx = sin(x * 0.5f);
	float sy = sin(y * 0.5f);
	float sz = sin(z * 0.5f);

	q.x=cy*cz*sx-cx*sy*sz;
	q.y=cy*sx*sz+cx*cz*sy;
	q.z=cx*cy*sz-cz*sx*sy;
	q.w=sx*sy*sz+cx*cy*cz;
};


void	ZXYToQuaternion(Quaternion& q, float  x, float  y, float  z){
	float cx = cos(x * 0.5f);
	float cy = cos(y * 0.5f);
	float cz = cos(z * 0.5f);
	float sx = sin(x * 0.5f);
	float sy = sin(y * 0.5f);
	float sz = sin(z * 0.5f);

	q.x=cx*sy*sz+cy*cz*sx;
	q.y=cx*cz*sy-cy*sx*sz;
	q.z=cx*cy*sz-cz*sx*sy;
	q.w=sx*sy*sz+cx*cy*cz;
};


void	XZYToQuaternion(Quaternion& q, float  x, float  y, float  z){
	float cx = cos(x * 0.5f);
	float cy = cos(y * 0.5f);
	float cz = cos(z * 0.5f);
	float sx = sin(x * 0.5f);
	float sy = sin(y * 0.5f);
	float sz = sin(z * 0.5f);

	q.x=cx*sy*sz+cy*cz*sx;
	q.y=cy*sx*sz+cx*cz*sy;
	q.z=cx*cy*sz-cz*sx*sy;
	q.w=cx*cy*cz-sx*sy*sz;
};


void	YXZToQuaternion(Quaternion& q, float  x, float  y, float  z){
	float cx = cos(x * 0.5f);
	float cy = cos(y * 0.5f);
	float cz = cos(z * 0.5f);
	float sx = sin(x * 0.5f);
	float sy = sin(y * 0.5f);
	float sz = sin(z * 0.5f);

	q.x=cy*cz*sx-cx*sy*sz;
	q.y=cy*sx*sz+cx*cz*sy;
	q.z=cx*cy*sz+cz*sx*sy;
	q.w=cx*cy*cz-sx*sy*sz;
};


void	YZXToQuaternion(Quaternion& q, float  x, float  y, float  z){
	float cx = cos(x * 0.5f);
	float cy = cos(y * 0.5f);
	float cz = cos(z * 0.5f);
	float sx = sin(x * 0.5f);
	float sy = sin(y * 0.5f);
	float sz = sin(z * 0.5f);

	q.x=cy*cz*sx-cx*sy*sz;
	q.y=cx*cz*sy-cy*sx*sz;
	q.z=cx*cy*sz+cz*sx*sy;
	q.w=sx*sy*sz+cx*cy*cz;
};


void	ZYXToQuaternion(Quaternion& q, float  x, float  y, float  z){
	float cx = cos(x * 0.5f);
	float cy = cos(y * 0.5f);
	float cz = cos(z * 0.5f);
	float sx = sin(x * 0.5f);
	float sy = sin(y * 0.5f);
	float sz = sin(z * 0.5f);

	q.x=cx*sy*sz+cy*cz*sx;
	q.y=cx*cz*sy-cy*sx*sz;
	q.z=cx*cy*sz+cz*sx*sy;
	q.w=cx*cy*cz-sx*sy*sz;
};

数式の導出

Euler angle(xyz/zxy/xzy/yxz/yzx/zyx)からクォータニオンへ変換する数式は、wxMaximaで導出しています。

qmul(l,r) := [
l[1]*r[4] + l[4]*r[1] + l[2]*r[3] - l[3]*r[2] ,
l[2]*r[4] + l[4]*r[2] + l[3]*r[1] - l[1]*r[3] ,
l[3]*r[4] + l[4]*r[3] + l[1]*r[2] - l[2]*r[1] ,
l[4]*r[4] - l[1]*r[1] - l[2]*r[2] - l[3]*r[3] ];

qx:[sx  ,0      ,0      ,cx];
qy:[0       ,sy ,0      ,cy];
qz:[0       ,0      ,sz ,cz];

printf(false,"==== xyz ====");
xyz:qmul(qmul(qz,qy),qx);

printf(false,"==== zxy ====");
zxy:qmul(qmul(qy,qx),qz);

printf(false,"==== xzy ====");
xzy:qmul(qmul(qy,qz),qx);

printf(false,"==== yxz ====");
yxz:qmul(qmul(qz,qx),qy);

printf(false,"==== yzx ====");
yzx:qmul(qmul(qx,qz),qy);

printf(false,"==== zyx ====");
zyx:qmul(qmul(qx,qy),qz);

リンク

Euler から Quaternion へ変換する数式など。
Maths - Conversion Euler to Quaternion - Martin Baker