[Unity] 回転、角度関係のやりたいこと逆引きメモ

毎度毎度回転が関係する処理を書こうと思うとそのたびに少し作法が変わる。
調べれば最終的には求めている答えにたどりつけるが時間を浪費する割に知識に落とし込めていないので、いっその事外部化してしまいます。

メモなので随時増やしていきます。


はじめに
transform.rotationに格納されているのはオイラー角(x = 60°とか)ではありません。
インスペクター上はオイラー角で表記されてますが、中身はQuaternion(4元数)という型です。
ここではQuaternionの説明はしません。
Sin、Cos、ラジアンなどはこちらがわかりやすかったです。

角度で取得したい

Vector3 vec = gameObject.transform.localEulerAngles;

角度をQuaternionに変換したい

Quaternion qua = Quaternion.Euler(Vector3);

注. Quaternion.EulerAngleというのもあるがこちらは廃止されている


ベクトルの方向に向ける

Vector3 vec = new Vector3( 1, 2, 0 );
transform.rotation = Quaternion.FromToRotation(Vector3.up, vec);

第一引数の方向を、第二引数の方向へ向けます。

ベクトルを角度に変換したい (2点間の角度)

Vector3 diff = target.position - transforme.position;
Vector3 axis = Vector3.Angle(transform.forward, diff);

角度で取得するパターンです。
まず2点間の差分を求めてそれを元に角度を出します。Angleの第一引数はどの方向を基準とするかです。上の例は3Dの場合で、2Dならtransform.upあたりが入ります。
diffは正規化しなくてもよしなにしてくれるようです。
さらに発展させて右回りか左回りかも判断できるようです
参考 : キャラクターから見て対象への角度を「-180~180度」の範囲で求める

角度をベクトルに変換したい

float rad = angle * Mathf.Deg2Rad ;
Vector3 vec = new Vector3( Mathf.Cos( rad ), Mathf.Sin( rad ), 0 ) ;

Deg2Radは ( PI * 2 ) / 360 と同じ意味で定数。 Sin, Cosを使ってベクトルを割り出したい時はラジアンで指定します。
「Deg2Rad」の2はtoの意味のスラング? F2P(Free to Play)的な。

ラジアンを角度に変換したい

float deg = rad * Mathf.Rad2Deg ;

Rad2Degは 360 / ( PI / 2 ) と同じでこちらも定数。

オブジェクトから見た向きをVector3取得したい

Vector3 dir1 = transform.forward;
Vector3 dir2 = transform.up;

forwardはz軸のプラス方向、upはy軸のプラス方向。他にもleftやrightも。
もしくは

Vector3 dir3 = transform.transformVector(Vector3.up);

と書いても dir2 と同じ結果が返る。より細かい向きを取得したい場合はdir3のパターンでなければ取得できないが、あまり凝ったことをしないのであれば上のパターンで事足りる
さらに

Vector3 dir4 = transform.rotation * Vector3.up;

これもdir2 = dir3 = dir4 となる。
QuaternionにVector3をかけると、そのVector3から見た方向が求まる。
注.前後を逆にして Vector3 * Quaternion の順番で書くとエラーになります。

Quaternion同士でたす

Quaternion rot = transform1.rotation * transform2.rotation ;

足し算だけど 「 * 」を使います

目標の角度まで補完しながら回転したい

transform.rotation = Quaternion.Slerp(transform.rotation, target.rotation, 0.1f);

引数は(現在の値、目標の値、補完率)です。
補完率は0から1で指定。
Updateで呼び出す場合、低い値にするとゆっくり、1にすると一瞬でその角度になる。

指定の軸に対して角度を指定したい

transform.rotation = Quaternion.AngleAxis(angle, Vector3 );

引数は(角度、基準となる軸)

現在の角度から相対的に変更したい(足したい)

transform.Rotate(Vector3, angle);

AngleAxisと似てます。引数の順番が逆。

現在の角度から任意の角度へのQuaternionを得たい

Quaternion diff = Quaternion.FromToRotation(Vector3, Vector3);

引数は(基準値、目標値)です。
たとえば基準値にオブジェクトAのtransforme.up、目標値にオブジェクトBのtransforme.upを指定するとAからBの回転までのQuaternionが得られます。
もしくは

Quaternion diff = target.rotation * Quaternion.Inverse( transforme.rotation ) ; 

差分Quaternion = 目標値 * (-現在の値) ;

対象の方向に向けたい

Vector3 diff = (target.position - transforme.position ).nomalized  ;
transform.rotation  = Quaternion.FromToRotation(Vector3.up, diff) ;

Quatrnionで取得するパターンです。
もしくは

transform.LookAt(target.transforme) ; 

もしくは

Vector3 diff = (target.position - transforme.position ) ;
 Quaternion.LookRotation( diff ) ;

物理ベースなら

Quaternion diff = target.rotation * Quaternion.Inverse( transforme.rotation ) ; 
Rigidbody.AddTorque( new Vector3( diff.x, diff.y, diff.z ) * 調整値 );

回転方向を制御したい

求めた角度をそのまま適用すると回転方向が意図しない向きだったりします。
その場合はQuaternonであるならwの値を見ることで変換できます。

var rot = target.rotation ; 
if( rot.w < 0 ){
    rot.x = -rot.x ;
    rot.y = -rot.y ;
    rot.z = -rot.z ;
    rot.w = -rot.w ;
}

Vector3から算出する方法は「ベクトルを角度に変換したい」のリンクで外積を使ったやり方が紹介されています。

オブジェクトを基準として任意の方向に弾を撃つ

Vector3 dir = Quaternion.Euler(0,0,1) * transform.forward ;

いくつか方法がありますが「オブジェクトからみた向きを取得したい」のdir4の方法です。Quaternionで撃ち出したい相対角度、Vector3でどの軸を基準とするかです。
出したベクトルはUpdateで加算してあげます。

直進しつつもターゲットに近づこうとする

var diff = ( target - transform.position ).normalized ; 
var endAng = Quaternion.FromToRotation( Vector3.up, diff ) ;
var ang = Quaternion.Slerp( transform.rotation, endAng, rate ) ;
var dir = transform.rotation * Vector3.up ;
var pos = transform.position + dir * speed ;
transform.SetPositionAndRotation( pos, ang ) ;

STGでよくいる敵キャラのような動きです。
ターゲットとの位置関係の差分を出して -> 完全にターゲットの方向を向いた時のQuaternionを取得 -> それを現在の角度と合成、合成率はrateをあたえます。
角度はこれで出ました。
dirには前進する向き、posにはspeedと現在地を足したものがはいります。
最終的な角度をrateで合成しているので近づいた時にターゲットの位置が変わると急旋回するような挙動になります。

物理ベースでの回転

Rigidbody.AddTorque(Vector3);
RigidBody.AddRelativeTorque(Vector3);

指定した軸にそって回転がかかります。Relativeはローカル軸が基準。



コメント