読者です 読者をやめる 読者になる 読者になる

リクルート住まいカンパニー Tech Blog

ITのちからで暮らしをよくしたい、エンジニア・デザイナーが発信するTech情報メディア

three.jsを利用した「回転」について

f:id:recruit-sumai:20170309105431p:plain

こんにちは、スマートデバイス戦略開発グループの katayama です。

普段はUX Design / UI Design 中心ですが、VRのプログラムに加えて数学的な話をすることになるとは思っていなかったです。笑

さて、「three.jsを利用したVR体験の実現 ② カメラを回転とCardboard対応」で、カメラの回転を扱いましたが (ライブラリをつかって)、今回はその回転について詳しく調べてみました。

回転には、「オイラー (Euler) 角」を使ったものと、「クォータニオン (Quaternion)」を使ったものの2つがあるらしいです。この2つの回転について調べた範囲でまとめさせていただきます。

まずはクォータニオンでの回転の考え方から始めましょう。 細かい数学のロジックに興味の無い方は、途中読み飛ばしてしまって構いません。

 

 

回転とは?

2次元の回転を複素数平面で考えてみる

以下の様に点P (√3, 1) を、90°回転させたあとの点Qの座標を計算してみましょう。 結果は、Q (-1, √3) になるはずですよね。これは、回転行列などでも計算できますが、今回は複素数平面での回転で考えます。 f:id:recruit-sumai:20170322191352p:plain  

まず、回転させる 点P(√3, 1) を複素数 「z=x+yi」という形式で表します。 (※このように、複素数を、実部のxと虚数のyを座標として表したものを複素数平面と呼びます。)

z(P) = √3 + i

また、この複素数は、極形式と呼ばれる 「z=r(cosθ+isinθ)」という形で表現することも可能です。

z(P) = 2(cos30° + isin30°)

この点を、φ だけ回転する場合 z = (cosφ + isinφ) をかければOKです (r=1で正規化した極形式) やってみましょう。今回は90°の回転なので、φ = 90° = π/2 ですね。

z(Q) = (√3 + i) × (cos90° + isin90°)
= (√3 + i) * i
= -1 +√3i      (※ iは複素数なので、i*i = -1)

つまり、この値を複素数平面で考えると Q(-1,√3) になっていることがわかります。 2Dでは、複素数平面をつかってこのように回転します。

 

3次元の回転の場合は? (これがクォータニオンの考え方)

それでは、3次元の物体を回転するにはどうしたらいいでしょうか? それが、クォータニオン (四元数) と呼ばれるもので実現可能です。

一般的にクォータニオンは、以下の様に表すことができます

Quat = (t; <strong>v</strong>) = (t; x, y, z) = t + xi + yj + zk
(ただし,ii=jj=kk=−1, ij=k,jk=i,ki=j, ji=−k,kj=−i,ik=−j)

(ちなみに、Quatの共役は 「 Quat = t - xi - yj - zk 」 で表せられる)

 

3Dのクォータニオンによる回転は、「回転軸」と、「回転軸に対する回転角」で考えます。 以下の図は、回転軸 v に対して、点P (ベクトルP) をθだけ回転させるというもののイメージ図となります。 f:id:recruit-sumai:20170322191415p:plain  

この回転に関するクォータニオンは、以下の様になります。

q = cos(θ/2) + (xi + yj + zk) sin(θ/2);
ここでいう、x,y,z は、回転軸のベクトルのx,y,z 軸への方向で、正規化されたものです。

また、3次元の座標P(Px, Py, Pz)をクォータニオンは

p = (0; Px, Py, Pz) = Px * i + Py * j + Pz * k  で表せます

 

この時、3次元座標pの任意軸v 回りの回転 q は、

p*(回転後のP) = qpq

で表現できます。

これで回転後の点が求められる。というのが、クォータニオンによる3次元の物体回転です。

 

オイラー角とクォータニオンによる回転の違い

さて、長々とクォータニオンの話をしましたが、ここでやっと、Three.js での回転について話を進めていきます。 まず、冒頭でも説明したように、回転には「オイラー (Euler) 角」を使ったものと、「クォータニオン (Quaternion)」を使ったものの2つがあります。

 

オイラー角は、x軸、y軸、z軸それぞれに何度ずつという3つの情報で回転を表現するものになります。 このオイラー角の回転は実は厄介で、「どの軸の順番で回転するかで結果が変わってくる」という性質があります。 また、「ジンバルロック」と呼ばれる、回転軸が重なってしまうことによって特定の向きにしかオブジェクトを回せなくなる現象も発生する可能性があります。

f:id:recruit-sumai:20170322191435g:plain

(画像 : wikipedia 「ジンバル」 より)

 

一方。クオータニオンによる回転は、「軸となる任意のベクトルに対する回転」で表現でき、 回転の順番や、ジンバルロックを気にする必要がなくなるという利点があります。

クォータニオンによる回転をThree.js でやってみる

最後に、このクォータニオンによる回転をやってみましょう。 以下のようにすることで、上記の面倒な計算をやってくれます。

var quat = new THREE.Quaternion();

// ベクトル(1,1,1) を回転軸とする (※正規化も実施)
var axis = new THREE.Vector3(1,1,1).normalize();

// 回転角は90°とする
var angle = Math.PI / 2;

// 回転軸axis と角度angle からクォータニオンを計算
quat.setFromAxisAngle(axis,angle);

// メッシュを回転させる
mesh.quaternion.multiply(quat);

以上となります。クォータニオンの理屈は難しいですね。。。 three.js では、オイラー角からクォータニオンを算出したり、上記のように、任意軸と回転角から算出してくれるメソッドを用意してくれているのでとても助かります。

 

参考サイト

今回、大変役に立ったサイトです。ありがとうございました。

ゲームの中に、虚数あり! | 高校数学を100倍楽しく 四元数と三次元空間における回転 | 高校数学の美しい物語 四元数(クォータニオン)でモデルを回転 - ArakinのGLSLを使ったOpenGLプログラム