てんちょーの技術日誌

自分がつまづいたこととかメモ

【Unity】回転関連について整理してみた"基礎編" C#

先日の土日に一人でハッカソン的な感じで開発してたところ、 オブジェクトを回転させるのに大変苦労しました。 というのもコード的にはそんなに難しく無いのですが、これが思ったように回転してくれない。 なのでどうなっているのか、詳しく実験しながら整理していきたいです。

基礎編ではまずquaternionについての理解を深めるために順を追って説明しますが、 そんなのどうでもいい人はこちら shop-0761.hatenablog.com

実際そこまでわからなくても使えます。(2015/0704)

回転といえば

そう""quaternion""ですね。 Wikipediaによると

数学における四元数(しげんすう、英: quaternion(クォターニオン))は複素数を拡張した数体系である。

とのことで複素数が絡んでくるやつです。複素数については知ってるものとして進みますね。 どうやら四元数というくらいだから4つ引数をとるんですよ。

Quaternionについて

でもなんで4つも引数いるの?と思いました。 だって3次元ならx,y,zの3つで事足りるじゃないかと。

と思って調べていたら次のようなサイトを発見しました。

wgld.org

ここによると

姿勢を表すためには、最低限の情報として[ どのくらい回転しているのか ]という情報と、[ どの方向を軸にするのか ]という情報が必要になります。逆に言うと、この二つの情報さえあれば、ありとあらゆる 回転を表すことが可能です。イメージし難いかもしれませんが、全ての姿勢はこの二つの要素だけで表現できてしまうのです。

そして、この二つの要素をいい感じに表せる概念が、他でもないクォータニオンなんですね。 なんだそうです。

ということは、quaternionは普段捉えている3次元のデータ(x,y,z)のように座標を表すのではなく、回転の基準となる3次元位置ベクトルと回転する角度のデータを持っているって押さえでよさそうです。 位置ベクトルというのは原点と指定した任意の点(x,y,z)を結んでできるベクトルで向きは指定した座標の方向が→の頭の方になります。

これでテラシュールブログさんの

Quaternionは回転情報です。

と端的におっしゃられていたのがわかった気がしました。

どんどん引用させてもらいますと 次にこのようなサイトを発見しました。

その10 クォータニオンを学んでみよう!

そこによると(引用の引用になってるっぽいけど

クォータニオンは、3 成分ベクトルを定義する [x, y, z] 値に第 4 の成分を追加する。クォータニオンは、3D 回転で一般的に使われる行列手法に代わるものである。クォータニオンは、3D 空間内の軸と、その軸を中心とする回転を表す。たとえば、1 つのクォータニオンで軸 (1,1,2) と 1 ラジアンの回転を表すことができる。クォータニオンは重要な情報も伝えるが、その真価は、クォータニオン上で実行できる 2 つの処理、合成と補間で発揮される。

このサイトは少し古めのDirectXについて書かれてますがquaternionについては変わらないと思います。 つまりは単体でも十分だけど合成やら補間することがよいらしいです。 そして三次元の位置ベクトル+ラジアンで構成されるそうです。 (ラジアンも割愛します

たとえば位置ベクトル(1,2,3)を回転軸にπラジアンだけ回転させるという情報を持っているってことですね。

Quaternionのもろもろ

またquaternionは以下のように2通り表せます。

{ \displaystyle
P = (a; x, y, z) = (a;\vec{p}) = a + xi + yj + zk
}

aは回転角、x,y,zは三次元の位置ベクトルを表すもの、その次の多項式はi,j,kがそれぞれx,y,z方向だよという意味付けの虚数ですね。

これらをまとめてベクトル表示にするとすっきりします。 このベクトル表示を使うとquaternionの積は内積外積を用いてスッキリした形で表せます。

{
R * Q = (a;\vec{r}) * (b;\vec{q})
= (ab-\vec{r}\vec{q}; a\vec{q} + b\vec{r} + \vec{r} \times \vec{q})
}

で任意の点P{(0,x,y,z)}をθ回転させるにはquaternionのP,その共役四元数Qを用いて {
 R * P * Q
} を計算すると

{
 (0;\grave{x},\grave{y},\grave{z})
} が得られるのでその点が移動先の点です。共役四元数は共役複素数と同じかんじです。

具体的な成分も細々書くと以下の式になります。(さらっと流すからここで諦めないで…

{
R * P * Q = (cos(\frac{\theta}{2}); \alpha sin(\frac{\theta}{2}), \beta sin(\frac{\theta}{2}), \gamma sin(\frac{\theta}{2})) \
 * (0;x,y,z) \
 * (cos(\frac{\theta}{2}); -\alpha sin(\frac{\theta}{2}), -\beta sin(\frac{\theta}{2}), -\gamma sin(\frac{\theta}{2}))
}

ただし{\alpha ^2 + \beta ^2 + \gamma ^2 = 1}です。(正規化してください

具体例

ここで簡単に例を挙げて考えてみましょう。 設定としては点(1,1,1)をx軸を中心に180度回転させたいとします。

Quaternion[0,1,0,0] * Quaternion[0,1,1,1] * Quaternion[0,-1,0,0] = Quaternion[0,1,-1,-1]

今回はwolfram言語でちゃちゃっと書いたのですがぱっと見でわかるかと思います…よね… 単にさっきの {
 R * P * Q
} を計算してるだけです。その下が答えです。

落ち着いて考えれば(1,-1,-1)に移動するよねって感じで十分です。具体的になんでそのR,Qなのかは上のなっがい式を読み解けば いけると思います。

ここまでくればquaternionの概要がつかめたような気がしています。 次回は実際にUnity上でどうなっているのか検証したいです。