はじめに
3Dグラフィックスやゲーム開発において、物体の回転は基本的かつ重要な処理です。
前回の記事では2次元での座標変換について整理しています。
今回は3次元空間での回転、特にクォータニオンについて紹介します。
この記事で学べること
- 3D回転の基本概念
- クォータニオンの理論と実装
- オイラー角との比較とジンバルロックの問題
- 実践的なコード例と最適化手法
3D回転の基礎
従来の回転表現:オイラー角
オイラー角は3つの角度(X軸、Y軸、Z軸周りの回転)で3次元の回転を表現する方法です。
直感的で理解しやすい反面、以下のような問題があります。
- ジンバルロック:特定の角度で自由度が失われる
- 回転の順序依存性:XYZの順序が結果に影響する
- 補間が難しい
クォータニオンとは
クォータニオンは4つの要素(w, x, y, z)を持つ数学的な概念で、3次元空間での回転を表現します。
スカラー部が回転の角度を表し、ベクトル部が回転軸を含む
public struct Quaternion
{
public double W { get; set; } // スカラー部
public double X { get; set; } // ベクトル部(i成分)
public double Y { get; set; } // ベクトル部(j成分)
public double Z { get; set; } // ベクトル部(k成分)
}
クォータニオンの実装
基本的な操作
まず、回転軸と角度からクォータニオンを生成する方法を実装します。
public static Quaternion FromAxisAngle(Vector3 axis, double angleInDegrees)
{
// 単位ベクトル化
double length = Math.Sqrt(axis.X * axis.X + axis.Y * axis.Y + axis.Z * axis.Z);
axis = new Vector3(
axis.X / length,
axis.Y / length,
axis.Z / length
);
double angleInRadians = angleInDegrees * Math.PI / 180.0;
double sinHalfAngle = Math.Sin(angleInRadians / 2.0);
double cosHalfAngle = Math.Cos(angleInRadians / 2.0);
return new Quaternion
{
W = cosHalfAngle,
X = axis.X * sinHalfAngle,
Y = axis.Y * sinHalfAngle,
Z = axis.Z * sinHalfAngle
};
}
クォータニオンの合成
2つの回転を合成する場合、クォータニオンの乗算を使用します。
public static Quaternion Multiply(Quaternion q1, Quaternion q2)
{
return new Quaternion
{
W = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z,
X = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y,
Y = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X,
Z = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W
};
}
点の回転
クォータニオンを使って点を回転させる実装
public Vector3 RotatePoint(Vector3 point)
{
// 共役クォータニオンの計算
Quaternion conjugate = new Quaternion
{
W = this.W,
X = -this.X,
Y = -this.Y,
Z = -this.Z
};
// 点をクォータニオンに変換
Quaternion p = new Quaternion
{
W = 0,
X = point.X,
Y = point.Y,
Z = point.Z
};
// 回転の適用: q * p * q'
Quaternion rotated = Multiply(Multiply(this, p), conjugate);
return new Vector3(rotated.X, rotated.Y, rotated.Z);
}
パフォーマンスの最適化
SIMDを活用した実装
.NET Core 3.0以降では、System.Numerics.Vector4を使用してSIMD演算を活用できます。
public static Vector3 RotatePointSimd(Vector4 quaternion, Vector3 point)
{
Vector4 p = new Vector4(point, 0);
Vector4 q = quaternion;
Vector4 qConjugate = new Vector4(-q.X, -q.Y, -q.Z, q.W);
Vector4 result = Vector4.Multiply(
Vector4.Multiply(q, p),
qConjugate
);
return new Vector3(result.X, result.Y, result.Z);
}
キャッシュ効率の改善
大量の点を回転させる場合、以下のように実装することでキャッシュ効率を改善できます。
public void RotatePoints(Vector3[] points, Vector3[] results)
{
const int batchSize = 1024; // キャッシュラインに合わせたサイズ
for (int i = 0; i < points.Length; i += batchSize)
{
int count = Math.Min(batchSize, points.Length - i);
for (int j = 0; j < count; j++)
{
results[i + j] = RotatePoint(points[i + j]);
}
}
}
実践的な使用例
カメラの制御
カメラの視点制御にクォータニオンを使用する例
public class Camera
{
public Vector3 Position { get; set; }
public Quaternion Rotation { get; set; }
public void LookAt(Vector3 target)
{
Vector3 direction = Vector3.Normalize(target - Position);
Vector3 up = new Vector3(0, 1, 0);
// 前方ベクトルとアップベクトルから回転を計算
Vector3 right = Vector3.Normalize(Vector3.Cross(up, direction));
up = Vector3.Cross(direction, right);
// 回転行列からクォータニオンを生成
// (実装は省略)
}
}
まとめ
クォータニオンを使用することで、以下のような利点があります。
- ジンバルロックの回避
- 滑らかな補間が可能
- 数値的な安定性
- 効率的な計算
ただし、以下の点に注意が必要です。
- 直感的な理解が難しい
- デバッグが複雑になりやすい
- 正規化の重要性
補足:最新の実装テクニック(2024年版)
最新の.NETでの実装
.NET 6以降では、より効率的な数値計算が可能になっています。
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
public static Vector3 RotatePointModern(Vector4 quaternion, Vector3 point)
{
if (Avx.IsSupported)
{
// AVXを使用した高速な回転計算
var vec = Vector256.Create(point.X, point.Y, point.Z, 0f);
// ... AVXを使用した実装
}
// 従来の実装にフォールバック
return RotatePoint(quaternion, point);
}
Unityでの最新の実装(2024年)
Unity 2022.3以降では、Burst CompilerとJob Systemを活用した並列処理が可能です。
using Unity.Mathematics;
using Unity.Jobs;
using Unity.Burst;
[BurstCompile]
public struct RotatePointsJob : IJobParallelFor
{
public NativeArray<float3> Points;
public quaternion Rotation;
public void Execute(int index)
{
Points[index] = math.rotate(Rotation, Points[index]);
}
}
パフォーマンスに関する最新の知見
SIMD演算の活用
- AVX-512命令セットの利用(対応CPUの場合)
- ハードウェアアクセラレーションの活用
メモリ最適化
メモリアライメントとSpanの活用による効率改善
[StructLayout(LayoutKind.Sequential, Pack = 16)]
public struct OptimizedQuaternion
{
public Vector4 Value; // 16バイトアライメント
}
クラウドでの3D処理
最近のクラウドサービスでは、GPUアクセラレーションを活用した3D処理が可能になっています。
- Azure Kinect DKのボーントラッキング
- AWSのAmazon Sumerian(3D/AR/VR)
- Google Cloud Platform の3Dレンダリングサービス
これらのサービスと連携する際も、クォータニオンは重要な役割を果たしています。