RSS

回転とクォータニオン

  • (2017年12月4日(月) 午後11時19分26秒 更新)

更新履歴

すみません。
まだ記載途中で、図もないです……。

2017/12/3 諸々整理中
2017/12/2 初稿

はじめに

本稿では、ベクトルは太字イタリックで\(\boldsymbol{v}\)のように書きます。
また、成分表示する場合は、縦ベクトル(列ベクトル)で表します。
ですからベクトルを変換する場合、つまり行列をかける場合は以下のように左からかけることになります。
\[
\boldsymbol{v}'=T\boldsymbol{v}
\]
また、x,y,z軸は番号で1,2,3軸と呼ぶことがあります。
例えば、2次元のベクトルは
\[
\boldsymbol{v}=
\left(
\begin{array}{ccc}
v_1\\
v_2\\
\end{array}
\right)
\]
のように書きます。
\(i\)番目の基底は\(\boldsymbol{e}_i\)です。
つまり、上のベクトルは
\[
\boldsymbol{v}=
v_1\boldsymbol{e}_1+
v_2\boldsymbol{e}_2
\]
です。

2次元回転行列

2次元ベクトル
\[
\boldsymbol{v}=
v_1\boldsymbol{e}_1+v_2\boldsymbol{e}_2=
\left(
\begin{array}{ccc}
v_1\\
v_2\\
\end{array}
\right)
\]
の回転を考えます。
このようなベクトルを角度\(\theta\)だけ回転させる変換\(R(\theta)\)を考えます。
ここでは計算しやすいように数ベクトルとして書きましたが、数ベクトルを行列で回転させると考えるよりは、方向と長さを持つ幾何ベクトルが回転している様子を思い浮かべたほうがわかりやすいと思います。
回転変換は行列で表すことができますが、ここではただの数の計算ではなく、実際に幾何学的にベクトルを他のベクトルに変えてしまうような抽象的な「変換」だと考えてください。

また、\(\boldsymbol{v}\)を角度\(\theta\)だけ回転させたベクトルを\(\boldsymbol{v}'\)と書きます。
式にすると
\[
\boldsymbol{v}'=R(\theta)\boldsymbol{v}
\]
です。

(ここに図を書く予定)

さて、回転後のベクトルの成分がどうなるかは、図を描いてみるとよくわかって、
\[
\boldsymbol{v}'
=
\left(
\begin{array}{ccc}
v_1'\\
v_2'\\
\end{array}
\right)
=
\left(
\begin{array}{ccc}
v_1\mathrm{cos}\theta -v_2\mathrm{sin}\theta\\
v_1\mathrm{sin}\theta + v_2\mathrm{cos}\theta\\
\end{array}
\right)
\]
となります。
ここから、回転変換\(R(\theta)\)の行列表示がどうなるかわかります。
\[
R(\theta)=
\left(
\begin{array}{ccc}
\mathrm{cos}\theta & -\mathrm{sin}\theta \\
\mathrm{sin}\theta & \mathrm{cos}\theta \\
\end{array}
\right)
\]
これが2次元の回転行列(rotation matrix)です。

ところで逆回転はどのようになるでしょうか。
逆回転は\(*\)で表しましょう。
つまり、
\(
R(\theta)^*=R(-\theta)
\)
です。
\[
\mathrm{cos}(-\theta)=\mathrm{cos}\theta, \\
\mathrm{sin}(-\theta)=-\mathrm{sin}\theta
\]
であることを思い出して行列表示すると、
\[
R(\theta)^*=R(-\theta)=
\left(
\begin{array}{ccc}
\mathrm{cos}(-\theta) & -\mathrm{sin}(-\theta) \\
\mathrm{sin}(-\theta) & \mathrm{cos}(-\theta) \\
\end{array}
\right)=
\left(
\begin{array}{ccc}
\mathrm{cos}\theta & \mathrm{sin}\theta \\
-\mathrm{sin}\theta & \mathrm{cos}\theta \\
\end{array}
\right)=
R(\theta)^T
\]
\(T\)は転置行列を表します。
つまり、逆回転行列は元の回転行列の転置と等しいということです。

\(R(\theta)\)の行列表示に戻りましょう。
\(\mathrm{cos}\theta\)、\(\mathrm{sin}\theta\)をなんども書くのは面倒なので、もう少し簡単に書きたいところです。
そこで
\[
I=
\left(
\begin{array}{ccc}
1 & 0 \\
0 & 1 \\
\end{array}
\right),\\
J=
\left(
\begin{array}{ccc}
0 & -1 \\
1 & 0 \\
\end{array}
\right)
\]
という記号を導入しましょう。
この記号を使うと、
\[
R(\theta)=
I\mathrm{cos}\theta
+J\mathrm{sin}\theta
\]
とまとめてかけます。
\(I\)は2x2の単位行列ですね。
\(I\)は行列だと考えると
\[
I=
\left(
\begin{array}{ccc}
1 & 0 \\
0 & 1 \\
\end{array}
\right)
\]
という単位行列です。
ですが、ベクトルの変換と考えると、恒等変換(identity transformation)、つまりどのようなベクトルも決して動かさない変換です。
恒等変換は\(I\)をベクトルにかけてもいいのですが、\(1\)をベクトルにかけても同じことです。
ベクトルの長さは1倍しても変わりません。
要するに純粋にベクトルの変換を考える限りは\(I=1\)だと考えても同じことなので、\(I\)を省略して1と書く場合があります。
つまり、上の\(R(\theta)\)は
\[
R(\theta)=
I\mathrm{cos}\theta
+J\mathrm{sin}\theta=
\mathrm{cos}\theta
+J\mathrm{sin}\theta
\]
のように\(I\)を省略して書くこともできるわけです。
この式はスカラーと行列をかけているように見えますが、単位行列=恒等変換の\(I\)が隠れていることに注意してください。

2次元の無限小回転

本題に入る前に、円弧の長さを考えます。\(\boldsymbol{v}\)を\(\theta\)だけ回転させたものを\(\boldsymbol{v}'\)とします。
この時、円弧の長さ\(a\)はどれだけになるでしょうか。
角度をラジアンで考えると、半径\(r\)、角度\(\theta\)の円弧の長さは
\[
a=r\theta
\]
です。これがラジアンの定義でした。
(半径が1の円弧を考えた時、円弧の長さをそのまま角度を表すために使ったものがラジアンです。
 つまり、半径が1であれば、角度がラジアン単位で\(\theta\)の円弧の長さは\(\theta\)になります。
 円弧の長さは角度が等しければ半径に比例するので、半径が\(r\)、角度が\(\theta\)であれば、円弧の長さは\(r\theta\)です)

\(\boldsymbol{v}\)を回転させる話をしていたので、今の場合は
\[
r=|\boldsymbol{v}|
\]
です。
したがって、円弧の長さは
\[
a=|\boldsymbol{v}|\theta
\]
となります。

ここまでは有限の角度\(\theta\)だけの回転を考えていました。
ここからは一度、無限小の角度\(d\theta\)だけの回転を考えましょう。
回転角度が無限小ということは、細かな角度は考えなくて構いません。
無限小の世界は曲線をどこまでも無限に拡大した世界。つまり、曲線が直線になった世界です。
無限小の角度の円弧はただの直線なのです。
ですので、回転元のベクトル\(\boldsymbol{v}\)の先端側を\(\boldsymbol{v}\)に垂直に、しかもまっすぐ動かすだけで問題ありません。

(ここに図を追加予定)

動かす距離は円弧の場合と同じで、\(|\boldsymbol{v}|d\theta\)です。
回転後のベクトル\(\boldsymbol{v}'\)は\(\boldsymbol{v}\)に垂直な単位ベクトルを\(\boldsymbol{e}_\perp\)と書くと
\[
\boldsymbol{v}'=\boldsymbol{v}+\boldsymbol{e}_\perp|\boldsymbol{v}|d\theta
\]
となります。
ところで、回転行列を使うと、
\[
\boldsymbol{e}_\perp|\boldsymbol{v}|=R(90^\circ)\boldsymbol{v}
\]
のはずです。
ここで、
\[
R(90^\circ)
=I\mathrm{cos}90^\circ
+J\mathrm{sin}90^\circ
=J
\]
なので、結局、
\[
\boldsymbol{v}'=\boldsymbol{v}+Jd\theta
=\boldsymbol{v}+d\theta J
\]
となります。
ただし、\(d\theta\)はただのスカラーなので\(J\)とは順番を変えても同じであるため、最後の=で順番を入れ替えました。
以下でも、スカラーと行列は適宜順番を入れ替えます。

一つ注目して欲しいのは、\(+d\theta J\)というところです。
今まで、ベクトルを回転させる場合には\(R(\theta)\)を掛け算していました。
しかしここでは足し算になっています。
無限小回転の世界では掛け算ではなく、足し算で回転を行うようです。

さて、ここで少し考え方を変えます。
今までは\(\boldsymbol{v}\)や\(\boldsymbol{v}'\)はただのベクトルと考えていました。
一方、長さを固定すると、x軸からの角度\(\theta\)が決まると、\(\boldsymbol{v}\)が決まります。
つまり、\(\boldsymbol{v}\)はx軸からの角度\(\theta\)の関数と考えることができるのです。
そこでここでは
\[
\boldsymbol{v}=\boldsymbol{v}(\theta)
\]
と書きましょう。
\(\boldsymbol{v}'\)は\(\boldsymbol{v}(\theta)\)を余計に\(d\theta\)だけ回転させたベクトルなので、
\[
\boldsymbol{v}'=\boldsymbol{v}(\theta+d\theta)
\]
です。
今までの内容をまとめると、
\[
\boldsymbol{v}(\theta+d\theta)
=\boldsymbol{v}(\theta)+d\theta J\boldsymbol{v}(\theta)
\]
となります。

無限小の回転前後のベクトルの差を\(d\boldsymbol{v}\)と書きましょう。
つまり、
\[
d\boldsymbol{v}=\boldsymbol{v}(\theta+d\theta)-\boldsymbol{v}(\theta)
\]
です。
すると、先ほどの式は
\[
d\boldsymbol{v}
=d\theta J\boldsymbol{v}(\theta)
\]
となり、両辺を\(d\theta\)で割ると、
\[
\frac{d\boldsymbol{v}}{d\theta}
=J\boldsymbol{v}(\theta)
\]
という微分方程式が得られます。
これを解いてみましょう。

微分方程式の解き方(工事中)

すみません。工事中です。

2次元回転の生成子

\[
\frac{d\boldsymbol{v}}{d\theta}
=J\boldsymbol{v}(\theta)
\]
という微分方程式を解くと
\[
\boldsymbol{v}(\theta+\Delta\theta)=e^{J\Delta\theta}\boldsymbol{v}(\theta)
\]
となります。
したがって、
\[
R(\Delta\theta) = e^{J\Delta\theta}
\]
と書けることがわかりました。
\(e^x\)は一般的には指数関数(exponential function)と呼びますが、\(x\)というスカラーではなく、\(J\)という変換、あるいは行列が肩に乗っているため、指数写像(exponential map)と呼ぶこともあります。

\(J\)は\(e\)の肩に乗せることで任意角度の回転を作ることができる変換であることがわかりました。
そのため、回転の生成子(generator)と呼ばれます。
ここで出てきた\(J\)の性質を調べましょう。
\(J\)を任意のベクトル\(\boldsymbol{u}\)にかけると、そのベクトルは\(90^\circ\)回転します。
ということは、\(J\)を2回かけると、\(180^\circ\)回転することになります。
2次元のベクトルを\(180^\circ\)回転させると、ベクトルは元の逆を向きます。
つまり、\(J\)をベクトル\(\boldsymbol{u}\)に2回かけるのは、\(\boldsymbol{u}\)に逆を向かせることと同じ意味を持つわけです。
式にすると、
\[
JJ\boldsymbol{u}=-\boldsymbol{u}
\]
\(\boldsymbol{u}\)はどのようなベクトルでも同じなので、\(\boldsymbol{u}\)をいちいち書く必要はなくて、
\[
JJ=-1
\]
と書いてしまっても誤解はありません。
行列として書くならば、\(1\)ではなく単位行列\(I\)を使って
\[
JJ=-I
\]
としたほうがわかりやすいかもしれません。
この関係を繰り返し適用すると、\(JJ=J^2\)、\(JJJ=J^3\)...なども以下のように計算できるようになります。
\begin{eqnarray}
J^2&=&JJ=-I,\\
J^3&=&J^2J=-IJ=-J,\\
J^4&=&J^2J^2=(-I)(-I)=I
\end{eqnarray}
また、\(J\)は\(R(90^\theta)\)のことでしたので、\(J\)の逆回転\(J^*\)も考えられて、
\[
J^*=R(90^\circ)^*
=R(-90^\circ)=
=I\mathrm{cos}(-90^\circ)
+J\mathrm{sin}(-90^\circ)
=-J
\]
となります。

ところで、\(J\)を行列で書くと
\[
J = \left(
\begin{array}{ccc}
0 & 1 \\
-1 & 0 \\
\end{array}
\right)
\]
でした、\(e^x\)のテイラー展開から
\[
R(\theta) = e^{J\theta}
=I\mathrm{cos}\theta+J\mathrm{sin}\theta
=\left(
\begin{array}{ccc}
\mathrm{cos}\theta & \mathrm{sin}\theta \\
-\mathrm{sin}\theta &\mathrm{cos}\theta \\
\end{array}
\right)
\]
これは回転行列ですね。
もともと\(R(\theta)\)に\(\theta=90^\circ\)を代入することで\(J\)を求めたのでした。
ここで私たちは微分方程式を解くことで逆に\(J\)から\(R(\theta)\)を求めたのです。

複素数と回転

さて、ここで\(J\)と書いているものですが、\(J\)の代わりに\(i\)という文字で表すことも多いです。
このように書いた場合、この\(i\)は虚数単位(imaginary unit)と呼ばれます。

\(R(\theta)\)のように、恒等変換\(1\)と虚数単位\(i\)を使って、
\[
aI+bJ=a+bi
\]
のように書けるモノを複素数(complex number)と呼びます。
また、上の複素数における\(a\)を実部(real part)、\(bi\)を虚部(imaginary part)と呼びます。

虚数単位は一般的には\(i=\sqrt{-1}\)のように定義されることが多いですが、これでは「本当にそんなものがあるのか、計算の都合上導入しただけの虚ろなものなのではないか」と思ってしまいがちです。
しかし、こうやってみると虚数単位とは\(90^\circ\)回転、あるいは2次元回転の生成子のことであり、なにも不思議なものではないことがわかるかと思います。

今私たちはクォータニオンについて学ぼうとしているので、\(i\)の記号はクォータニオンのために残しておいて、以降では虚数単位、つまり2次元回転の生成子は\(J\)で統一しようと思います。

ここまでの議論で出てきた登場人物を整理しましょう。
2次元ベクトルを扱っているので、基底が2つ\(\boldsymbol{e}_1,\boldsymbol{e}_2\)に、好きな回転変換を作るために、恒等変換\(I=1\)と生成子\(J\)が必要です。

もう少し登場人物を減らせないでしょうか。
一つ面白いことをしてみましょう。
ベクトルを行列で表すのです。
ベクトル\(\boldsymbol{v}\)は普通は2つの成分が並んだもの
\[
\boldsymbol{v}=
\left(
\begin{array}{ccc}
v_1 \\
v_2
\end{array}
\right)=
v_1\boldsymbol{e}_1+v_2\boldsymbol{e}_2
\]
として表します。
しかし、\(\boldsymbol{v}\)がどんなベクトルか表すにはもう一つよく使われる方法があります。
「\(\boldsymbol{e}_1\)にどのような変換をかければ\(\boldsymbol{v}\)になるか」で表す方法です。
\(\boldsymbol{v}\)を変形すると
\[
\boldsymbol{v}=
v_1\boldsymbol{e}_1+v_2\boldsymbol{e}_2=
v_1I\boldsymbol{e}_1+v_2J\boldsymbol{e}_1=
(v_1I+v_2J)\boldsymbol{e}_1
\]
のようになります。
ここで
\[
C(\boldsymbol{v})=v_1I+v_2J
\]
と定義すると、
\[
\boldsymbol{v}=C(\boldsymbol{v})\boldsymbol{e}_1
\]
のように簡単になります。
この\(C(\boldsymbol{v})\)は\(\boldsymbol{v}\)がどのようなベクトルであるかを表しているといえます。
となると、もう\(\boldsymbol{e}_1\)はいりません。\(C(\boldsymbol{v})\)だけでものを考えてもいいわけです。

\(\boldsymbol{v}\)と
\(C(\boldsymbol{v})\)を比べてみましょう。
\[
\boldsymbol{v}=v_1\boldsymbol{e}_1+v_2\boldsymbol{e}_2=
v_1
\left(
\begin{array}{ccc}
1 \\
0 \\
\end{array}
\right)+
v_2
\left(
\begin{array}{ccc}
0 \\
1 \\
\end{array}
\right), \\
C(\boldsymbol{v})=v_1I+v_2J=
v_1
\left(
\begin{array}{ccc}
1 & 0 \\
0 & 1 \\
\end{array}
\right)+
v_2
\left(
\begin{array}{ccc}
0 & -1 \\
1 & 0 \\
\end{array}
\right)
\]
とても似ていますね。
これは言ってみれば、行列がベクトルの基底になっているようなものです。
\(C(\boldsymbol{v})\)はベクトルであり、なおかつ行列。そのような不思議なものになりました。
ともかく、これで登場人物は減りました。
回転変換も回転するベクトルも、\(I\)と\(J\)の組み合わせ、つまり複素数で表せるようになったのです。

これで、2次元ベクトルの回転は全て複素数だけで考えることができるようになりました。
言い方を変えれば全てが行列になったのです。
ベクトルと行列があった時は、ベクトルに左から回転行列をかけることで、ベクトルを回転させることができました。
当たり前です。
私たちは列ベクトルで考えているので、行列は左からしかかけることができません。
しかし、ベクトルを行列で表すと、行列は左右どちらからでもかけることができてしまいます。
今まで通り、左からかけるでいいのでしょうか?
試してみましょう。
\begin{eqnarray}
R(\theta)\boldsymbol{v}
&=&\left(
\begin{array}{ccc}
\mathrm{cos}\theta & -\mathrm{sin}\theta \\
\mathrm{sin}\theta & \mathrm{cos}\theta \\
\end{array}
\right)
\left(
\begin{array}{ccc}
v_1 \\
v_2 \\
\end{array}
\right)\\
&=&\left(
\begin{array}{ccc}
v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta \\
v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta \\
\end{array}
\right)\\
&=&(v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta)\boldsymbol{e}_1+
(v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta)\boldsymbol{e}_2
\end{eqnarray}
これがベクトル版です。
行列版はまず左からかけてみましょう。
\begin{eqnarray}
R(\theta)C(\boldsymbol{v})
&=&
\left(
\begin{array}{ccc}
\mathrm{cos}\theta & -\mathrm{sin}\theta \\
\mathrm{sin}\theta & \mathrm{cos}\theta \\
\end{array}
\right)
\left(
\begin{array}{ccc}
v_1 & -v_2 \\
v_2 & v_1 \\
\end{array}
\right)\\
&=&
\left(
\begin{array}{ccc}
v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta &
-v_2\mathrm{cos}\theta-v_1\mathrm{sin}\theta \\
v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta &
-v_2\mathrm{sin}\theta+v_1\mathrm{cos}\theta \\
\end{array}
\right)\\
&=&
(v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta) 1+
(v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta) J\\
&=&
(v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta) C(\boldsymbol{e}_1)+
(v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta) C(\boldsymbol{e}_2)
\end{eqnarray}
大丈夫ですね。ベクトルを\(C()\)で行列化している以外は全く同じ式になりました。
ちゃんと回転変換できていそうです。
ちょっと行列は書くのが面倒ですね。
\(I,J\)を使えば少し楽になるかも。
上の式を書き直してみましょう。
\begin{eqnarray}
R(\theta)C(\boldsymbol{v})
&=&
(I\mathrm{cos}\theta +J\mathrm{sin}\theta)
(Iv_1 +Jv_2)\\
&=&
Iv_1\mathrm{cos}\theta+Iv_2J\mathrm{cos}\theta+
JIv_1\mathrm{sin}\theta+J^2v_2\mathrm{sin}\theta\\
&=&
(v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta) I+
(v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta) J\\
&=&
(v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta) C(\boldsymbol{e}_1)+
(v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta) C(\boldsymbol{e}_2)
\end{eqnarray}
ちょっと楽になりました。
以下、基本的に\(I,J\)を使った形を使い、またわかりづらくない場合は1を省略して書きたいと思います。
なんだか式が怪しいな、と思ったら行列で計算し直しましょう。

では、逆に右からかけてみます。
\begin{eqnarray}
C(\boldsymbol{v})R(\theta)
&=&
(v_1 +Jv_2)
(\mathrm{cos}\theta +J\mathrm{sin}\theta)\\
&=&
v_1\mathrm{cos}\theta+v_1J\mathrm{sin}\theta+Jv_2\mathrm{cos}\theta+J^2v_2\mathrm{sin}\theta\\
&=&
(v_1\mathrm{cos}\theta-v_2\mathrm{sin}\theta) 1+
(v_1\mathrm{sin}\theta+v_2\mathrm{cos}\theta) J\\
&=&
R(\theta)C(\boldsymbol{v})
\end{eqnarray}
なるほど。
右からかけても左からかけても同じ結果になるようです。
よく考えれば当たり前です。行列は右からかけるか左からかけるかで結果が変わる場合がありますが、今扱っている行列は\(I,J\)の2種類だけです。
これらは
\[
IJ=J=JI
\]
のように、かける方向によらず、掛け算の結果は等しいものですので、当たり前でしたね。

無限小の回転を表す\(J\)と有限の回転を表す\(R(\theta)\)を考えてきました。
有限の回転は掛け算で、無限小の回転は(無限小の範囲内だけですが)足し算で合わせることができます。つまり、無限小と有限の回転では少し性質が違うみたいですね。
でも、無限小の回転は積分すれば有限の回転が得られます。

ここで出てきた2x2行列で表せる有限の回転の世界を\(\mathrm{SO}(2)\)と呼びます。
それに対して、無限小の回転の世界は\(\mathrm{so}(2)\)と呼びます。
有限の回転は\(\mathrm{SO}(2)\)の世界の話。
無限小の回転は\(\mathrm{so}(2)\)の世界の話。
大文字と小文字の違いです。
(\(\mathrm{so}(2)\)はドイツ文字で\(\mathfrak{so}(2)\)と書く場合もあります)

有限の回転\(\mathrm{SO}(2)\)に関する数学をリー群(Lie group)と呼びます。
それに対して、無限小の回転\(\mathrm{so}(2)\)に関する数学をリー代数(Lie algebra)あるいは、リー環(Lie ring)と呼びます。
(厳密にはリー代数とリー環は別のものですが詳細には踏み込みません)
リーさんが色々と研究をしたためです。
リー群とリー代数は指数写像で結ばれます。

リー代数は無限小でしか厳密には成り立ちませんが、無限小ではなくても小さい回転角であれば近似的に成り立ちます。
また、リー群では掛け算になる計算が足し算で済むので処理負荷的に有利です。
ですから、リアルタイムCGやゲームの世界では小さい回転をリー代数で計算し、あとでexponential mapでリー群にすることが実際行われています。

CGでの応用に興味がある方は、「exponential map」で、数学に興味がある方は「リー群」、「リー代数」などで検索してみると良いでしょう。

このページのトップへ