開発環境 Microsoft Visual C# 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 空のプロジェクト
プロジェクト名 Quaternion

四元数(しげんすう、クォータニオン)の用途には2種類ある。
1.座標を表す。
2.回転軸と角度を表す。

1.の方は値のセットも取得も行う。
2.の方は値をセットし利用はするが、取得はあまり行わない。

3次元の座標の四元数での表現


ある座標(x,y,z)を四元数で表すには、

Quaternion p = new Quaternion(new Vector3(x, y, z), 0);

とする。
ちなみに、4番目の要素wをゼロ以外の値にしても問題ないようだが、ゼロ以外にする意味はないと思う。

回転の四元数での表現


原点を回転の中心として、回転の軸が(x,y,z)で
(右手系の座標定義では、ベクトル(x,y,z)の進む方向に向かって眺めて反時計回りに)
t度回す回転を表す四元数は

Quaternion q = Quaternion.CreateFromAxisAngle(new Vector3(x, y, z), MathHelper.ToRadians(t));
Quaternion r = Quaternion.Quaternion.Conjugate(Q);

と作る。(ちなみにrはqの共役四元数という)
回転を実行するには、

Quaternion rpq = r * p * q;

と計算する。rpqの(x,y,z)が回転した後の座標である。
原点以外を通る回転軸の場合、回転軸が原点を通るように座標を平行移動して回転し、平行移動しなおす。
(もっといい方法があるかもしれない)

参考

Program.cs
// Quaternion4.1
using System;
using Microsoft.Xna.Framework; // .NET参照
 
class Program
{
    static void Main()
    {
        Vector3 v = new Vector3(0, 1, 0); // 回転軸の方向を表すベクトル
        for (int t = 0; t <= 360; t += 45)
        {
            Quaternion q = Quaternion.CreateFromAxisAngle(v, MathHelper.ToRadians(t));
            Console.Write(string.Format("t={0} / ", t));
            Print(q);
        }
        Console.ReadLine();
    }
 
    static void Print(Quaternion q)
    {
        Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2} w={3:f2} len={4:f2}",
            q.X, q.Y, q.Z, q.W, q.Length()));
    }
}
 

出力
t=0 / x=0.00 y=0.00 z=0.00 w=1.00 len=1.00
t=45 / x=0.00 y=0.38 z=0.00 w=0.92 len=1.00
t=90 / x=0.00 y=0.71 z=0.00 w=0.71 len=1.00
t=135 / x=0.00 y=0.92 z=0.00 w=0.38 len=1.00
t=180 / x=0.00 y=1.00 z=0.00 w=0.00 len=1.00
t=225 / x=0.00 y=0.92 z=0.00 w=-0.38 len=1.00
t=270 / x=0.00 y=0.71 z=0.00 w=-0.71 len=1.00
t=315 / x=0.00 y=0.38 z=0.00 w=-0.92 len=1.00
t=360 / x=0.00 y=0.00 z=0.00 w=-1.00 len=1.00

考察
t=0のときqはQuaternion.Identity(=(0,0,0,1))と同じ値になり無回転を表す。
t=180のときqは(0,1,0)の座標と同じ値であるが、使われ方によってその意味は異なる。

Program.cs
// Quaternion4.2 任意の回転軸で点を回転
using System;
using Microsoft.Xna.Framework; // .NET参照
 
class Program
{
    static void Main()
    {
        float a = (float)Math.Sin(MathHelper.ToRadians(45)) * 10;
        Quaternion p = new Quaternion(new Vector3(a, a, 0), 0); // 回転させたい点
        Vector3 v = new Vector3(0, 1, 0); // 回転軸の方向を表すベクトル
        for (int t = 0; t <= 360; t += 45)
        {
            Quaternion q = Quaternion.CreateFromAxisAngle(v, MathHelper.ToRadians(t));
            //Quaternion r = Quaternion.CreateFromAxisAngle(-v, MathHelper.ToRadians(n));
            Quaternion r = Quaternion.Conjugate(q); // 共役。↑と同じ
            Quaternion rpq = r * p * q;
            Console.Write(string.Format("t={0} / ", t));
            Print(rpq);
        }
        Console.ReadLine();
    }
 
    static void Print(Quaternion q)
    {
        Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2} w={3:f2} len={4:f2}",
            q.X, q.Y, q.Z, q.W, q.Length()));
    }
}
 

出力
t=0 / x=7.07 y=7.07 z=0.00 w=0.00 len=10.00
t=45 / x=5.00 y=7.07 z=5.00 w=0.00 len=10.00
t=90 / x=0.00 y=7.07 z=7.07 w=0.00 len=10.00
t=135 / x=-5.00 y=7.07 z=5.00 w=0.00 len=10.00
t=180 / x=-7.07 y=7.07 z=0.00 w=0.00 len=10.00
t=225 / x=-5.00 y=7.07 z=-5.00 w=0.00 len=10.00
t=270 / x=0.00 y=7.07 z=-7.07 w=0.00 len=10.00
t=315 / x=5.00 y=7.07 z=-5.00 w=0.00 len=10.00
t=360 / x=7.07 y=7.07 z=0.00 w=0.00 len=10.00

Program.cs
// Quaternion4.3 任意の回転軸・原点で点を回転
using System;
using Microsoft.Xna.Framework; // .NET参照
 
class Program
{
    static void Main()
    {
        Vector3 v = new Vector3(0, 1, 0); // 回転軸の方向を表すベクトル
        Vector3 o = new Vector3(10, 0, 0); // 回転の原点
        Quaternion p = new Quaternion(new Vector3(20, 0, 0) - o, 0); // 回転させたい点-回転の原点
        for (int t = 0; t <= 360; t += 45)
        {
            Quaternion q = Quaternion.CreateFromAxisAngle(v, MathHelper.ToRadians(t));
            //Quaternion r = Quaternion.CreateFromAxisAngle(-v, MathHelper.ToRadians(n));
            Quaternion r = Quaternion.Conjugate(q); // 共役。↑と同じ
            Quaternion rpq = r * p * q;
            Vector3 pos = QV(rpq) + o; // 回転後の点+回転の原点
            Console.Write(string.Format("t={0} / ", t));
            Print(pos);
        }
        Console.ReadLine();
    }
 
    static void Print(Vector3 v)
    {
        Console.WriteLine(string.Format("x={0:f2} y={1:f2} z={2:f2}", v.X, v.Y, v.Z));
    }
 
    static Vector3 QV(Quaternion q)
    {
        return new Vector3(q.X, q.Y, q.Z);
    }
}
 

出力
t=0 / x=20.00 y=0.00 z=0.00
t=45 / x=17.07 y=0.00 z=7.07
t=90 / x=10.00 y=0.00 z=10.00
t=135 / x=2.93 y=0.00 z=7.07
t=180 / x=0.00 y=0.00 z=0.00
t=225 / x=2.93 y=0.00 z=-7.07
t=270 / x=10.00 y=0.00 z=-10.00
t=315 / x=17.07 y=0.00 z=-7.07
t=360 / x=20.00 y=0.00 z=0.00
最終更新:2012年12月17日 12:33