読者です 読者をやめる 読者になる 読者になる

Unityな日々(Unity Geek)

Unityで可視化アプリを開発するための試行錯誤の覚書

軸周りの回転の方向

回転は一見単純な操作だが、すぐ忘れるので備忘録代わりに書いておく。


プリミティブをの円柱(Cylinder)を新規作成した場合、

transform.right :グローバルX方向&ローカルX方向=半径方向1
transform.up :グローバルY方向&ローカルY方向=円柱の軸方向
transform.forwad: グローバルZ方向&ローカルZ方向=半径方向2

となる。
f:id:yasuda0404:20141017191018p:plain


この円柱を

transform.Rotate(new Vector3(90.0f, 0.0f, 0.0f))

と、X軸周りに90度回転させる。(円柱の軸は水平方向に向く)
このとき、

transform.right :グローバルX方向&ローカル半径方向1
transform.up :グローバルZ方向&ローカル軸方向
transform.forwad: グローバル-Y方向&ローカル半径方向2

となる。
f:id:yasuda0404:20141017191251p:plain

つまり、ある軸まわりの回転は、その軸を手前から向こうに向かう方向から見たとき、反時計回りの回転となる。ねじ回しでいうと、ねじを外す方向。

当然のことだが、ローカル座標は物体にくっついて方向を変える。円柱の場合、軸方向は常にローカルY軸となる。


この円柱を軸方向に動かしたい時、どうするか。

obj.transform.Translate(10*obj.transform.up);

と書いてしまいそうだが、これではだめ。Translate()はデフォルト(=Translateの第二引数が`Space.Self`の状態)ではグローバル座標で方向を指定するからだ。
下の画像は、青い球の中心に生成した円柱を、青い球の半径分、円柱の軸方向に動かそうとしたもの。しかし、軸方向ではなく円柱の半径方向に動いてしまっている。これは、グローバル座標で(0.0, 0.0, 1.0)であるtransform.upを、円柱のローカル座標で動かしているため、矛盾が生じてしまったのだ。つまり、円柱の軸は水平を向いているが、円柱ローカルのZは下を向いているので、下方に移動してしまう。
f:id:yasuda0404:20141017194946p:plain


円柱の軸方向に動かすには、Translateの第二引数に'Space.World'を指定し、

obj.transform.Translate(10*obj.transform.up, Space.World);

とすればよい。これで、グローバルで見ているtransform.upを、正しくグローバル座標で移動できる。
f:id:yasuda0404:20141017194956p:plain



ランダムに与えた緯度・経度の示す地球表面上の地点に、垂直に円柱を立てるには次のようにすればよい。

void Update () {
  if(count < 20) {
    cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
    cylinder.transform.position = Vector3.zero;
    Debug.Log (cylinder.transform.up);	//(0.0, 1.0, 0.0)
    cylinder.transform.localScale = new Vector3(cylinderRadius, cylinderHeight, cylinderRadius);
    lat =  Random.Range(-80.0f,80.0f);	//latitude
    lng = Random.Range(-180.0f,180.0f);	//longitude

    cylinder.transform.Rotate(new Vector3(-90.0f, 0.0f, 0.0f), Space.Self);	//rotate 90 around X to equator
    Debug.Log (cylinder.transform.up);	//(0.0, 0.0, 1.0)
    cylinder.transform.Rotate(new Vector3(0.0f, 0.0f, -lng), Space.Self);	//rotate in longitude direction
    cylinder.transform.Rotate(new Vector3(lat, 0.0f, 0.0f), Space.Self);

    cylinder.transform.Translate((sphereRadius+cylinderHeight)*cylinder.transform.up, Space.World);
  };
  count++;
}

f:id:yasuda0404:20141017201230p:plain