NやUpベクトルからなる回転行列からオイラー角を求める方法。
Houdiniのカメラにオイラー角の入力ボックスしか見当たらなかったので計算することに。
回転行列を掛け合わせた行列をつくる
XYZ軸すべての回転行列を掛けた結果の行列をつくる。Z回転、X回転、Y回転の順で掛けていきます。この順番をしっかり決めておくことが大事で、順番が変わると結果も変わる。
// Z軸でz(ラジアン)回転させる行列
Rz = {cos(z), sin(z), 0,
-sin(z), cos(z), 0,
0, 0, 1}
この行列にX軸の回転行列を掛ける。
// X軸方向にx(ラジアン)回転させる行列
Rx = {1, 0, 0,
0, cos(x), sin(x),
0, -sin(x), cos(x)}
結果こうなる
RzRx = {cos(z), sin(z)*cos(x), sin(z)*sin(x),
-sin(z), cos(z)*cos(x), cos(z)*sin(x),
0, -sin(x), cos(x)}
さらにY軸方向の回転行列を掛ける。
// Y軸方向にy(ラジアン)回転させる行列
Ry = {cos(y), 0, -sin(y),
0, 1, 0,
sin(y), 0, cos(y)}
結果は以下
RzRxRy = {cos(z)*cos(y)+sin(z)*sin(x)*sin(y), sin(z)*cos(x), -cos(z)sin(y)+sin(z)*sin(x)*cos(y),
-sin(z)*cos(y)+cos(z)*sin(x)*sin(y), cos(z)*cos(x), sin(z)*sin(y)+cos(z)*sin(x)*cos(y),
cos(x)*sin(y), -sin(x), cos(x)*cos(y)}
この式に角度x,y,zを当てはめれば行列(各軸のベクトル)ができる。
ベクトルから行列をつくる
次にベクトルから行列をつくる。Houdiniでは基本的にZ軸は@N、Y軸は@upなので
// @upと@Nの外積からx軸のベクトルをつくる
vector L = cross(@up, @N)
RzRxRy = {L.x, L.y, L.z,
up.x, up.y, up.z,
N.x, N.y, N.z}
となる。このベクトルで構成した行列とZXY回転をした行列が同じ結果になるための角度x, y, zは何かを考える。
L.x = cos(z)*cos(y)+sin(z)*sin(x)*sin(y)
L.y = sin(z)*cos(x)
L.z = -cos(z)sin(y)+sin(z)*sin(x)*cos(y)
up.x = -sin(z)*cos(y)+cos(z)*sin(x)*sin(y)
up.y = cos(z)*cos(x)
up.z = sin(z)*sin(y)+cos(z)*sin(x)*cos(y)
N.x = cos(x)*sin(y)
N.y = -sin(x)
N.z = cos(x)*cos(y)
中身を比較しながら方程式を解く要領で片方の変数を求めていく。
角度x
N.yが-sin(x)に当たるので
N.y = -sin(x)
という等式が成り立つので
x = -asin(N.y)
となる。
角度z
zはL.yをup.yで割ることで求めることができる。
L.y / up.y = sin(z)*cos(x) / cos(z)*cos(x) = sin(z)/cos(z) = tan(z)
z = atan(L.y, up.y)
となる。
角度y
yも同じ要領でNxをNzで割ることで求まる。
Nx / Nz = cos(x)*sin(y) / cos(x)*cos(y) = sin(y) / cos(y) = tan(y)
y = atan(Nx, Nz)
モデルを回転して確認
// 行列を構成する3つの軸ベクトルをつくる
@N = normalize(set(1, 0, 1));
@up = normalize(set(-1, 1, 0));
@left = cross(@up, @N);
@up = cross(@N, @left); // 90度で交わるようにupベクトルを補正する
// オイラー角を計算する
v@rot.x = degrees(-asin(@N.y));
v@rot.y = degrees(atan2(@N.x, @N.z));
v@rot.z = degrees(atan2(v@left.y, @up.y));
printf('@rot:' + sprintf('%g', @rot) + '\n');
//@rot:{-0,45,35.2644}
適当にZ軸ベクトル(1, 0, 1)、Y軸ベクトル(-1, 1, 0)をもとに作った軸ベクトルから計算すると、角度はX軸が0度、Y軸が45度、Z軸が35.26度になりました。
Transform SOPに角度を入力したところ一致した。
Transform OrderはRzRxRyの順にすることを忘れずに。
カメラに角度を割り当てる
同じようにWrangleでv@rotという角度のアトリビュートをつくり
これをカメラのRotateにリンクさせます。カメラの正面の向きがZマイナス方向なので、@Nはカメラに値を渡すときにー1を掛けて反転させておきましょう。
Translateにも座標をリンクさせればカメラが移動してくれます。