クォータニオン(四元数)
3D プログラミングと数学
3D プログラミングの世界では、数学的知識が非常に重要になる場面があります。
その最も代表的な例が[ 行列 ]でしょう。行列を知らずして、座標変換は行なえません。そのほかにも、ベクトルの知識や、内積・外積などの知識も欠かせません。ほんとに、困ったものですね。
さて、今回のテーマはクォータニオン(四元数)です。WebGL に限らず、DirectX などでも登場するクォータニオン。それがいったいどういうもので、使用することによってどう便利になるのか、あまりハッキリとイメージできない人も多いと思います。今回はこのクォータニオンの基本的な部分から、簡単な使い方までを解説します。あまり、本格的な数学の話になってしまってもつまらないだけですので、今回のテキストの最大の目的は理解することよりも使い方を知ることとして進めていきます。
そもそもそれはなんなのか
クォータニオンは四元数とも呼ばれる数学の概念の一つです。3D プログラミングにおいては回転に関わる処理の多くでクォータニオンが使われています。
そもそも、クォータニオンとはなんなのか、その手掛かりを求めて調べてみると大抵わけのわからない解説が出てきます。参考までに wikipedia の四元数の項から引用すると、クォータニオンは次のように説明されています。
3つの虚数単位を持つ超複素数系のひとつ
こんな説明でクォータニオンがなんなのか想像できる人は、そもそも当テキストをご覧になってはいないでしょう。少なくとも私個人はこれを読んでも全く意味がわかりませんでした。
先ほども書いたように、クォータニオンの定義や原理を一から理解することが今回の目的ではありません。あくまでも、クォータニオンとはなんなのか、どのように使うのか、そのあたりに重点を置いて解説していきます。その前提で読み進めていただければと思います。
さて、それではここでちょっと考えてみてください。
三次元空間上に何かしらのモデルを配置しようとするとき、そのモデルの姿勢を表すにはどうすればいいでしょうか。
モデルの座標位置ではありません。[ 姿勢 ]です。
ここで言う姿勢とは、モデルがどのように傾いているか、であるとか、モデルがどのような方角を向いているのか、であるとか、要はモデルに適用されている様々な回転の要素のことです。
回転なら、今までも行列を使って表現してきたじゃないか! と思われるかもしれません。確かに行列は回転を扱うことが可能ですが、移動や拡大縮小なども同時に扱うことができるため、姿勢を表すということだけに絞って考えると、余計な情報がくっついてしまっています。
また、行列による回転では X ・ Y ・ Z の各軸それぞれについて、個別に何度回転しているのかを考える必要がありました。三つの軸による回転を組み合わせることで、確かにあらゆる姿勢を表すことはできます。しかしこれが結構ややこしくて、たとえばローカル座標で(0.0, 1.0, 0.0)の方角を向いているモデルを、(0.42, 0.59, 0.68)の方角へ向かせるために、XYZ の各軸を何度ずつ回転させればいいのかわかるでしょうか。これは普通に考えて人間の思考能力で即座にわかるわけがありません。
このように、姿勢を表すという観点からすると、行列はややわかりにくいわけです。
姿勢を表すためには、最低限の情報として[ どのくらい回転しているのか ]という情報と、[ どの方向を軸にするのか ]という情報が必要になります。逆に言うと、この二つの情報さえあれば、ありとあらゆる回転を表すことが可能です。イメージし難いかもしれませんが、全ての姿勢はこの二つの要素だけで表現できてしまうのです。
そして、この二つの要素をいい感じに表せる概念が、他でもないクォータニオンなんですね。
クォータニオンを用いると、任意の方向を軸とした、任意角の回転を表すことが可能になります。これは即ち、ありとあらゆる全ての姿勢はたった一つのクォータニオンで表現できてしまうということでもあるのです。
ここまで読んでも、まだクォータニオンについてイマイチ理解できない人も多いと思います。実際に、クォータニオンを扱いながらさらに読み解いていきましょう。
クォータニオンを表してみる
クォータニオンは先ほども書いたように[ 任意の方向を軸 ]とした[ 任意角の回転 ]を表すことができます。
ここでまずは、任意の方向を軸とするということだけに絞って考えてみます。
これまでのテキストでも、方向を表すということはやってきましたね。たとえば、ライティングの処理を行なったときには、光源から放たれた光の向きを表すためにライトベクトルを定義しましたね。このことからもわかるように、ある[ 向き ]を表すためにはベクトルが一つあれば十分です。三次元空間上のベクトルはご存知の通り、X ・ Y ・ Z の三つの要素によって表現できますね。
では次に、任意の回転角について考えてみると、これは純粋に角度ですから、度数法で言うところの度数や、ラジアンで表すことが可能ですね。
これを総合すると、クォータニオンを構成する要素は三つの要素を持つベクトルと一つの角度で表現できることになります。そしてこれこそがクォータニオンの正体なのです。
クォータニオンは、一般に次のように表します。
Q = (t; x, y, z)
どうですか。一つの要素と三次元ベクトルしかありませんね。
先ほども書いたように、クォータニオンはベクトルと角度のみで構成されています。上記の式を見ると、それがよくわかりますね。難しい言い方をすると、上記の式にある t は実部と呼ばれます。そして、ベクトルの部分にある三つの要素を虚部と呼びます。しかし、呼び方なんて気にしなくてもいいのです。要は、クォータニオンがたった四つの要素のみで表されるものだということを理解していればそれでいいのです。
実際にプログラミングの中でクォータニオンを使う際には、最低限これだけわかっていればどうにかなります。実部や虚部の意味についてこれ以上踏み込んだ内容を知りたい人は、各自で調べることをオススメします。
クォータニオンを使った計算
さて、それではクォータニオンを使って計算を行なう基本について見てみます。
まず知っておくべきこととして、クォータニオン同士の掛け算は行列がそうであったように掛ける順序によって結果が変わります。これについては大前提として覚えておきましょう。
クォータニオン同士の掛け算は、以下のようにして行ないます。
クォータニオン同士の掛け算
Q = (q; V)
R = (r; W)
QR = (qr - V ・ W; qW + rV + V × W)
一つ目のクォータニオン Q
と、二つ目のクォータニオン R
の掛け算を計算したのが上記の式になります。ここで出てくる[ ・ ]はドット、つまり内積です。[ × ]こちらはクロス、つまり外積ですね。
このクォータニオン同士を掛け合わせる処理は、内部的には足し算と引き算、そして内積と外積だけで行うことができるのですね。これは演算負荷も少なく、比較的高速に動作させることができる処理です。
クォータニオン同士の掛け算が理解できたら、次はクォータニオンで回転を表してみます。これも、ルールさえ覚えてしまえばそれほど難しくはありません。クォータニオンに回転の要素を与えるには次のようにします。
クォータニオンに回転を与える
原点を中心とした軸ベクトル = (x, y, z)
回転する角度 = th
Q = (cos(th / 2); x * sin(th / 2), y * sin(th / 2), z * sin(th / 2))
一瞬、何コレと思ってしまうかもしれませんが、よーく見てみれば非常に単純です。要は、X ・ Y ・ Z の各要素に角度を 2 で割ったサインを掛けているだけです。これだけで、回転が表現できます。落ち着いて考えると非常に簡単ですね。
ここで注意しなければならないのは、軸ベクトルは正規化されている必要があるということです。正規化されていないベクトルを軸に使用しないように気をつけましょう。
こうして作られた回転を表すクォータニオンから、今度は共役四元数と呼ばれるクォータニオンを作ります。名前は大層ですが、怖気づく必要はありません。共役四元数は X ・ Y ・ Z の値を反転させるだけで作れます。
共役四元数
原点を中心とした軸ベクトル = (x, y, z)
回転する角度 = th
Q = (cos(th / 2); x * sin(th / 2), y * sin(th / 2), z * sin(th / 2))
Q の共役四元数 R
R = (cos(th / 2); -x * sin(th / 2), -y * sin(th / 2), -z * sin(th / 2))
これで、回転を表すクォータニオン Q と、その共役四元数である R ができました。この二つのクォータニオンを使うと、三次元空間上にある一点を、任意軸・任意角で回転させることができます。その計算方法は次のようにします。
任意軸・任意角による回転の計算
三次元空間上の座標: P = (0; x, y, z)
P を回転させるための計算は……
R * P * Q = (0; X, Y, Z)
先ほども書いたように、クォータニオン同士の掛け算は、その順序によって結果が変わりますので注意しましょう。上記の式で、大文字のアルファベットで表されている XYZ のそれぞれを参照すれば、任意軸・任意角の回転を行なったあとの座標が得られます。
焦らず落ち着いて考えれば、意外と単純な計算だけでクォータニオンを扱えるということがわかるのではないでしょうか。
まとめ
さて、ここまで四元数(クォータニオン)ついて見てきましたが、まだまだクォータニオンがどうして便利なのかということに関してはピンとこないかもしれません。
今回のテキストでは、クォータニオンとはそもそもなんなのか、そしてクォータニオンを使った計算の基本とはどんなものなのか、そこまでわかっていただければ十分だと思います。
任意軸・任意角の回転を行なう計算方法についても簡単に触れましたが、回転という冗長になりがちな座標計算をクォータニオンは実に簡潔に行うことができます。これを実際にプログラムにどう活かしていくのかはそれぞれの問題ですが、クォータニオンが強力なツールであることには変わりありません。
次回は、実際にクォータニオンを使ってサンプルプログラムを組んでみます。また、クォータニオンを扱うための自作ライブラリについても解説する予定です。サンプルプログラムを通して実際にクォータニオンに触れてみれば、クォータニオンを使うことのメリットもより鮮明に見えてくるでしょう。