Edited at

カメラの向いている方向とオブジェクトの角度の差を計算する

More than 1 year has passed since last update.


はじめに

VR のゲームを作っている時、視線の方向とターゲットとなるオブジェクトの方向との角度差をとりたくなることがあります。そういうとき、ついつい eulerAngles にして、軸ごとに計算しちゃうのですが、そうするとマイナスの処理とか考えないといけなくてめんどくさいです。そこで、角度計算はクオータニオンで行い、そこからオイラー角に変換する方法を使用してみました。


クオータニオンの演算

クオータニオンには詳しくないので間違ってるかもしれないのですが、ベクトルの加算減算と同じようなことが、「乗算」と「Inverse したものの乗算」で行えるようです。

Quaternion qa, qb, qc;

// qc は qa の回転を適用してから、qb の回転を適用したもの
// ベクトルでいう c = a + b
qc = qa * qb;

// qa の回転と qb の回転を足した qc から qb の回転を引くと qa になる
// ベクトルで言う a = (a + b) - b = c - b
qa == (qa * qb) * Quaternion.Inverse(qb);
qa == qc * Quaternion.Inverse(qb);


2点間のベクトル => 2回転間のクオータニオン

a から 点 b へのベクトル c は以下の式で求められます。

Vector3 a, b, c;

c = b - a;

同じように、回転 a から 回転 b へのクオータニオン c も、以下の式で求められそうです。

Quaternion a, b, c;

c = b * Quaternion.Inverse(a);

image


最終的なコード

void PrintRequiredDegrees()

{
// カメラの位置からターゲットの方向に向くための回転
var toTargetRot = Quaternion.LookRotation(target.transform.position - Camera.main.transform.position);
// カメラの現在の向きからターゲットの方向に向くために必要な回転
var requiredRot = toTargetRot * Quaternion.Inverse(Camera.main.transform.rotation);

var requiredDegree = requiredRot.eulerAngles;
print(Map360To180(requiredDegree .x) + ", " + Map360To180(requiredDegree .y));
}

// 角度 0-360 を 0-180-0 にマッピングする
float Map360To180(float degree)
{
if (degree < 180)
{
return degree;
}

return 360 - degree;
}


終わりに

クオータニオンの演算について理解せず書いているので間違っていたら教えてください。