Math World Lab

四元数(クォータニオン)と3D回転

オイラー角のジンバルロックを回避する4次元数の代数と3D回転表現

この単元の発見をシェア
3行要約(Key Takeaways / AIOサマリー)
1
四元数は実部1つと虚部3つ(w, x, y, z)からなる数で、単位四元数は3次元空間の回転を1つの連続的な代数として表現できる
2
オイラー角(3軸の回転角を順番に適用する方式)は特定の角度の組み合わせで自由度が1つ失われる「ジンバルロック」を起こすが、四元数はこの特異点を持たない
3
Unity や Unreal Engine などのゲームエンジンは、内部の回転計算・補間(スラープ)に四元数を使い、人間が編集する角度表示だけオイラー角に変換している

なぜこれを学ぶのか? — 現実社会とテクノロジーでの価値

Purpose & Motivation

なぜ生まれたのか?

四元数は実部1つと虚部3つ(w, x, y, z)からなる数で、単位四元数は3次元空間の回転を1つの連続的な代数として表現できる

身につく武器・思考力

オイラー角(3軸の回転角を順番に適用する方式)は特定の角度の組み合わせで自由度が1つ失われる「ジンバルロック」を起こすが、四元数はこの特異点を持たない

実社会・ITでの活躍現場

  • •ゲームエンジンにおける四元数ベースの回転補間(Slerp)
  • •ITシステム・アルゴリズム実装における論理設計
  • •データ分析やシミュレーションにおける数理モデリング

Layer 1 — 直感・シミュレーター

左側のオイラー角パネルでは Roll・Pitch・Yaw の3つのスライダーを順番に動かして矢印の向きを回転させ、Pitch を ±90° 付近に近づけたときに Roll と Yaw が同じ軸周りの回転になって矢印が思うように動かなくなる「ジンバルロック」を体験しよう。右側の四元数パネルでは同じ最終姿勢を単一の回転角+回転軸(単位四元数)で滑らかに表現できることを比較できる。

オイラー角による回転(3軸を順番に適用)

Z(yaw) → Y(pitch) → X(roll) の順に回転行列を合成

四元数による同一姿勢の表現

単一の単位四元数 q で滑らかに姿勢を保持(特異点なし)

現在の単位四元数 q:
q=1.000+0.000i+0.000j+0.000kq = 1.000 + 0.000i + 0.000j + 0.000k

ノルム ∥q∥=1.0000\|q\| = 1.0000(常に1に保たれる単位四元数であることを確認できる)

↑ 2つのパネルは同じ Roll / Pitch / Yaw の値から計算された「同じ最終姿勢」を表示しています。Pitch を ±90° に近づけると、左のオイラー角表示で Roll と Yaw が区別できなくなる「ジンバルロック」が視覚的に確認できます。右の四元数はこの角度の組み合わせに関わらず、常に矛盾なく滑らかに姿勢を表現し続けます。

直感チェック!ミニクイズ

オイラー角による回転と比較して、四元数による3D回転表現の最大の利点は何か?

Layer 2 — 定義・受験・証明

定義

四元数(クォータニオン)は、実数の拡張として1つの実部と3つの虚部を持つ数であり、i2=j2=k2=ijk=−1i^2 = j^2 = k^2 = ijk = -1 を満たす基底 i,j,ki, j, k を用いて次のように表される。

q=w+xi+yj+zk(w,x,y,z∈R)q = w + xi + yj + zk \quad (w, x, y, z \in \mathbb{R})

ノルムが1の単位四元数 ∥q∥=w2+x2+y2+z2=1\|q\| = \sqrt{w^2+x^2+y^2+z^2} = 1 は、回転軸を表す単位ベクトル n^=(nx,ny,nz)\hat{\mathbf{n}} = (n_x, n_y, n_z) と回転角 θ\theta を用いて、

q=cos⁡θ2+(nxi+nyj+nzk)sin⁡θ2q = \cos\frac{\theta}{2} + \left(n_x i + n_y j + n_z k\right)\sin\frac{\theta}{2}

と書くことができ、これが3次元空間における「軸 n^\hat{\mathbf{n}} の周りに角度 θ\theta だけ回転する」操作そのものを表す。任意のベクトル v\mathbf{v}(純虚四元数 v=0+vxi+vyj+vzkv = 0 + v_xi+v_yj+v_zk とみなす)の回転後の姿勢は共役四元数 q−1=q∗=w−xi−yj−zkq^{-1} = q^* = w - xi - yj - zk(単位四元数では q−1=q∗q^{-1}=q^*)を用いて v′=qvq−1v' = q v q^{-1} で求められる。

公式・数理モデル

q=cos⁡θ2+(nxi+nyj+nzk)sin⁡θ2,v′=q v q−1q = \cos\frac{\theta}{2} + \left(n_x i + n_y j + n_z k\right)\sin\frac{\theta}{2}, \qquad v' = q\,v\,q^{-1}

証明・導出

ジンバルロックが起こる理由: オイラー角による回転は、3つの単軸回転行列の積 R=Rz(yaw)Ry(pitch)Rx(roll)R = R_z(\text{yaw}) R_y(\text{pitch}) R_x(\text{roll}) として構成される(順序は規約によるが本質は同じ)。

ここで中間の回転(例えば pitch)がちょうど ±90∘\pm 90^\circ になると、RzR_z が作用する軸と RxR_x が作用する軸が、変換後の座標系において一致してしまう。このとき RzR_z による回転と RxR_x による回転は「同じ軸周りの回転」に縮退し、3つあったはずの独立な回転自由度が実質2つに減少する(3次元の回転群 SO(3)SO(3) を局所座標として3つのオイラー角で覆おうとしても、この写像は球面上の極(特異点)を避けられないことが位相幾何学的に示される)。

一方、単位四元数の集合は3次元球面 S3⊂R4S^3 \subset \mathbb{R}^4 上の点として滑らかにパラメータ化され、SO(3)SO(3) への二重被覆写像 q↦Rqq \mapsto R_q(qq と −q-q が同じ回転に対応)は至る所で滑らかであり、特異点を持たない。したがって四元数による回転補間(球面線形補間 Slerp)は角度の組み合わせに関わらず常に連続かつ一意に定義される。

押さえておきたいポイント

  • 四元数の積は非可換(qp≠pqqp \neq pq)であり、これは3次元回転の合成順序が結果に影響することと対応している
  • 2つの単位四元数 q1,q2q_1, q_2 の球面線形補間(Slerp)は、2つの姿勢の間を一定角速度で滑らかに補間でき、キャラクターアニメーションで多用される
  • 四元数は qq と −q-q が同一の回転を表す「二重被覆」の性質を持つため、補間時には内積の符号を確認して最短経路を選ぶ必要がある
  • オイラー角は人間が直感的に数値を読み書きするのに適し、四元数は内部計算・補間・累積誤差の少なさに適するため、実務では「編集はオイラー角、内部表現は四元数」という使い分けがされる
参照基準・学習指導要領との対応

本トピックの内容・数理モデルは、文部科学省学習指導要領(算数・数学・情報)および国際標準カリキュラムに準拠し、エンジニアリング現場の実装事例と照らし合わせてMath World Lab編集部により検証・作成されています。

Layer 3 — 工学応用・現場実装

ゲームエンジンにおける四元数ベースの回転補間(Slerp)

Unity・Unreal Engine などの3Dゲームエンジンは、キャラクターやカメラの回転をオイラー角ではなく四元数で内部保持する。これによりジンバルロックを避けつつ、Quaternion.Slerp(球面線形補間)でアニメーション間の滑らかな回転補間を実現している。以下はその中核アルゴリズムのTypeScript実装。

1type Quat = { w: number; x: number; y: number; z: number };
2
3// 回転軸と角度から単位四元数を生成
4function fromAxisAngle(axis: [number, number, number], angleRad: number): Quat {
5 const half = angleRad / 2;
6 const s = Math.sin(half);
7 const len = Math.hypot(...axis) || 1;
8 return {
9 w: Math.cos(half),
10 x: (axis[0] / len) * s,
11 y: (axis[1] / len) * s,
12 z: (axis[2] / len) * s,
13 };
14}
15
16// 四元数の積(回転の合成。qb を先に適用してから qa を適用)
17function multiply(qa: Quat, qb: Quat): Quat {
18 return {
19 w: qa.w * qb.w - qa.x * qb.x - qa.y * qb.y - qa.z * qb.z,
20 x: qa.w * qb.x + qa.x * qb.w + qa.y * qb.z - qa.z * qb.y,
21 y: qa.w * qb.y - qa.x * qb.z + qa.y * qb.w + qa.z * qb.x,
22 z: qa.w * qb.z + qa.x * qb.y - qa.y * qb.x + qa.z * qb.w,
23 };
24}
25
26function dot(a: Quat, b: Quat): number {
27 return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
28}
29
30// 球面線形補間 (Slerp): t=0でqa, t=1でqbの姿勢を返す
31function slerp(qa: Quat, qb: Quat, t: number): Quat {
32 let { w, x, y, z } = qb;
33 let cosOmega = dot(qa, qb);
34
35 // 最短経路を取るため、内積が負なら qb を反転(二重被覆 q と -q は同じ回転)
36 if (cosOmega < 0) {
37 cosOmega = -cosOmega;
38 w = -w; x = -x; y = -y; z = -z;
39 }
40
41 let k0: number, k1: number;
42 if (cosOmega > 0.9999) {
43 // ほぼ同じ姿勢は線形補間で近似(ゼロ除算回避)
44 k0 = 1 - t;
45 k1 = t;
46 } else {
47 const omega = Math.acos(cosOmega);
48 const sinOmega = Math.sin(omega);
49 k0 = Math.sin((1 - t) * omega) / sinOmega;
50 k1 = Math.sin(t * omega) / sinOmega;
51 }
52
53 return {
54 w: qa.w * k0 + w * k1,
55 x: qa.x * k0 + x * k1,
56 y: qa.y * k0 + y * k1,
57 z: qa.z * k0 + z * k1,
58 };
59}
60
61// 例: Y軸90度回転からX軸90度回転へアニメーション補間
62const start = fromAxisAngle([0, 1, 0], Math.PI / 2);
63const end = fromAxisAngle([1, 0, 0], Math.PI / 2);
64const mid = slerp(start, end, 0.5); // アニメーション中間フレームの姿勢
65console.log(mid);

次に学ぶならコレ!おすすめトピック

この単元と深い繋がりを持つ、あわせて学ぶと理解が深まるおすすめ単元

数理モデル・概念が近い関連トピック

関連度高大学数学

固有値・固有ベクトル

行列で変換しても「向きが変わらない」特別な方向

関連度高大学数学

線形変換と基底

行列が空間をどう歪めるか──基底ベクトルの行き先がすべてを決める

関連度高高校数学

行列の基本とアフィン変換

2×2行列で平面の空間を伸縮・回転・せん断させる幾何学

同じレベルで次に挑戦したいトピック

同レベル推薦大学数学

フーリエ変換と周波数分解

どんなに複雑な波も、単純なサイン波の重ね合わせに分解できる

同レベル推薦大学数学

ベイズの定理(条件付き確率と事前・事後確率)

新たな情報や証拠(エビデンス)を得て「確信度」を更新する確率論

同レベル推薦大学数学

正規分布と中心極限定理

あらゆるランダムなばらつきが最終的に収束する「釣鐘型の山」

工学・実社会での応用先でつながるトピック

工学・実践連携小学校・算数

円の面積と円周率

半径を変えると、円周と面積はどう変わる?

工学・実践連携小学校・算数

三角形・多角形の面積

頂点を動かして、面積の公式が成り立つ理由を確かめよう

工学・実践連携小学校・算数

単位変換(長さ・面積・体積)

長さが2倍になると、面積・体積は何倍になる?

あなたの数学力をさらに伸ばす

数学の弱点診断や算数パズルに挑戦してみませんか?

簡単な質問に答えてあなたにぴったりの学習ロードマップを発見したり、直感を試すパズルで数の面白さを体験できます。